php-cs-fixer 1.8 MB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216921792189219922092219222922392249225922692279228922992309231923292339234923592369237923892399240924192429243924492459246924792489249925092519252925392549255925692579258925992609261926292639264926592669267926892699270927192729273927492759276927792789279928092819282928392849285928692879288928992909291929292939294929592969297929892999300930193029303930493059306930793089309931093119312931393149315931693179318931993209321932293239324932593269327932893299330933193329333933493359336933793389339934093419342934393449345934693479348934993509351935293539354935593569357935893599360936193629363936493659366936793689369937093719372937393749375937693779378937993809381938293839384938593869387938893899390939193929393939493959396939793989399940094019402940394049405940694079408940994109411941294139414941594169417941894199420942194229423942494259426942794289429943094319432943394349435943694379438943994409441944294439444944594469447944894499450945194529453945494559456945794589459946094619462946394649465946694679468946994709471947294739474947594769477947894799480948194829483948494859486948794889489949094919492949394949495949694979498949995009501950295039504950595069507950895099510951195129513951495159516951795189519952095219522952395249525952695279528952995309531953295339534953595369537953895399540954195429543954495459546954795489549955095519552955395549555955695579558955995609561956295639564956595669567956895699570957195729573957495759576957795789579958095819582958395849585958695879588958995909591959295939594959595969597959895999600960196029603960496059606960796089609961096119612961396149615961696179618961996209621962296239624962596269627962896299630963196329633963496359636963796389639964096419642964396449645964696479648964996509651965296539654965596569657965896599660966196629663966496659666966796689669967096719672967396749675967696779678967996809681968296839684968596869687968896899690969196929693969496959696969796989699970097019702970397049705970697079708970997109711971297139714971597169717971897199720972197229723972497259726972797289729973097319732973397349735973697379738973997409741974297439744974597469747974897499750975197529753975497559756975797589759976097619762976397649765976697679768976997709771977297739774977597769777977897799780978197829783978497859786978797889789979097919792979397949795979697979798979998009801980298039804980598069807980898099810981198129813981498159816981798189819982098219822982398249825982698279828982998309831983298339834983598369837983898399840984198429843984498459846984798489849985098519852985398549855985698579858985998609861986298639864986598669867986898699870987198729873987498759876987798789879988098819882988398849885988698879888988998909891989298939894989598969897989898999900990199029903990499059906990799089909991099119912991399149915991699179918991999209921992299239924992599269927992899299930993199329933993499359936993799389939994099419942994399449945994699479948994999509951995299539954995599569957995899599960996199629963996499659966996799689969997099719972997399749975997699779978997999809981998299839984998599869987998899899990999199929993999499959996999799989999100001000110002100031000410005100061000710008100091001010011100121001310014100151001610017100181001910020100211002210023100241002510026100271002810029100301003110032100331003410035100361003710038100391004010041100421004310044100451004610047100481004910050100511005210053100541005510056100571005810059100601006110062100631006410065100661006710068100691007010071100721007310074100751007610077100781007910080100811008210083100841008510086100871008810089100901009110092100931009410095100961009710098100991010010101101021010310104101051010610107101081010910110101111011210113101141011510116101171011810119101201012110122101231012410125101261012710128101291013010131101321013310134101351013610137101381013910140101411014210143101441014510146101471014810149101501015110152101531015410155101561015710158101591016010161101621016310164101651016610167101681016910170101711017210173101741017510176101771017810179101801018110182101831018410185101861018710188101891019010191101921019310194101951019610197101981019910200102011020210203102041020510206102071020810209102101021110212102131021410215102161021710218102191022010221102221022310224102251022610227102281022910230102311023210233102341023510236102371023810239102401024110242102431024410245102461024710248102491025010251102521025310254102551025610257102581025910260102611026210263102641026510266102671026810269102701027110272102731027410275102761027710278102791028010281102821028310284102851028610287102881028910290102911029210293102941029510296102971029810299103001030110302103031030410305103061030710308103091031010311103121031310314103151031610317103181031910320103211032210323103241032510326103271032810329103301033110332103331033410335103361033710338103391034010341103421034310344103451034610347103481034910350103511035210353103541035510356103571035810359103601036110362103631036410365103661036710368103691037010371103721037310374103751037610377103781037910380103811038210383103841038510386103871038810389103901039110392103931039410395103961039710398103991040010401104021040310404104051040610407104081040910410104111041210413104141041510416104171041810419104201042110422104231042410425104261042710428104291043010431104321043310434104351043610437104381043910440104411044210443104441044510446104471044810449104501045110452104531045410455104561045710458104591046010461104621046310464104651046610467104681046910470104711047210473104741047510476104771047810479104801048110482104831048410485104861048710488104891049010491104921049310494104951049610497104981049910500105011050210503105041050510506105071050810509105101051110512105131051410515105161051710518105191052010521105221052310524105251052610527105281052910530105311053210533105341053510536105371053810539105401054110542105431054410545105461054710548105491055010551105521055310554105551055610557105581055910560105611056210563105641056510566105671056810569105701057110572105731057410575105761057710578105791058010581105821058310584105851058610587105881058910590105911059210593105941059510596105971059810599106001060110602106031060410605106061060710608106091061010611106121061310614106151061610617106181061910620106211062210623106241062510626106271062810629106301063110632106331063410635106361063710638106391064010641106421064310644106451064610647106481064910650106511065210653106541065510656106571065810659106601066110662106631066410665106661066710668106691067010671106721067310674106751067610677106781067910680106811068210683106841068510686106871068810689106901069110692106931069410695106961069710698106991070010701107021070310704107051070610707107081070910710107111071210713107141071510716107171071810719107201072110722107231072410725107261072710728107291073010731107321073310734107351073610737107381073910740107411074210743107441074510746107471074810749107501075110752107531075410755107561075710758107591076010761107621076310764107651076610767107681076910770107711077210773107741077510776107771077810779107801078110782107831078410785107861078710788107891079010791107921079310794107951079610797107981079910800108011080210803108041080510806108071080810809108101081110812108131081410815108161081710818108191082010821108221082310824108251082610827108281082910830108311083210833108341083510836108371083810839108401084110842108431084410845108461084710848108491085010851108521085310854108551085610857108581085910860108611086210863108641086510866108671086810869108701087110872108731087410875108761087710878108791088010881108821088310884108851088610887108881088910890108911089210893108941089510896108971089810899109001090110902109031090410905109061090710908109091091010911109121091310914109151091610917109181091910920109211092210923109241092510926109271092810929109301093110932109331093410935109361093710938109391094010941109421094310944109451094610947109481094910950109511095210953109541095510956109571095810959109601096110962109631096410965109661096710968109691097010971109721097310974109751097610977109781097910980109811098210983109841098510986109871098810989109901099110992109931099410995109961099710998109991100011001110021100311004110051100611007110081100911010110111101211013110141101511016110171101811019110201102111022110231102411025110261102711028110291103011031110321103311034110351103611037110381103911040110411104211043110441104511046110471104811049110501105111052110531105411055110561105711058110591106011061110621106311064110651106611067110681106911070110711107211073110741107511076110771107811079110801108111082110831108411085110861108711088110891109011091110921109311094110951109611097110981109911100111011110211103111041110511106111071110811109111101111111112111131111411115111161111711118111191112011121111221112311124111251112611127111281112911130111311113211133111341113511136111371113811139111401114111142111431114411145111461114711148111491115011151111521115311154111551115611157111581115911160111611116211163111641116511166111671116811169111701117111172111731117411175111761117711178111791118011181111821118311184111851118611187111881118911190111911119211193111941119511196111971119811199112001120111202112031120411205112061120711208112091121011211112121121311214112151121611217112181121911220112211122211223112241122511226112271122811229112301123111232112331123411235112361123711238112391124011241112421124311244112451124611247112481124911250112511125211253112541125511256112571125811259112601126111262112631126411265112661126711268112691127011271112721127311274112751127611277112781127911280112811128211283112841128511286112871128811289112901129111292112931129411295112961129711298112991130011301113021130311304113051130611307113081130911310113111131211313113141131511316113171131811319113201132111322113231132411325113261132711328113291133011331113321133311334113351133611337113381133911340113411134211343113441134511346113471134811349113501135111352113531135411355113561135711358113591136011361113621136311364113651136611367113681136911370113711137211373113741137511376113771137811379113801138111382113831138411385113861138711388113891139011391113921139311394113951139611397113981139911400114011140211403114041140511406114071140811409114101141111412114131141411415114161141711418114191142011421114221142311424114251142611427114281142911430114311143211433114341143511436114371143811439114401144111442114431144411445114461144711448114491145011451114521145311454114551145611457114581145911460114611146211463114641146511466114671146811469114701147111472114731147411475114761147711478114791148011481114821148311484114851148611487114881148911490114911149211493114941149511496114971149811499115001150111502115031150411505115061150711508115091151011511115121151311514115151151611517115181151911520115211152211523115241152511526115271152811529115301153111532115331153411535115361153711538115391154011541115421154311544115451154611547115481154911550115511155211553115541155511556115571155811559115601156111562115631156411565115661156711568115691157011571115721157311574115751157611577115781157911580115811158211583115841158511586115871158811589115901159111592115931159411595115961159711598115991160011601116021160311604116051160611607116081160911610116111161211613116141161511616116171161811619116201162111622116231162411625116261162711628116291163011631116321163311634116351163611637116381163911640116411164211643116441164511646116471164811649116501165111652116531165411655116561165711658116591166011661116621166311664116651166611667116681166911670116711167211673116741167511676116771167811679116801168111682116831168411685116861168711688116891169011691116921169311694116951169611697116981169911700117011170211703117041170511706117071170811709117101171111712117131171411715117161171711718117191172011721117221172311724117251172611727117281172911730117311173211733117341173511736117371173811739117401174111742117431174411745117461174711748117491175011751117521175311754117551175611757117581175911760117611176211763117641176511766117671176811769117701177111772117731177411775117761177711778117791178011781117821178311784117851178611787117881178911790117911179211793117941179511796117971179811799118001180111802118031180411805118061180711808118091181011811118121181311814118151181611817118181181911820118211182211823118241182511826118271182811829118301183111832118331183411835118361183711838118391184011841118421184311844118451184611847118481184911850118511185211853118541185511856118571185811859118601186111862118631186411865118661186711868118691187011871118721187311874118751187611877118781187911880118811188211883118841188511886118871188811889118901189111892118931189411895118961189711898118991190011901119021190311904119051190611907119081190911910119111191211913119141191511916119171191811919119201192111922119231192411925119261192711928119291193011931119321193311934119351193611937119381193911940119411194211943119441194511946119471194811949119501195111952119531195411955119561195711958119591196011961119621196311964119651196611967119681196911970119711197211973119741197511976119771197811979119801198111982119831198411985119861198711988119891199011991119921199311994119951199611997119981199912000120011200212003120041200512006120071200812009120101201112012120131201412015120161201712018120191202012021120221202312024120251202612027120281202912030120311203212033120341203512036120371203812039120401204112042120431204412045120461204712048120491205012051120521205312054120551205612057120581205912060120611206212063120641206512066120671206812069120701207112072120731207412075120761207712078120791208012081120821208312084120851208612087120881208912090120911209212093120941209512096120971209812099121001210112102121031210412105121061210712108121091211012111121121211312114121151211612117121181211912120121211212212123121241212512126121271212812129121301213112132121331213412135121361213712138121391214012141121421214312144121451214612147121481214912150121511215212153121541215512156121571215812159121601216112162121631216412165121661216712168121691217012171121721217312174121751217612177121781217912180121811218212183121841218512186121871218812189121901219112192121931219412195121961219712198121991220012201122021220312204122051220612207122081220912210122111221212213122141221512216122171221812219122201222112222122231222412225122261222712228122291223012231122321223312234122351223612237122381223912240122411224212243122441224512246122471224812249122501225112252122531225412255122561225712258122591226012261122621226312264122651226612267122681226912270122711227212273122741227512276122771227812279122801228112282122831228412285122861228712288122891229012291122921229312294122951229612297122981229912300123011230212303123041230512306123071230812309123101231112312123131231412315123161231712318123191232012321123221232312324123251232612327123281232912330123311233212333123341233512336123371233812339123401234112342123431234412345123461234712348123491235012351123521235312354123551235612357123581235912360123611236212363123641236512366123671236812369123701237112372123731237412375123761237712378123791238012381123821238312384123851238612387123881238912390123911239212393123941239512396123971239812399124001240112402124031240412405124061240712408124091241012411124121241312414124151241612417124181241912420124211242212423124241242512426124271242812429124301243112432124331243412435124361243712438124391244012441124421244312444124451244612447124481244912450124511245212453124541245512456124571245812459124601246112462124631246412465124661246712468124691247012471124721247312474124751247612477124781247912480124811248212483124841248512486124871248812489124901249112492124931249412495124961249712498124991250012501125021250312504125051250612507125081250912510125111251212513125141251512516125171251812519125201252112522125231252412525125261252712528125291253012531125321253312534125351253612537125381253912540125411254212543125441254512546125471254812549125501255112552125531255412555125561255712558125591256012561125621256312564125651256612567125681256912570125711257212573125741257512576125771257812579125801258112582125831258412585125861258712588125891259012591125921259312594125951259612597125981259912600126011260212603126041260512606126071260812609126101261112612126131261412615126161261712618126191262012621126221262312624126251262612627126281262912630126311263212633126341263512636126371263812639126401264112642126431264412645126461264712648126491265012651126521265312654126551265612657126581265912660126611266212663126641266512666126671266812669126701267112672126731267412675126761267712678126791268012681126821268312684126851268612687126881268912690126911269212693126941269512696126971269812699127001270112702127031270412705127061270712708127091271012711127121271312714127151271612717127181271912720127211272212723127241272512726127271272812729127301273112732127331273412735127361273712738127391274012741127421274312744127451274612747127481274912750127511275212753127541275512756127571275812759127601276112762127631276412765127661276712768127691277012771127721277312774127751277612777127781277912780127811278212783127841278512786127871278812789127901279112792127931279412795127961279712798127991280012801128021280312804128051280612807128081280912810128111281212813128141281512816128171281812819128201282112822128231282412825128261282712828128291283012831128321283312834128351283612837128381283912840128411284212843128441284512846128471284812849128501285112852128531285412855128561285712858128591286012861128621286312864128651286612867128681286912870128711287212873128741287512876128771287812879128801288112882128831288412885128861288712888128891289012891128921289312894128951289612897128981289912900129011290212903129041290512906129071290812909129101291112912129131291412915129161291712918129191292012921129221292312924129251292612927129281292912930129311293212933129341293512936129371293812939129401294112942129431294412945129461294712948129491295012951129521295312954129551295612957129581295912960129611296212963129641296512966129671296812969129701297112972129731297412975129761297712978129791298012981129821298312984129851298612987129881298912990129911299212993129941299512996129971299812999130001300113002130031300413005130061300713008130091301013011130121301313014130151301613017130181301913020130211302213023130241302513026130271302813029130301303113032130331303413035130361303713038130391304013041130421304313044130451304613047130481304913050130511305213053130541305513056130571305813059130601306113062130631306413065130661306713068130691307013071130721307313074130751307613077130781307913080130811308213083130841308513086130871308813089130901309113092130931309413095130961309713098130991310013101131021310313104131051310613107131081310913110131111311213113131141311513116131171311813119131201312113122131231312413125131261312713128131291313013131131321313313134131351313613137131381313913140131411314213143131441314513146131471314813149131501315113152131531315413155131561315713158131591316013161131621316313164131651316613167131681316913170131711317213173131741317513176131771317813179131801318113182131831318413185131861318713188131891319013191131921319313194131951319613197131981319913200132011320213203132041320513206132071320813209132101321113212132131321413215132161321713218132191322013221132221322313224132251322613227132281322913230132311323213233132341323513236132371323813239132401324113242132431324413245132461324713248132491325013251132521325313254132551325613257132581325913260132611326213263132641326513266132671326813269132701327113272132731327413275132761327713278132791328013281132821328313284132851328613287132881328913290132911329213293132941329513296132971329813299133001330113302133031330413305133061330713308133091331013311133121331313314133151331613317133181331913320133211332213323133241332513326133271332813329133301333113332133331333413335133361333713338133391334013341133421334313344133451334613347133481334913350133511335213353133541335513356133571335813359133601336113362133631336413365133661336713368133691337013371133721337313374133751337613377133781337913380133811338213383133841338513386133871338813389133901339113392133931339413395133961339713398133991340013401134021340313404134051340613407134081340913410134111341213413134141341513416134171341813419134201342113422134231342413425134261342713428134291343013431134321343313434134351343613437134381343913440134411344213443134441344513446134471344813449134501345113452134531345413455134561345713458134591346013461134621346313464134651346613467134681346913470134711347213473134741347513476134771347813479134801348113482134831348413485134861348713488134891349013491134921349313494134951349613497134981349913500135011350213503135041350513506135071350813509135101351113512135131351413515135161351713518135191352013521135221352313524135251352613527135281352913530135311353213533135341353513536135371353813539135401354113542135431354413545135461354713548135491355013551135521355313554135551355613557135581355913560135611356213563135641356513566135671356813569135701357113572135731357413575135761357713578135791358013581135821358313584135851358613587135881358913590135911359213593135941359513596135971359813599136001360113602136031360413605136061360713608136091361013611136121361313614136151361613617136181361913620136211362213623136241362513626136271362813629136301363113632136331363413635136361363713638136391364013641136421364313644136451364613647136481364913650136511365213653136541365513656136571365813659136601366113662136631366413665136661366713668136691367013671136721367313674136751367613677136781367913680136811368213683136841368513686136871368813689136901369113692136931369413695136961369713698136991370013701137021370313704137051370613707137081370913710137111371213713137141371513716137171371813719137201372113722137231372413725137261372713728137291373013731137321373313734137351373613737137381373913740137411374213743137441374513746137471374813749137501375113752137531375413755137561375713758137591376013761137621376313764137651376613767137681376913770137711377213773137741377513776137771377813779137801378113782137831378413785137861378713788137891379013791137921379313794137951379613797137981379913800138011380213803138041380513806138071380813809138101381113812138131381413815138161381713818138191382013821138221382313824138251382613827138281382913830138311383213833138341383513836138371383813839138401384113842138431384413845138461384713848138491385013851138521385313854138551385613857138581385913860138611386213863138641386513866138671386813869138701387113872138731387413875138761387713878138791388013881138821388313884138851388613887138881388913890138911389213893138941389513896138971389813899139001390113902139031390413905139061390713908139091391013911139121391313914139151391613917139181391913920139211392213923139241392513926139271392813929139301393113932139331393413935139361393713938139391394013941139421394313944139451394613947139481394913950139511395213953139541395513956139571395813959139601396113962139631396413965139661396713968139691397013971139721397313974139751397613977139781397913980139811398213983139841398513986139871398813989139901399113992139931399413995139961399713998139991400014001140021400314004140051400614007140081400914010140111401214013140141401514016140171401814019140201402114022140231402414025140261402714028140291403014031140321403314034140351403614037140381403914040140411404214043140441404514046140471404814049140501405114052140531405414055140561405714058140591406014061140621406314064140651406614067140681406914070140711407214073140741407514076140771407814079140801408114082140831408414085140861408714088140891409014091140921409314094140951409614097140981409914100141011410214103141041410514106141071410814109141101411114112141131411414115141161411714118141191412014121141221412314124141251412614127141281412914130141311413214133141341413514136141371413814139141401414114142141431414414145141461414714148141491415014151141521415314154141551415614157141581415914160141611416214163141641416514166141671416814169141701417114172141731417414175141761417714178141791418014181141821418314184141851418614187141881418914190141911419214193141941419514196141971419814199142001420114202142031420414205142061420714208142091421014211142121421314214142151421614217142181421914220142211422214223142241422514226142271422814229142301423114232142331423414235142361423714238142391424014241142421424314244142451424614247142481424914250142511425214253142541425514256142571425814259142601426114262142631426414265142661426714268142691427014271142721427314274142751427614277142781427914280142811428214283142841428514286142871428814289142901429114292142931429414295142961429714298142991430014301143021430314304143051430614307143081430914310143111431214313143141431514316143171431814319143201432114322143231432414325143261432714328143291433014331143321433314334143351433614337143381433914340143411434214343143441434514346143471434814349143501435114352143531435414355143561435714358143591436014361143621436314364143651436614367143681436914370143711437214373143741437514376143771437814379143801438114382143831438414385143861438714388143891439014391143921439314394143951439614397143981439914400144011440214403144041440514406144071440814409144101441114412144131441414415144161441714418144191442014421144221442314424144251442614427144281442914430144311443214433144341443514436144371443814439144401444114442144431444414445144461444714448144491445014451144521445314454144551445614457144581445914460144611446214463144641446514466144671446814469144701447114472144731447414475144761447714478144791448014481144821448314484144851448614487144881448914490144911449214493144941449514496144971449814499145001450114502145031450414505145061450714508145091451014511145121451314514145151451614517145181451914520145211452214523145241452514526145271452814529145301453114532145331453414535145361453714538145391454014541145421454314544145451454614547145481454914550145511455214553145541455514556145571455814559145601456114562145631456414565145661456714568145691457014571145721457314574145751457614577145781457914580145811458214583145841458514586145871458814589145901459114592145931459414595145961459714598145991460014601146021460314604146051460614607146081460914610146111461214613146141461514616146171461814619146201462114622146231462414625146261462714628146291463014631146321463314634146351463614637146381463914640146411464214643146441464514646146471464814649146501465114652146531465414655146561465714658146591466014661146621466314664146651466614667146681466914670146711467214673146741467514676146771467814679146801468114682146831468414685146861468714688146891469014691146921469314694146951469614697146981469914700147011470214703147041470514706147071470814709147101471114712147131471414715147161471714718147191472014721147221472314724147251472614727147281472914730147311473214733147341473514736147371473814739147401474114742147431474414745147461474714748147491475014751147521475314754147551475614757147581475914760147611476214763147641476514766147671476814769147701477114772147731477414775147761477714778147791478014781147821478314784147851478614787147881478914790147911479214793147941479514796147971479814799148001480114802148031480414805148061480714808148091481014811148121481314814148151481614817148181481914820148211482214823148241482514826148271482814829148301483114832148331483414835148361483714838148391484014841148421484314844148451484614847148481484914850148511485214853148541485514856148571485814859148601486114862148631486414865148661486714868148691487014871148721487314874148751487614877148781487914880148811488214883148841488514886148871488814889148901489114892148931489414895148961489714898148991490014901149021490314904149051490614907149081490914910149111491214913149141491514916149171491814919149201492114922149231492414925149261492714928149291493014931149321493314934149351493614937149381493914940149411494214943149441494514946149471494814949149501495114952149531495414955149561495714958149591496014961149621496314964149651496614967149681496914970149711497214973149741497514976149771497814979149801498114982149831498414985149861498714988149891499014991149921499314994149951499614997149981499915000150011500215003150041500515006150071500815009150101501115012150131501415015150161501715018150191502015021150221502315024150251502615027150281502915030150311503215033150341503515036150371503815039150401504115042150431504415045150461504715048150491505015051150521505315054150551505615057150581505915060150611506215063150641506515066150671506815069150701507115072150731507415075150761507715078150791508015081150821508315084150851508615087150881508915090150911509215093150941509515096150971509815099151001510115102151031510415105151061510715108151091511015111151121511315114151151511615117151181511915120151211512215123151241512515126151271512815129151301513115132151331513415135151361513715138151391514015141151421514315144151451514615147151481514915150151511515215153151541515515156151571515815159151601516115162151631516415165151661516715168151691517015171151721517315174151751517615177151781517915180151811518215183151841518515186151871518815189151901519115192151931519415195151961519715198151991520015201152021520315204152051520615207152081520915210152111521215213152141521515216152171521815219152201522115222152231522415225152261522715228152291523015231152321523315234152351523615237152381523915240152411524215243152441524515246152471524815249152501525115252152531525415255152561525715258152591526015261152621526315264152651526615267152681526915270152711527215273152741527515276152771527815279152801528115282152831528415285152861528715288152891529015291152921529315294152951529615297152981529915300153011530215303153041530515306153071530815309153101531115312153131531415315153161531715318153191532015321153221532315324153251532615327153281532915330153311533215333153341533515336153371533815339153401534115342153431534415345153461534715348153491535015351153521535315354153551535615357153581535915360153611536215363153641536515366153671536815369153701537115372153731537415375153761537715378153791538015381153821538315384153851538615387153881538915390153911539215393153941539515396153971539815399154001540115402154031540415405154061540715408154091541015411154121541315414154151541615417154181541915420154211542215423154241542515426154271542815429154301543115432154331543415435154361543715438154391544015441154421544315444154451544615447154481544915450154511545215453154541545515456154571545815459154601546115462154631546415465154661546715468154691547015471154721547315474154751547615477154781547915480154811548215483154841548515486154871548815489154901549115492154931549415495154961549715498154991550015501155021550315504155051550615507155081550915510155111551215513155141551515516155171551815519155201552115522155231552415525155261552715528155291553015531155321553315534155351553615537155381553915540155411554215543155441554515546155471554815549155501555115552155531555415555155561555715558155591556015561155621556315564155651556615567155681556915570155711557215573155741557515576155771557815579155801558115582155831558415585155861558715588155891559015591155921559315594155951559615597155981559915600156011560215603156041560515606156071560815609156101561115612156131561415615156161561715618156191562015621156221562315624156251562615627156281562915630156311563215633156341563515636156371563815639156401564115642156431564415645156461564715648156491565015651156521565315654156551565615657156581565915660156611566215663156641566515666156671566815669156701567115672156731567415675156761567715678156791568015681156821568315684156851568615687156881568915690156911569215693156941569515696156971569815699157001570115702157031570415705157061570715708157091571015711157121571315714157151571615717157181571915720157211572215723157241572515726157271572815729157301573115732157331573415735157361573715738157391574015741157421574315744157451574615747157481574915750157511575215753157541575515756157571575815759157601576115762157631576415765157661576715768157691577015771157721577315774157751577615777157781577915780157811578215783157841578515786157871578815789157901579115792157931579415795157961579715798157991580015801158021580315804158051580615807158081580915810158111581215813158141581515816158171581815819158201582115822158231582415825158261582715828158291583015831158321583315834158351583615837158381583915840158411584215843158441584515846158471584815849158501585115852158531585415855158561585715858158591586015861158621586315864158651586615867158681586915870158711587215873158741587515876158771587815879158801588115882158831588415885158861588715888158891589015891158921589315894158951589615897158981589915900159011590215903159041590515906159071590815909159101591115912159131591415915159161591715918159191592015921159221592315924159251592615927159281592915930159311593215933159341593515936159371593815939159401594115942159431594415945159461594715948159491595015951159521595315954159551595615957159581595915960159611596215963159641596515966159671596815969159701597115972159731597415975159761597715978159791598015981159821598315984159851598615987159881598915990159911599215993159941599515996159971599815999160001600116002160031600416005160061600716008160091601016011160121601316014160151601616017160181601916020160211602216023160241602516026160271602816029160301603116032160331603416035160361603716038160391604016041160421604316044160451604616047160481604916050160511605216053160541605516056160571605816059160601606116062160631606416065160661606716068160691607016071160721607316074160751607616077160781607916080160811608216083160841608516086160871608816089160901609116092160931609416095160961609716098160991610016101161021610316104161051610616107161081610916110161111611216113161141611516116161171611816119161201612116122161231612416125161261612716128161291613016131161321613316134161351613616137161381613916140161411614216143161441614516146161471614816149161501615116152161531615416155161561615716158161591616016161161621616316164161651616616167161681616916170161711617216173161741617516176161771617816179161801618116182161831618416185161861618716188161891619016191161921619316194161951619616197161981619916200162011620216203162041620516206162071620816209162101621116212162131621416215162161621716218162191622016221162221622316224162251622616227162281622916230162311623216233162341623516236162371623816239162401624116242162431624416245162461624716248162491625016251162521625316254162551625616257162581625916260162611626216263162641626516266162671626816269162701627116272162731627416275162761627716278162791628016281162821628316284162851628616287162881628916290162911629216293162941629516296162971629816299163001630116302163031630416305163061630716308163091631016311163121631316314163151631616317163181631916320163211632216323163241632516326163271632816329163301633116332163331633416335163361633716338163391634016341163421634316344163451634616347163481634916350163511635216353163541635516356163571635816359163601636116362163631636416365163661636716368163691637016371163721637316374163751637616377163781637916380163811638216383163841638516386163871638816389163901639116392163931639416395163961639716398163991640016401164021640316404164051640616407164081640916410164111641216413164141641516416164171641816419164201642116422164231642416425164261642716428164291643016431164321643316434164351643616437164381643916440164411644216443164441644516446164471644816449164501645116452164531645416455164561645716458164591646016461164621646316464164651646616467164681646916470164711647216473164741647516476164771647816479164801648116482164831648416485164861648716488164891649016491164921649316494164951649616497164981649916500165011650216503165041650516506165071650816509165101651116512165131651416515165161651716518165191652016521165221652316524165251652616527165281652916530165311653216533165341653516536165371653816539165401654116542165431654416545165461654716548165491655016551165521655316554165551655616557165581655916560165611656216563165641656516566165671656816569165701657116572165731657416575165761657716578165791658016581165821658316584165851658616587165881658916590165911659216593165941659516596165971659816599166001660116602166031660416605166061660716608166091661016611166121661316614166151661616617166181661916620166211662216623166241662516626166271662816629166301663116632166331663416635166361663716638166391664016641166421664316644166451664616647166481664916650166511665216653166541665516656166571665816659166601666116662166631666416665166661666716668166691667016671166721667316674166751667616677166781667916680166811668216683166841668516686166871668816689166901669116692166931669416695166961669716698166991670016701167021670316704167051670616707167081670916710167111671216713167141671516716167171671816719167201672116722167231672416725167261672716728167291673016731167321673316734167351673616737167381673916740167411674216743167441674516746167471674816749167501675116752167531675416755167561675716758167591676016761167621676316764167651676616767167681676916770167711677216773167741677516776167771677816779167801678116782167831678416785167861678716788167891679016791167921679316794167951679616797167981679916800168011680216803168041680516806168071680816809168101681116812168131681416815168161681716818168191682016821168221682316824168251682616827168281682916830168311683216833168341683516836168371683816839168401684116842168431684416845168461684716848168491685016851168521685316854168551685616857168581685916860168611686216863168641686516866168671686816869168701687116872168731687416875168761687716878168791688016881168821688316884168851688616887168881688916890168911689216893168941689516896168971689816899169001690116902169031690416905169061690716908169091691016911169121691316914169151691616917169181691916920169211692216923169241692516926169271692816929169301693116932169331693416935169361693716938169391694016941169421694316944169451694616947169481694916950169511695216953169541695516956169571695816959169601696116962169631696416965169661696716968169691697016971169721697316974169751697616977169781697916980169811698216983169841698516986169871698816989169901699116992169931699416995169961699716998169991700017001170021700317004170051700617007170081700917010170111701217013170141701517016170171701817019170201702117022170231702417025170261702717028170291703017031170321703317034170351703617037170381703917040170411704217043170441704517046170471704817049170501705117052170531705417055170561705717058170591706017061170621706317064170651706617067170681706917070170711707217073170741707517076170771707817079170801708117082170831708417085170861708717088170891709017091170921709317094170951709617097170981709917100171011710217103171041710517106171071710817109171101711117112171131711417115171161711717118171191712017121171221712317124171251712617127171281712917130171311713217133171341713517136171371713817139171401714117142171431714417145171461714717148171491715017151171521715317154171551715617157171581715917160171611716217163171641716517166171671716817169171701717117172171731717417175171761717717178171791718017181171821718317184171851718617187171881718917190171911719217193171941719517196171971719817199172001720117202172031720417205172061720717208172091721017211172121721317214172151721617217172181721917220172211722217223172241722517226172271722817229172301723117232172331723417235172361723717238172391724017241172421724317244172451724617247172481724917250172511725217253172541725517256172571725817259172601726117262172631726417265172661726717268172691727017271172721727317274172751727617277172781727917280172811728217283172841728517286172871728817289172901729117292172931729417295172961729717298172991730017301173021730317304173051730617307173081730917310173111731217313173141731517316173171731817319173201732117322173231732417325173261732717328173291733017331173321733317334173351733617337173381733917340173411734217343173441734517346173471734817349173501735117352173531735417355173561735717358173591736017361173621736317364173651736617367173681736917370173711737217373173741737517376173771737817379173801738117382173831738417385173861738717388173891739017391173921739317394173951739617397173981739917400174011740217403174041740517406174071740817409174101741117412174131741417415174161741717418174191742017421174221742317424174251742617427174281742917430174311743217433174341743517436174371743817439174401744117442174431744417445174461744717448174491745017451174521745317454174551745617457174581745917460174611746217463174641746517466174671746817469174701747117472174731747417475174761747717478174791748017481174821748317484174851748617487174881748917490174911749217493174941749517496174971749817499175001750117502175031750417505175061750717508175091751017511175121751317514175151751617517175181751917520175211752217523175241752517526175271752817529175301753117532175331753417535175361753717538175391754017541175421754317544175451754617547175481754917550175511755217553175541755517556175571755817559175601756117562175631756417565175661756717568175691757017571175721757317574175751757617577175781757917580175811758217583175841758517586175871758817589175901759117592175931759417595175961759717598175991760017601176021760317604176051760617607176081760917610176111761217613176141761517616176171761817619176201762117622176231762417625176261762717628176291763017631176321763317634176351763617637176381763917640176411764217643176441764517646176471764817649176501765117652176531765417655176561765717658176591766017661176621766317664176651766617667176681766917670176711767217673176741767517676176771767817679176801768117682176831768417685176861768717688176891769017691176921769317694176951769617697176981769917700177011770217703177041770517706177071770817709177101771117712177131771417715177161771717718177191772017721177221772317724177251772617727177281772917730177311773217733177341773517736177371773817739177401774117742177431774417745177461774717748177491775017751177521775317754177551775617757177581775917760177611776217763177641776517766177671776817769177701777117772177731777417775177761777717778177791778017781177821778317784177851778617787177881778917790177911779217793177941779517796177971779817799178001780117802178031780417805178061780717808178091781017811178121781317814178151781617817178181781917820178211782217823178241782517826178271782817829178301783117832178331783417835178361783717838178391784017841178421784317844178451784617847178481784917850178511785217853178541785517856178571785817859178601786117862178631786417865178661786717868178691787017871178721787317874178751787617877178781787917880178811788217883178841788517886178871788817889178901789117892178931789417895178961789717898178991790017901179021790317904179051790617907179081790917910179111791217913179141791517916179171791817919179201792117922179231792417925179261792717928179291793017931179321793317934179351793617937179381793917940179411794217943179441794517946179471794817949179501795117952179531795417955179561795717958179591796017961179621796317964179651796617967179681796917970179711797217973179741797517976179771797817979179801798117982179831798417985179861798717988179891799017991179921799317994179951799617997179981799918000180011800218003180041800518006180071800818009180101801118012180131801418015180161801718018180191802018021180221802318024180251802618027180281802918030180311803218033180341803518036180371803818039180401804118042180431804418045180461804718048180491805018051180521805318054180551805618057180581805918060180611806218063180641806518066180671806818069180701807118072180731807418075180761807718078180791808018081180821808318084180851808618087180881808918090180911809218093180941809518096180971809818099181001810118102181031810418105181061810718108181091811018111181121811318114181151811618117181181811918120181211812218123181241812518126181271812818129181301813118132181331813418135181361813718138181391814018141181421814318144181451814618147181481814918150181511815218153181541815518156181571815818159181601816118162181631816418165181661816718168181691817018171181721817318174181751817618177181781817918180181811818218183181841818518186181871818818189181901819118192181931819418195181961819718198181991820018201182021820318204182051820618207182081820918210182111821218213182141821518216182171821818219182201822118222182231822418225182261822718228182291823018231182321823318234182351823618237182381823918240182411824218243182441824518246182471824818249182501825118252182531825418255182561825718258182591826018261182621826318264182651826618267182681826918270182711827218273182741827518276182771827818279182801828118282182831828418285182861828718288182891829018291182921829318294182951829618297182981829918300183011830218303183041830518306183071830818309183101831118312183131831418315183161831718318183191832018321183221832318324183251832618327183281832918330183311833218333183341833518336183371833818339183401834118342183431834418345183461834718348183491835018351183521835318354183551835618357183581835918360183611836218363183641836518366183671836818369183701837118372183731837418375183761837718378183791838018381183821838318384183851838618387183881838918390183911839218393183941839518396183971839818399184001840118402184031840418405184061840718408184091841018411184121841318414184151841618417184181841918420184211842218423184241842518426184271842818429184301843118432184331843418435184361843718438184391844018441184421844318444184451844618447184481844918450184511845218453184541845518456184571845818459184601846118462184631846418465184661846718468184691847018471184721847318474184751847618477184781847918480184811848218483184841848518486184871848818489184901849118492184931849418495184961849718498184991850018501185021850318504185051850618507185081850918510185111851218513185141851518516185171851818519185201852118522185231852418525185261852718528185291853018531185321853318534185351853618537185381853918540185411854218543185441854518546185471854818549185501855118552185531855418555185561855718558185591856018561185621856318564185651856618567185681856918570185711857218573185741857518576185771857818579185801858118582185831858418585185861858718588185891859018591185921859318594185951859618597185981859918600186011860218603186041860518606186071860818609186101861118612186131861418615186161861718618186191862018621186221862318624186251862618627186281862918630186311863218633186341863518636186371863818639186401864118642186431864418645186461864718648186491865018651186521865318654186551865618657186581865918660186611866218663186641866518666186671866818669186701867118672186731867418675186761867718678186791868018681186821868318684186851868618687186881868918690186911869218693186941869518696186971869818699187001870118702187031870418705187061870718708187091871018711187121871318714187151871618717187181871918720187211872218723187241872518726187271872818729187301873118732187331873418735187361873718738187391874018741187421874318744187451874618747187481874918750187511875218753187541875518756187571875818759187601876118762187631876418765187661876718768187691877018771187721877318774187751877618777187781877918780187811878218783187841878518786187871878818789187901879118792187931879418795187961879718798187991880018801188021880318804188051880618807188081880918810188111881218813188141881518816188171881818819188201882118822188231882418825188261882718828188291883018831188321883318834188351883618837188381883918840188411884218843188441884518846188471884818849188501885118852188531885418855188561885718858188591886018861188621886318864188651886618867188681886918870188711887218873188741887518876188771887818879188801888118882188831888418885188861888718888188891889018891188921889318894188951889618897188981889918900189011890218903189041890518906189071890818909189101891118912189131891418915189161891718918189191892018921189221892318924189251892618927189281892918930189311893218933189341893518936189371893818939189401894118942189431894418945189461894718948189491895018951189521895318954189551895618957189581895918960189611896218963189641896518966189671896818969189701897118972189731897418975189761897718978189791898018981189821898318984189851898618987189881898918990189911899218993189941899518996189971899818999190001900119002190031900419005190061900719008190091901019011190121901319014190151901619017190181901919020190211902219023190241902519026190271902819029190301903119032190331903419035190361903719038190391904019041190421904319044190451904619047190481904919050190511905219053190541905519056190571905819059190601906119062190631906419065190661906719068190691907019071190721907319074190751907619077190781907919080190811908219083190841908519086190871908819089190901909119092190931909419095190961909719098190991910019101191021910319104191051910619107191081910919110191111911219113191141911519116191171911819119191201912119122191231912419125191261912719128191291913019131191321913319134191351913619137191381913919140191411914219143191441914519146191471914819149191501915119152191531915419155191561915719158191591916019161191621916319164191651916619167191681916919170191711917219173191741917519176191771917819179191801918119182191831918419185191861918719188191891919019191191921919319194191951919619197191981919919200192011920219203192041920519206192071920819209192101921119212192131921419215192161921719218192191922019221192221922319224192251922619227192281922919230192311923219233192341923519236192371923819239192401924119242192431924419245192461924719248192491925019251192521925319254192551925619257192581925919260192611926219263192641926519266192671926819269192701927119272192731927419275192761927719278192791928019281192821928319284192851928619287192881928919290192911929219293192941929519296192971929819299193001930119302193031930419305193061930719308193091931019311193121931319314193151931619317193181931919320193211932219323193241932519326193271932819329193301933119332193331933419335193361933719338193391934019341193421934319344193451934619347193481934919350193511935219353193541935519356193571935819359193601936119362193631936419365193661936719368193691937019371193721937319374193751937619377193781937919380193811938219383193841938519386193871938819389193901939119392193931939419395193961939719398193991940019401194021940319404194051940619407194081940919410194111941219413194141941519416194171941819419194201942119422194231942419425194261942719428194291943019431194321943319434194351943619437194381943919440194411944219443194441944519446194471944819449194501945119452194531945419455194561945719458194591946019461194621946319464194651946619467194681946919470194711947219473194741947519476194771947819479194801948119482194831948419485194861948719488194891949019491194921949319494194951949619497194981949919500195011950219503195041950519506195071950819509195101951119512195131951419515195161951719518195191952019521195221952319524195251952619527195281952919530195311953219533195341953519536195371953819539195401954119542195431954419545195461954719548195491955019551195521955319554195551955619557195581955919560195611956219563195641956519566195671956819569195701957119572195731957419575195761957719578195791958019581195821958319584195851958619587195881958919590195911959219593195941959519596195971959819599196001960119602196031960419605196061960719608196091961019611196121961319614196151961619617196181961919620196211962219623196241962519626196271962819629196301963119632196331963419635196361963719638196391964019641196421964319644196451964619647196481964919650196511965219653196541965519656196571965819659196601966119662196631966419665196661966719668196691967019671196721967319674196751967619677196781967919680196811968219683196841968519686196871968819689196901969119692196931969419695196961969719698196991970019701197021970319704197051970619707197081970919710197111971219713197141971519716197171971819719197201972119722197231972419725197261972719728197291973019731197321973319734197351973619737197381973919740197411974219743197441974519746197471974819749197501975119752197531975419755197561975719758197591976019761197621976319764197651976619767197681976919770197711977219773197741977519776197771977819779197801978119782197831978419785197861978719788197891979019791197921979319794197951979619797197981979919800198011980219803198041980519806198071980819809198101981119812198131981419815198161981719818198191982019821198221982319824198251982619827198281982919830198311983219833198341983519836198371983819839198401984119842198431984419845198461984719848198491985019851198521985319854198551985619857198581985919860198611986219863198641986519866198671986819869198701987119872198731987419875198761987719878198791988019881198821988319884198851988619887198881988919890198911989219893198941989519896198971989819899199001990119902199031990419905199061990719908199091991019911199121991319914199151991619917199181991919920199211992219923199241992519926199271992819929199301993119932199331993419935199361993719938199391994019941199421994319944199451994619947199481994919950199511995219953199541995519956199571995819959199601996119962199631996419965199661996719968199691997019971199721997319974199751997619977199781997919980199811998219983199841998519986199871998819989199901999119992199931999419995199961999719998199992000020001200022000320004200052000620007200082000920010200112001220013200142001520016200172001820019200202002120022200232002420025200262002720028200292003020031200322003320034200352003620037200382003920040200412004220043200442004520046200472004820049200502005120052200532005420055200562005720058200592006020061200622006320064200652006620067200682006920070200712007220073200742007520076200772007820079200802008120082200832008420085200862008720088200892009020091200922009320094200952009620097200982009920100201012010220103201042010520106201072010820109201102011120112201132011420115201162011720118201192012020121201222012320124201252012620127201282012920130201312013220133201342013520136201372013820139201402014120142201432014420145201462014720148201492015020151201522015320154201552015620157201582015920160201612016220163201642016520166201672016820169201702017120172201732017420175201762017720178201792018020181201822018320184201852018620187201882018920190201912019220193201942019520196201972019820199202002020120202202032020420205202062020720208202092021020211202122021320214202152021620217202182021920220202212022220223202242022520226202272022820229202302023120232202332023420235202362023720238202392024020241202422024320244202452024620247202482024920250202512025220253202542025520256202572025820259202602026120262202632026420265202662026720268202692027020271202722027320274202752027620277202782027920280202812028220283202842028520286202872028820289202902029120292202932029420295202962029720298202992030020301203022030320304203052030620307203082030920310203112031220313203142031520316203172031820319203202032120322203232032420325203262032720328203292033020331203322033320334203352033620337203382033920340203412034220343203442034520346203472034820349203502035120352203532035420355203562035720358203592036020361203622036320364203652036620367203682036920370203712037220373203742037520376203772037820379203802038120382203832038420385203862038720388203892039020391203922039320394203952039620397203982039920400204012040220403204042040520406204072040820409204102041120412204132041420415204162041720418204192042020421204222042320424204252042620427204282042920430204312043220433204342043520436204372043820439204402044120442204432044420445204462044720448204492045020451204522045320454204552045620457204582045920460204612046220463204642046520466204672046820469204702047120472204732047420475204762047720478204792048020481204822048320484204852048620487204882048920490204912049220493204942049520496204972049820499205002050120502205032050420505205062050720508205092051020511205122051320514205152051620517205182051920520205212052220523205242052520526205272052820529205302053120532205332053420535205362053720538205392054020541205422054320544205452054620547205482054920550205512055220553205542055520556205572055820559205602056120562205632056420565205662056720568205692057020571205722057320574205752057620577205782057920580205812058220583205842058520586205872058820589205902059120592205932059420595205962059720598205992060020601206022060320604206052060620607206082060920610206112061220613206142061520616206172061820619206202062120622206232062420625206262062720628206292063020631206322063320634206352063620637206382063920640206412064220643206442064520646206472064820649206502065120652206532065420655206562065720658206592066020661206622066320664206652066620667206682066920670206712067220673206742067520676206772067820679206802068120682206832068420685206862068720688206892069020691206922069320694206952069620697206982069920700207012070220703207042070520706207072070820709207102071120712207132071420715207162071720718207192072020721207222072320724207252072620727207282072920730207312073220733207342073520736207372073820739207402074120742207432074420745207462074720748207492075020751207522075320754207552075620757207582075920760207612076220763207642076520766207672076820769207702077120772207732077420775207762077720778207792078020781207822078320784207852078620787207882078920790207912079220793207942079520796207972079820799208002080120802208032080420805208062080720808208092081020811208122081320814208152081620817208182081920820208212082220823208242082520826208272082820829208302083120832208332083420835208362083720838208392084020841208422084320844208452084620847208482084920850208512085220853208542085520856208572085820859208602086120862208632086420865208662086720868208692087020871208722087320874208752087620877208782087920880208812088220883208842088520886208872088820889208902089120892208932089420895208962089720898208992090020901209022090320904209052090620907209082090920910209112091220913209142091520916209172091820919209202092120922209232092420925209262092720928209292093020931209322093320934209352093620937209382093920940209412094220943209442094520946209472094820949209502095120952209532095420955209562095720958209592096020961209622096320964209652096620967209682096920970209712097220973209742097520976209772097820979209802098120982209832098420985209862098720988209892099020991209922099320994209952099620997209982099921000210012100221003210042100521006210072100821009210102101121012210132101421015210162101721018210192102021021210222102321024210252102621027210282102921030210312103221033210342103521036210372103821039210402104121042210432104421045210462104721048210492105021051210522105321054210552105621057210582105921060210612106221063210642106521066210672106821069210702107121072210732107421075210762107721078210792108021081210822108321084210852108621087210882108921090210912109221093210942109521096210972109821099211002110121102211032110421105211062110721108211092111021111211122111321114211152111621117211182111921120211212112221123211242112521126211272112821129211302113121132211332113421135211362113721138211392114021141211422114321144211452114621147211482114921150211512115221153211542115521156211572115821159211602116121162211632116421165211662116721168211692117021171211722117321174211752117621177211782117921180211812118221183211842118521186211872118821189211902119121192211932119421195211962119721198211992120021201212022120321204212052120621207212082120921210212112121221213212142121521216212172121821219212202122121222212232122421225212262122721228212292123021231212322123321234212352123621237212382123921240212412124221243212442124521246212472124821249212502125121252212532125421255212562125721258212592126021261212622126321264212652126621267212682126921270212712127221273212742127521276212772127821279212802128121282212832128421285212862128721288212892129021291212922129321294212952129621297212982129921300213012130221303213042130521306213072130821309213102131121312213132131421315213162131721318213192132021321213222132321324213252132621327213282132921330213312133221333213342133521336213372133821339213402134121342213432134421345213462134721348213492135021351213522135321354213552135621357213582135921360213612136221363213642136521366213672136821369213702137121372213732137421375213762137721378213792138021381213822138321384213852138621387213882138921390213912139221393213942139521396213972139821399214002140121402214032140421405214062140721408214092141021411214122141321414214152141621417214182141921420214212142221423214242142521426214272142821429214302143121432214332143421435214362143721438214392144021441214422144321444214452144621447214482144921450214512145221453214542145521456214572145821459214602146121462214632146421465214662146721468214692147021471214722147321474214752147621477214782147921480214812148221483214842148521486214872148821489214902149121492214932149421495214962149721498214992150021501215022150321504215052150621507215082150921510215112151221513215142151521516215172151821519215202152121522215232152421525215262152721528215292153021531215322153321534215352153621537215382153921540215412154221543215442154521546215472154821549215502155121552215532155421555215562155721558215592156021561215622156321564215652156621567215682156921570215712157221573215742157521576215772157821579215802158121582215832158421585215862158721588215892159021591215922159321594215952159621597215982159921600216012160221603216042160521606216072160821609216102161121612216132161421615216162161721618216192162021621216222162321624216252162621627216282162921630216312163221633216342163521636216372163821639216402164121642216432164421645216462164721648216492165021651216522165321654216552165621657216582165921660216612166221663216642166521666216672166821669216702167121672216732167421675216762167721678216792168021681216822168321684216852168621687216882168921690216912169221693216942169521696216972169821699217002170121702217032170421705217062170721708217092171021711217122171321714217152171621717217182171921720217212172221723217242172521726217272172821729217302173121732217332173421735217362173721738217392174021741217422174321744217452174621747217482174921750217512175221753217542175521756217572175821759217602176121762217632176421765217662176721768217692177021771217722177321774217752177621777217782177921780217812178221783217842178521786217872178821789217902179121792217932179421795217962179721798217992180021801218022180321804218052180621807218082180921810218112181221813218142181521816218172181821819218202182121822218232182421825218262182721828218292183021831218322183321834218352183621837218382183921840218412184221843218442184521846218472184821849218502185121852218532185421855218562185721858218592186021861218622186321864218652186621867218682186921870218712187221873218742187521876218772187821879218802188121882218832188421885218862188721888218892189021891218922189321894218952189621897218982189921900219012190221903219042190521906219072190821909219102191121912219132191421915219162191721918219192192021921219222192321924219252192621927219282192921930219312193221933219342193521936219372193821939219402194121942219432194421945219462194721948219492195021951219522195321954219552195621957219582195921960219612196221963219642196521966219672196821969219702197121972219732197421975219762197721978219792198021981219822198321984219852198621987219882198921990219912199221993219942199521996219972199821999220002200122002220032200422005220062200722008220092201022011220122201322014220152201622017220182201922020220212202222023220242202522026220272202822029220302203122032220332203422035220362203722038220392204022041220422204322044220452204622047220482204922050220512205222053220542205522056220572205822059220602206122062220632206422065220662206722068220692207022071220722207322074220752207622077220782207922080220812208222083220842208522086220872208822089220902209122092220932209422095220962209722098220992210022101221022210322104221052210622107221082210922110221112211222113221142211522116221172211822119221202212122122221232212422125221262212722128221292213022131221322213322134221352213622137221382213922140221412214222143221442214522146221472214822149221502215122152221532215422155221562215722158221592216022161221622216322164221652216622167221682216922170221712217222173221742217522176221772217822179221802218122182221832218422185221862218722188221892219022191221922219322194221952219622197221982219922200222012220222203222042220522206222072220822209222102221122212222132221422215222162221722218222192222022221222222222322224222252222622227222282222922230222312223222233222342223522236222372223822239222402224122242222432224422245222462224722248222492225022251222522225322254222552225622257222582225922260222612226222263222642226522266222672226822269222702227122272222732227422275222762227722278222792228022281222822228322284222852228622287222882228922290222912229222293222942229522296222972229822299223002230122302223032230422305223062230722308223092231022311223122231322314223152231622317223182231922320223212232222323223242232522326223272232822329223302233122332223332233422335223362233722338223392234022341223422234322344223452234622347223482234922350223512235222353223542235522356223572235822359223602236122362223632236422365223662236722368223692237022371223722237322374223752237622377223782237922380223812238222383223842238522386223872238822389223902239122392223932239422395223962239722398223992240022401224022240322404224052240622407224082240922410224112241222413224142241522416224172241822419224202242122422224232242422425224262242722428224292243022431224322243322434224352243622437224382243922440224412244222443224442244522446224472244822449224502245122452224532245422455224562245722458224592246022461224622246322464224652246622467224682246922470224712247222473224742247522476224772247822479224802248122482224832248422485224862248722488224892249022491224922249322494224952249622497224982249922500225012250222503225042250522506225072250822509225102251122512225132251422515225162251722518225192252022521225222252322524225252252622527225282252922530225312253222533225342253522536225372253822539225402254122542225432254422545225462254722548225492255022551225522255322554225552255622557225582255922560225612256222563225642256522566225672256822569225702257122572225732257422575225762257722578225792258022581225822258322584225852258622587225882258922590225912259222593225942259522596225972259822599226002260122602226032260422605226062260722608226092261022611226122261322614226152261622617226182261922620226212262222623226242262522626226272262822629226302263122632226332263422635226362263722638226392264022641226422264322644226452264622647226482264922650226512265222653226542265522656226572265822659226602266122662226632266422665226662266722668226692267022671226722267322674226752267622677226782267922680226812268222683226842268522686226872268822689226902269122692226932269422695226962269722698226992270022701227022270322704227052270622707227082270922710227112271222713227142271522716227172271822719227202272122722227232272422725227262272722728227292273022731227322273322734227352273622737227382273922740227412274222743227442274522746227472274822749227502275122752227532275422755227562275722758227592276022761227622276322764227652276622767227682276922770227712277222773227742277522776227772277822779227802278122782227832278422785227862278722788227892279022791227922279322794227952279622797227982279922800228012280222803228042280522806228072280822809228102281122812228132281422815228162281722818228192282022821228222282322824228252282622827228282282922830228312283222833228342283522836228372283822839228402284122842228432284422845228462284722848228492285022851228522285322854228552285622857228582285922860228612286222863228642286522866228672286822869228702287122872228732287422875228762287722878228792288022881228822288322884228852288622887228882288922890228912289222893228942289522896228972289822899229002290122902229032290422905229062290722908229092291022911229122291322914229152291622917229182291922920229212292222923229242292522926229272292822929229302293122932229332293422935229362293722938229392294022941229422294322944229452294622947229482294922950229512295222953229542295522956229572295822959229602296122962229632296422965229662296722968229692297022971229722297322974229752297622977229782297922980229812298222983229842298522986229872298822989229902299122992229932299422995229962299722998229992300023001230022300323004230052300623007230082300923010230112301223013230142301523016230172301823019230202302123022230232302423025230262302723028230292303023031230322303323034230352303623037230382303923040230412304223043230442304523046230472304823049230502305123052230532305423055230562305723058230592306023061230622306323064230652306623067230682306923070230712307223073230742307523076230772307823079230802308123082230832308423085230862308723088230892309023091230922309323094230952309623097230982309923100231012310223103231042310523106231072310823109231102311123112231132311423115231162311723118231192312023121231222312323124231252312623127231282312923130231312313223133231342313523136231372313823139231402314123142231432314423145231462314723148231492315023151231522315323154231552315623157231582315923160231612316223163231642316523166231672316823169231702317123172231732317423175231762317723178231792318023181231822318323184231852318623187231882318923190231912319223193231942319523196231972319823199232002320123202232032320423205232062320723208232092321023211232122321323214232152321623217232182321923220232212322223223232242322523226232272322823229232302323123232232332323423235232362323723238232392324023241232422324323244232452324623247232482324923250232512325223253232542325523256232572325823259232602326123262232632326423265232662326723268232692327023271232722327323274232752327623277232782327923280232812328223283232842328523286232872328823289232902329123292232932329423295232962329723298232992330023301233022330323304233052330623307233082330923310233112331223313233142331523316233172331823319233202332123322233232332423325233262332723328233292333023331233322333323334233352333623337233382333923340233412334223343233442334523346233472334823349233502335123352233532335423355233562335723358233592336023361233622336323364233652336623367233682336923370233712337223373233742337523376233772337823379233802338123382233832338423385233862338723388233892339023391233922339323394233952339623397233982339923400234012340223403234042340523406234072340823409234102341123412234132341423415234162341723418234192342023421234222342323424234252342623427234282342923430234312343223433234342343523436234372343823439234402344123442234432344423445234462344723448234492345023451234522345323454234552345623457234582345923460234612346223463234642346523466234672346823469234702347123472234732347423475234762347723478234792348023481234822348323484234852348623487234882348923490234912349223493234942349523496234972349823499235002350123502235032350423505235062350723508235092351023511235122351323514235152351623517235182351923520235212352223523235242352523526235272352823529235302353123532235332353423535235362353723538235392354023541235422354323544235452354623547235482354923550235512355223553235542355523556235572355823559235602356123562235632356423565235662356723568235692357023571235722357323574235752357623577235782357923580235812358223583235842358523586235872358823589235902359123592235932359423595235962359723598235992360023601236022360323604236052360623607236082360923610236112361223613236142361523616236172361823619236202362123622236232362423625236262362723628236292363023631236322363323634236352363623637236382363923640236412364223643236442364523646236472364823649236502365123652236532365423655236562365723658236592366023661236622366323664236652366623667236682366923670236712367223673236742367523676236772367823679236802368123682236832368423685236862368723688236892369023691236922369323694236952369623697236982369923700237012370223703237042370523706237072370823709237102371123712237132371423715237162371723718237192372023721237222372323724237252372623727237282372923730237312373223733237342373523736237372373823739237402374123742237432374423745237462374723748237492375023751237522375323754237552375623757237582375923760237612376223763237642376523766237672376823769237702377123772237732377423775237762377723778237792378023781237822378323784237852378623787237882378923790237912379223793237942379523796237972379823799238002380123802238032380423805238062380723808238092381023811238122381323814238152381623817238182381923820238212382223823238242382523826238272382823829238302383123832238332383423835238362383723838238392384023841238422384323844238452384623847238482384923850238512385223853238542385523856238572385823859238602386123862238632386423865238662386723868238692387023871238722387323874238752387623877238782387923880238812388223883238842388523886238872388823889238902389123892238932389423895238962389723898238992390023901239022390323904239052390623907239082390923910239112391223913239142391523916239172391823919239202392123922239232392423925239262392723928239292393023931239322393323934239352393623937239382393923940239412394223943239442394523946239472394823949239502395123952239532395423955239562395723958239592396023961239622396323964239652396623967239682396923970239712397223973239742397523976239772397823979239802398123982239832398423985239862398723988239892399023991239922399323994239952399623997239982399924000240012400224003240042400524006240072400824009240102401124012240132401424015240162401724018240192402024021240222402324024240252402624027240282402924030240312403224033240342403524036240372403824039240402404124042240432404424045240462404724048240492405024051240522405324054240552405624057240582405924060240612406224063240642406524066240672406824069240702407124072240732407424075240762407724078240792408024081240822408324084240852408624087240882408924090240912409224093240942409524096240972409824099241002410124102241032410424105241062410724108241092411024111241122411324114241152411624117241182411924120241212412224123241242412524126241272412824129241302413124132241332413424135241362413724138241392414024141241422414324144241452414624147241482414924150241512415224153241542415524156241572415824159241602416124162241632416424165241662416724168241692417024171241722417324174241752417624177241782417924180241812418224183241842418524186241872418824189241902419124192241932419424195241962419724198241992420024201242022420324204242052420624207242082420924210242112421224213242142421524216242172421824219242202422124222242232422424225242262422724228242292423024231242322423324234242352423624237242382423924240242412424224243242442424524246242472424824249242502425124252242532425424255242562425724258242592426024261242622426324264242652426624267242682426924270242712427224273242742427524276242772427824279242802428124282242832428424285242862428724288242892429024291242922429324294242952429624297242982429924300243012430224303243042430524306243072430824309243102431124312243132431424315243162431724318243192432024321243222432324324243252432624327243282432924330243312433224333243342433524336243372433824339243402434124342243432434424345243462434724348243492435024351243522435324354243552435624357243582435924360243612436224363243642436524366243672436824369243702437124372243732437424375243762437724378243792438024381243822438324384243852438624387243882438924390243912439224393243942439524396243972439824399244002440124402244032440424405244062440724408244092441024411244122441324414244152441624417244182441924420244212442224423244242442524426244272442824429244302443124432244332443424435244362443724438244392444024441244422444324444244452444624447244482444924450244512445224453244542445524456244572445824459244602446124462244632446424465244662446724468244692447024471244722447324474244752447624477244782447924480244812448224483244842448524486244872448824489244902449124492244932449424495244962449724498244992450024501245022450324504245052450624507245082450924510245112451224513245142451524516245172451824519245202452124522245232452424525245262452724528245292453024531245322453324534245352453624537245382453924540245412454224543245442454524546245472454824549245502455124552245532455424555245562455724558245592456024561245622456324564245652456624567245682456924570245712457224573245742457524576245772457824579245802458124582245832458424585245862458724588245892459024591245922459324594245952459624597245982459924600246012460224603246042460524606246072460824609246102461124612246132461424615246162461724618246192462024621246222462324624246252462624627246282462924630246312463224633246342463524636246372463824639246402464124642246432464424645246462464724648246492465024651246522465324654246552465624657246582465924660246612466224663246642466524666246672466824669246702467124672246732467424675246762467724678246792468024681246822468324684246852468624687246882468924690246912469224693246942469524696246972469824699247002470124702247032470424705247062470724708247092471024711247122471324714247152471624717247182471924720247212472224723247242472524726247272472824729247302473124732247332473424735247362473724738247392474024741247422474324744247452474624747247482474924750247512475224753247542475524756247572475824759247602476124762247632476424765247662476724768247692477024771247722477324774247752477624777247782477924780247812478224783247842478524786247872478824789247902479124792247932479424795247962479724798247992480024801248022480324804248052480624807248082480924810248112481224813248142481524816248172481824819248202482124822248232482424825248262482724828248292483024831248322483324834248352483624837248382483924840248412484224843248442484524846248472484824849248502485124852248532485424855248562485724858248592486024861248622486324864248652486624867248682486924870248712487224873248742487524876248772487824879248802488124882248832488424885248862488724888248892489024891248922489324894248952489624897248982489924900249012490224903249042490524906249072490824909249102491124912249132491424915249162491724918249192492024921249222492324924249252492624927249282492924930249312493224933249342493524936249372493824939249402494124942249432494424945249462494724948249492495024951249522495324954249552495624957249582495924960249612496224963249642496524966249672496824969249702497124972249732497424975249762497724978249792498024981249822498324984249852498624987249882498924990249912499224993249942499524996249972499824999250002500125002250032500425005250062500725008250092501025011250122501325014250152501625017250182501925020250212502225023250242502525026250272502825029250302503125032250332503425035250362503725038250392504025041250422504325044250452504625047250482504925050250512505225053250542505525056250572505825059250602506125062250632506425065250662506725068250692507025071250722507325074250752507625077250782507925080250812508225083250842508525086250872508825089250902509125092250932509425095250962509725098250992510025101251022510325104251052510625107251082510925110251112511225113251142511525116251172511825119251202512125122251232512425125251262512725128251292513025131251322513325134251352513625137251382513925140251412514225143251442514525146251472514825149251502515125152251532515425155251562515725158251592516025161251622516325164251652516625167251682516925170251712517225173251742517525176251772517825179251802518125182251832518425185251862518725188251892519025191251922519325194251952519625197251982519925200252012520225203252042520525206252072520825209252102521125212252132521425215252162521725218252192522025221252222522325224252252522625227252282522925230252312523225233252342523525236252372523825239252402524125242252432524425245252462524725248252492525025251252522525325254252552525625257252582525925260252612526225263252642526525266252672526825269252702527125272252732527425275252762527725278252792528025281252822528325284252852528625287252882528925290252912529225293252942529525296252972529825299253002530125302253032530425305253062530725308253092531025311253122531325314253152531625317253182531925320253212532225323253242532525326253272532825329253302533125332253332533425335253362533725338253392534025341253422534325344253452534625347253482534925350253512535225353253542535525356253572535825359253602536125362253632536425365253662536725368253692537025371253722537325374253752537625377253782537925380253812538225383253842538525386253872538825389253902539125392253932539425395253962539725398253992540025401254022540325404254052540625407254082540925410254112541225413254142541525416254172541825419254202542125422254232542425425254262542725428254292543025431254322543325434254352543625437254382543925440254412544225443254442544525446254472544825449254502545125452254532545425455254562545725458254592546025461254622546325464254652546625467254682546925470254712547225473254742547525476254772547825479254802548125482254832548425485254862548725488254892549025491254922549325494254952549625497254982549925500255012550225503255042550525506255072550825509255102551125512255132551425515255162551725518255192552025521255222552325524255252552625527255282552925530255312553225533255342553525536255372553825539255402554125542255432554425545255462554725548255492555025551255522555325554255552555625557255582555925560255612556225563255642556525566255672556825569255702557125572255732557425575255762557725578255792558025581255822558325584255852558625587255882558925590255912559225593255942559525596255972559825599256002560125602256032560425605256062560725608256092561025611256122561325614256152561625617256182561925620256212562225623256242562525626256272562825629256302563125632256332563425635256362563725638256392564025641256422564325644256452564625647256482564925650256512565225653256542565525656256572565825659256602566125662256632566425665256662566725668256692567025671256722567325674256752567625677256782567925680256812568225683256842568525686256872568825689256902569125692256932569425695256962569725698256992570025701257022570325704257052570625707257082570925710257112571225713257142571525716257172571825719257202572125722257232572425725257262572725728257292573025731257322573325734257352573625737257382573925740257412574225743257442574525746257472574825749257502575125752257532575425755257562575725758257592576025761257622576325764257652576625767257682576925770257712577225773257742577525776257772577825779257802578125782257832578425785257862578725788257892579025791257922579325794257952579625797257982579925800258012580225803258042580525806258072580825809258102581125812258132581425815258162581725818258192582025821258222582325824258252582625827258282582925830258312583225833258342583525836258372583825839258402584125842258432584425845258462584725848258492585025851258522585325854258552585625857258582585925860258612586225863258642586525866258672586825869258702587125872258732587425875258762587725878258792588025881258822588325884258852588625887258882588925890258912589225893258942589525896258972589825899259002590125902259032590425905259062590725908259092591025911259122591325914259152591625917259182591925920259212592225923259242592525926259272592825929259302593125932259332593425935259362593725938259392594025941259422594325944259452594625947259482594925950259512595225953259542595525956259572595825959259602596125962259632596425965259662596725968259692597025971259722597325974259752597625977259782597925980259812598225983259842598525986259872598825989259902599125992259932599425995259962599725998259992600026001260022600326004260052600626007260082600926010260112601226013260142601526016260172601826019260202602126022260232602426025260262602726028260292603026031260322603326034260352603626037260382603926040260412604226043260442604526046260472604826049260502605126052260532605426055260562605726058260592606026061260622606326064260652606626067260682606926070260712607226073260742607526076260772607826079260802608126082260832608426085260862608726088260892609026091260922609326094260952609626097260982609926100261012610226103261042610526106261072610826109261102611126112261132611426115261162611726118261192612026121261222612326124261252612626127261282612926130261312613226133261342613526136261372613826139261402614126142261432614426145261462614726148261492615026151261522615326154261552615626157261582615926160261612616226163261642616526166261672616826169261702617126172261732617426175261762617726178261792618026181261822618326184261852618626187261882618926190261912619226193261942619526196261972619826199262002620126202262032620426205262062620726208262092621026211262122621326214262152621626217262182621926220262212622226223262242622526226262272622826229262302623126232262332623426235262362623726238262392624026241262422624326244262452624626247262482624926250262512625226253262542625526256262572625826259262602626126262262632626426265262662626726268262692627026271262722627326274262752627626277262782627926280262812628226283262842628526286262872628826289262902629126292262932629426295262962629726298262992630026301263022630326304263052630626307263082630926310263112631226313263142631526316263172631826319263202632126322263232632426325263262632726328263292633026331263322633326334263352633626337263382633926340263412634226343263442634526346263472634826349263502635126352263532635426355263562635726358263592636026361263622636326364263652636626367263682636926370263712637226373263742637526376263772637826379263802638126382263832638426385263862638726388263892639026391263922639326394263952639626397263982639926400264012640226403264042640526406264072640826409264102641126412264132641426415264162641726418264192642026421264222642326424264252642626427264282642926430264312643226433264342643526436264372643826439264402644126442264432644426445264462644726448264492645026451264522645326454264552645626457264582645926460264612646226463264642646526466264672646826469264702647126472264732647426475264762647726478264792648026481264822648326484264852648626487264882648926490264912649226493264942649526496264972649826499265002650126502265032650426505265062650726508265092651026511265122651326514265152651626517265182651926520265212652226523265242652526526265272652826529265302653126532265332653426535265362653726538265392654026541265422654326544265452654626547265482654926550265512655226553265542655526556265572655826559265602656126562265632656426565265662656726568265692657026571265722657326574265752657626577265782657926580265812658226583265842658526586265872658826589265902659126592265932659426595265962659726598265992660026601266022660326604266052660626607266082660926610266112661226613266142661526616266172661826619266202662126622266232662426625266262662726628266292663026631266322663326634266352663626637266382663926640266412664226643266442664526646266472664826649266502665126652266532665426655266562665726658266592666026661266622666326664266652666626667266682666926670266712667226673266742667526676266772667826679266802668126682266832668426685266862668726688266892669026691266922669326694266952669626697266982669926700267012670226703267042670526706267072670826709267102671126712267132671426715267162671726718267192672026721267222672326724267252672626727267282672926730267312673226733267342673526736267372673826739267402674126742267432674426745267462674726748267492675026751267522675326754267552675626757267582675926760267612676226763267642676526766267672676826769267702677126772267732677426775267762677726778267792678026781267822678326784267852678626787267882678926790267912679226793267942679526796267972679826799268002680126802268032680426805268062680726808268092681026811268122681326814268152681626817268182681926820268212682226823268242682526826268272682826829268302683126832268332683426835268362683726838268392684026841268422684326844268452684626847268482684926850268512685226853268542685526856268572685826859268602686126862268632686426865268662686726868268692687026871268722687326874268752687626877268782687926880268812688226883268842688526886268872688826889268902689126892268932689426895268962689726898268992690026901269022690326904269052690626907269082690926910269112691226913269142691526916269172691826919269202692126922269232692426925269262692726928269292693026931269322693326934269352693626937269382693926940269412694226943269442694526946269472694826949269502695126952269532695426955269562695726958269592696026961269622696326964269652696626967269682696926970269712697226973269742697526976269772697826979269802698126982269832698426985269862698726988269892699026991269922699326994269952699626997269982699927000270012700227003270042700527006270072700827009270102701127012270132701427015270162701727018270192702027021270222702327024270252702627027270282702927030270312703227033270342703527036270372703827039270402704127042270432704427045270462704727048270492705027051270522705327054270552705627057270582705927060270612706227063270642706527066270672706827069270702707127072270732707427075270762707727078270792708027081270822708327084270852708627087270882708927090270912709227093270942709527096270972709827099271002710127102271032710427105271062710727108271092711027111271122711327114271152711627117271182711927120271212712227123271242712527126271272712827129271302713127132271332713427135271362713727138271392714027141271422714327144271452714627147271482714927150271512715227153271542715527156271572715827159271602716127162271632716427165271662716727168271692717027171271722717327174271752717627177271782717927180271812718227183271842718527186271872718827189271902719127192271932719427195271962719727198271992720027201272022720327204272052720627207272082720927210272112721227213272142721527216272172721827219272202722127222272232722427225272262722727228272292723027231272322723327234272352723627237272382723927240272412724227243272442724527246272472724827249272502725127252272532725427255272562725727258272592726027261272622726327264272652726627267272682726927270272712727227273272742727527276272772727827279272802728127282272832728427285272862728727288272892729027291272922729327294272952729627297272982729927300273012730227303273042730527306273072730827309273102731127312273132731427315273162731727318273192732027321273222732327324273252732627327273282732927330273312733227333273342733527336273372733827339273402734127342273432734427345273462734727348273492735027351273522735327354273552735627357273582735927360273612736227363273642736527366273672736827369273702737127372273732737427375273762737727378273792738027381273822738327384273852738627387273882738927390273912739227393273942739527396273972739827399274002740127402274032740427405274062740727408274092741027411274122741327414274152741627417274182741927420274212742227423274242742527426274272742827429274302743127432274332743427435274362743727438274392744027441274422744327444274452744627447274482744927450274512745227453274542745527456274572745827459274602746127462274632746427465274662746727468274692747027471274722747327474274752747627477274782747927480274812748227483274842748527486274872748827489274902749127492274932749427495274962749727498274992750027501275022750327504275052750627507275082750927510275112751227513275142751527516275172751827519275202752127522275232752427525275262752727528275292753027531275322753327534275352753627537275382753927540275412754227543275442754527546275472754827549275502755127552275532755427555275562755727558275592756027561275622756327564275652756627567275682756927570275712757227573275742757527576275772757827579275802758127582275832758427585275862758727588275892759027591275922759327594275952759627597275982759927600276012760227603276042760527606276072760827609276102761127612276132761427615276162761727618276192762027621276222762327624276252762627627276282762927630276312763227633276342763527636276372763827639276402764127642276432764427645276462764727648276492765027651276522765327654276552765627657276582765927660276612766227663276642766527666276672766827669276702767127672276732767427675276762767727678276792768027681276822768327684276852768627687276882768927690276912769227693276942769527696276972769827699277002770127702277032770427705277062770727708277092771027711277122771327714277152771627717277182771927720277212772227723277242772527726277272772827729277302773127732277332773427735277362773727738277392774027741277422774327744277452774627747277482774927750277512775227753277542775527756277572775827759277602776127762277632776427765277662776727768277692777027771277722777327774277752777627777277782777927780277812778227783277842778527786277872778827789277902779127792277932779427795277962779727798277992780027801278022780327804278052780627807278082780927810278112781227813278142781527816278172781827819278202782127822278232782427825278262782727828278292783027831278322783327834278352783627837278382783927840278412784227843278442784527846278472784827849278502785127852278532785427855278562785727858278592786027861278622786327864278652786627867278682786927870278712787227873278742787527876278772787827879278802788127882278832788427885278862788727888278892789027891278922789327894278952789627897278982789927900279012790227903279042790527906279072790827909279102791127912279132791427915279162791727918279192792027921279222792327924279252792627927279282792927930279312793227933279342793527936279372793827939279402794127942279432794427945279462794727948279492795027951279522795327954279552795627957279582795927960279612796227963279642796527966279672796827969279702797127972279732797427975279762797727978279792798027981279822798327984279852798627987279882798927990279912799227993279942799527996279972799827999280002800128002280032800428005280062800728008280092801028011280122801328014280152801628017280182801928020280212802228023280242802528026280272802828029280302803128032280332803428035280362803728038280392804028041280422804328044280452804628047280482804928050280512805228053280542805528056280572805828059280602806128062280632806428065280662806728068280692807028071280722807328074280752807628077280782807928080280812808228083280842808528086280872808828089280902809128092280932809428095280962809728098280992810028101281022810328104281052810628107281082810928110281112811228113281142811528116281172811828119281202812128122281232812428125281262812728128281292813028131281322813328134281352813628137281382813928140281412814228143281442814528146281472814828149281502815128152281532815428155281562815728158281592816028161281622816328164281652816628167281682816928170281712817228173281742817528176281772817828179281802818128182281832818428185281862818728188281892819028191281922819328194281952819628197281982819928200282012820228203282042820528206282072820828209282102821128212282132821428215282162821728218282192822028221282222822328224282252822628227282282822928230282312823228233282342823528236282372823828239282402824128242282432824428245282462824728248282492825028251282522825328254282552825628257282582825928260282612826228263282642826528266282672826828269282702827128272282732827428275282762827728278282792828028281282822828328284282852828628287282882828928290282912829228293282942829528296282972829828299283002830128302283032830428305283062830728308283092831028311283122831328314283152831628317283182831928320283212832228323283242832528326283272832828329283302833128332283332833428335283362833728338283392834028341283422834328344283452834628347283482834928350283512835228353283542835528356283572835828359283602836128362283632836428365283662836728368283692837028371283722837328374283752837628377283782837928380283812838228383283842838528386283872838828389283902839128392283932839428395283962839728398283992840028401284022840328404284052840628407284082840928410284112841228413284142841528416284172841828419284202842128422284232842428425284262842728428284292843028431284322843328434284352843628437284382843928440284412844228443284442844528446284472844828449284502845128452284532845428455284562845728458284592846028461284622846328464284652846628467284682846928470284712847228473284742847528476284772847828479284802848128482284832848428485284862848728488284892849028491284922849328494284952849628497284982849928500285012850228503285042850528506285072850828509285102851128512285132851428515285162851728518285192852028521285222852328524285252852628527285282852928530285312853228533285342853528536285372853828539285402854128542285432854428545285462854728548285492855028551285522855328554285552855628557285582855928560285612856228563285642856528566285672856828569285702857128572285732857428575285762857728578285792858028581285822858328584285852858628587285882858928590285912859228593285942859528596285972859828599286002860128602286032860428605286062860728608286092861028611286122861328614286152861628617286182861928620286212862228623286242862528626286272862828629286302863128632286332863428635286362863728638286392864028641286422864328644286452864628647286482864928650286512865228653286542865528656286572865828659286602866128662286632866428665286662866728668286692867028671286722867328674286752867628677286782867928680286812868228683286842868528686286872868828689286902869128692286932869428695286962869728698286992870028701287022870328704287052870628707287082870928710287112871228713287142871528716287172871828719287202872128722287232872428725287262872728728287292873028731287322873328734287352873628737287382873928740287412874228743287442874528746287472874828749287502875128752287532875428755287562875728758287592876028761287622876328764287652876628767287682876928770287712877228773287742877528776287772877828779287802878128782287832878428785287862878728788287892879028791287922879328794287952879628797287982879928800288012880228803288042880528806288072880828809288102881128812288132881428815288162881728818288192882028821288222882328824288252882628827288282882928830288312883228833288342883528836288372883828839288402884128842288432884428845288462884728848288492885028851288522885328854288552885628857288582885928860288612886228863288642886528866288672886828869288702887128872288732887428875288762887728878288792888028881288822888328884288852888628887288882888928890288912889228893288942889528896288972889828899289002890128902289032890428905289062890728908289092891028911289122891328914289152891628917289182891928920289212892228923289242892528926289272892828929289302893128932289332893428935289362893728938289392894028941289422894328944289452894628947289482894928950289512895228953289542895528956289572895828959289602896128962289632896428965289662896728968289692897028971289722897328974289752897628977289782897928980289812898228983289842898528986289872898828989289902899128992289932899428995289962899728998289992900029001290022900329004290052900629007290082900929010290112901229013290142901529016290172901829019290202902129022290232902429025290262902729028290292903029031290322903329034290352903629037290382903929040290412904229043290442904529046290472904829049290502905129052290532905429055290562905729058290592906029061290622906329064290652906629067290682906929070290712907229073290742907529076290772907829079290802908129082290832908429085290862908729088290892909029091290922909329094290952909629097290982909929100291012910229103291042910529106291072910829109291102911129112291132911429115291162911729118291192912029121291222912329124291252912629127291282912929130291312913229133291342913529136291372913829139291402914129142291432914429145291462914729148291492915029151291522915329154291552915629157291582915929160291612916229163291642916529166291672916829169291702917129172291732917429175291762917729178291792918029181291822918329184291852918629187291882918929190291912919229193291942919529196291972919829199292002920129202292032920429205292062920729208292092921029211292122921329214292152921629217292182921929220292212922229223292242922529226292272922829229292302923129232292332923429235292362923729238292392924029241292422924329244292452924629247292482924929250292512925229253292542925529256292572925829259292602926129262292632926429265292662926729268292692927029271292722927329274292752927629277292782927929280292812928229283292842928529286292872928829289292902929129292292932929429295292962929729298292992930029301293022930329304293052930629307293082930929310293112931229313293142931529316293172931829319293202932129322293232932429325293262932729328293292933029331293322933329334293352933629337293382933929340293412934229343293442934529346293472934829349293502935129352293532935429355293562935729358293592936029361293622936329364293652936629367293682936929370293712937229373293742937529376293772937829379293802938129382293832938429385293862938729388293892939029391293922939329394293952939629397293982939929400294012940229403294042940529406294072940829409294102941129412294132941429415294162941729418294192942029421294222942329424294252942629427294282942929430294312943229433294342943529436294372943829439294402944129442294432944429445294462944729448294492945029451294522945329454294552945629457294582945929460294612946229463294642946529466294672946829469294702947129472294732947429475294762947729478294792948029481294822948329484294852948629487294882948929490294912949229493294942949529496294972949829499295002950129502295032950429505295062950729508295092951029511295122951329514295152951629517295182951929520295212952229523295242952529526295272952829529295302953129532295332953429535295362953729538295392954029541295422954329544295452954629547295482954929550295512955229553295542955529556295572955829559295602956129562295632956429565295662956729568295692957029571295722957329574295752957629577295782957929580295812958229583295842958529586295872958829589295902959129592295932959429595295962959729598295992960029601296022960329604296052960629607296082960929610296112961229613296142961529616296172961829619296202962129622296232962429625296262962729628296292963029631296322963329634296352963629637296382963929640296412964229643296442964529646296472964829649296502965129652296532965429655296562965729658296592966029661296622966329664296652966629667296682966929670296712967229673296742967529676296772967829679296802968129682296832968429685296862968729688296892969029691296922969329694296952969629697296982969929700297012970229703297042970529706297072970829709297102971129712297132971429715297162971729718297192972029721297222972329724297252972629727297282972929730297312973229733297342973529736297372973829739297402974129742297432974429745297462974729748297492975029751297522975329754297552975629757297582975929760297612976229763297642976529766297672976829769297702977129772297732977429775297762977729778297792978029781297822978329784297852978629787297882978929790297912979229793297942979529796297972979829799298002980129802298032980429805298062980729808298092981029811298122981329814298152981629817298182981929820298212982229823298242982529826298272982829829298302983129832298332983429835298362983729838298392984029841298422984329844298452984629847298482984929850298512985229853298542985529856298572985829859298602986129862298632986429865298662986729868298692987029871298722987329874298752987629877298782987929880298812988229883298842988529886298872988829889298902989129892298932989429895298962989729898298992990029901299022990329904299052990629907299082990929910299112991229913299142991529916299172991829919299202992129922299232992429925299262992729928299292993029931299322993329934299352993629937299382993929940299412994229943299442994529946299472994829949299502995129952299532995429955299562995729958299592996029961299622996329964299652996629967299682996929970299712997229973299742997529976299772997829979299802998129982299832998429985299862998729988299892999029991299922999329994299952999629997299982999930000300013000230003300043000530006300073000830009300103001130012300133001430015300163001730018300193002030021300223002330024300253002630027300283002930030300313003230033300343003530036300373003830039300403004130042300433004430045300463004730048300493005030051300523005330054300553005630057300583005930060300613006230063300643006530066300673006830069300703007130072300733007430075300763007730078300793008030081300823008330084300853008630087300883008930090300913009230093300943009530096300973009830099301003010130102301033010430105301063010730108301093011030111301123011330114301153011630117301183011930120301213012230123301243012530126301273012830129301303013130132301333013430135301363013730138301393014030141301423014330144301453014630147301483014930150301513015230153301543015530156301573015830159301603016130162301633016430165301663016730168301693017030171301723017330174301753017630177301783017930180301813018230183301843018530186301873018830189301903019130192301933019430195301963019730198301993020030201302023020330204302053020630207302083020930210302113021230213302143021530216302173021830219302203022130222302233022430225302263022730228302293023030231302323023330234302353023630237302383023930240302413024230243302443024530246302473024830249302503025130252302533025430255302563025730258302593026030261302623026330264302653026630267302683026930270302713027230273302743027530276302773027830279302803028130282302833028430285302863028730288302893029030291302923029330294302953029630297302983029930300303013030230303303043030530306303073030830309303103031130312303133031430315303163031730318303193032030321303223032330324303253032630327303283032930330303313033230333303343033530336303373033830339303403034130342303433034430345303463034730348303493035030351303523035330354303553035630357303583035930360303613036230363303643036530366303673036830369303703037130372303733037430375303763037730378303793038030381303823038330384303853038630387303883038930390303913039230393303943039530396303973039830399304003040130402304033040430405304063040730408304093041030411304123041330414304153041630417304183041930420304213042230423304243042530426304273042830429304303043130432304333043430435304363043730438304393044030441304423044330444304453044630447304483044930450304513045230453304543045530456304573045830459304603046130462304633046430465304663046730468304693047030471304723047330474304753047630477304783047930480304813048230483304843048530486304873048830489304903049130492304933049430495304963049730498304993050030501305023050330504305053050630507305083050930510305113051230513305143051530516305173051830519305203052130522305233052430525305263052730528305293053030531305323053330534305353053630537305383053930540305413054230543305443054530546305473054830549305503055130552305533055430555305563055730558305593056030561305623056330564305653056630567305683056930570305713057230573305743057530576305773057830579305803058130582305833058430585305863058730588305893059030591305923059330594305953059630597305983059930600306013060230603306043060530606306073060830609306103061130612306133061430615306163061730618306193062030621306223062330624306253062630627306283062930630306313063230633306343063530636306373063830639306403064130642306433064430645306463064730648306493065030651306523065330654306553065630657306583065930660306613066230663306643066530666306673066830669306703067130672306733067430675306763067730678306793068030681306823068330684306853068630687306883068930690306913069230693306943069530696306973069830699307003070130702307033070430705307063070730708307093071030711307123071330714307153071630717307183071930720307213072230723307243072530726307273072830729307303073130732307333073430735307363073730738307393074030741307423074330744307453074630747307483074930750307513075230753307543075530756307573075830759307603076130762307633076430765307663076730768307693077030771307723077330774307753077630777307783077930780307813078230783307843078530786307873078830789307903079130792307933079430795307963079730798307993080030801308023080330804308053080630807308083080930810308113081230813308143081530816308173081830819308203082130822308233082430825308263082730828308293083030831308323083330834308353083630837308383083930840308413084230843308443084530846308473084830849308503085130852308533085430855308563085730858308593086030861308623086330864308653086630867308683086930870308713087230873308743087530876308773087830879308803088130882308833088430885308863088730888308893089030891308923089330894308953089630897308983089930900309013090230903309043090530906309073090830909309103091130912309133091430915309163091730918309193092030921309223092330924309253092630927309283092930930309313093230933309343093530936309373093830939309403094130942309433094430945309463094730948309493095030951309523095330954309553095630957309583095930960309613096230963309643096530966309673096830969309703097130972309733097430975309763097730978309793098030981309823098330984309853098630987309883098930990309913099230993309943099530996309973099830999310003100131002310033100431005310063100731008310093101031011310123101331014310153101631017310183101931020310213102231023310243102531026310273102831029310303103131032310333103431035310363103731038310393104031041310423104331044310453104631047310483104931050310513105231053310543105531056310573105831059310603106131062310633106431065310663106731068310693107031071310723107331074310753107631077310783107931080310813108231083310843108531086310873108831089310903109131092310933109431095310963109731098310993110031101311023110331104311053110631107311083110931110311113111231113311143111531116311173111831119311203112131122311233112431125311263112731128311293113031131311323113331134311353113631137311383113931140311413114231143311443114531146311473114831149311503115131152311533115431155311563115731158311593116031161311623116331164311653116631167311683116931170311713117231173311743117531176311773117831179311803118131182311833118431185311863118731188311893119031191311923119331194311953119631197311983119931200312013120231203312043120531206312073120831209312103121131212312133121431215312163121731218312193122031221312223122331224312253122631227312283122931230312313123231233312343123531236312373123831239312403124131242312433124431245312463124731248312493125031251312523125331254312553125631257312583125931260312613126231263312643126531266312673126831269312703127131272312733127431275312763127731278312793128031281312823128331284312853128631287312883128931290312913129231293312943129531296312973129831299313003130131302313033130431305313063130731308313093131031311313123131331314313153131631317313183131931320313213132231323313243132531326313273132831329313303133131332313333133431335313363133731338313393134031341313423134331344313453134631347313483134931350313513135231353313543135531356313573135831359313603136131362313633136431365313663136731368313693137031371313723137331374313753137631377313783137931380313813138231383313843138531386313873138831389313903139131392313933139431395313963139731398313993140031401314023140331404314053140631407314083140931410314113141231413314143141531416314173141831419314203142131422314233142431425314263142731428314293143031431314323143331434314353143631437314383143931440314413144231443314443144531446314473144831449314503145131452314533145431455314563145731458314593146031461314623146331464314653146631467314683146931470314713147231473314743147531476314773147831479314803148131482314833148431485314863148731488314893149031491314923149331494314953149631497314983149931500315013150231503315043150531506315073150831509315103151131512315133151431515315163151731518315193152031521315223152331524315253152631527315283152931530315313153231533315343153531536315373153831539315403154131542315433154431545315463154731548315493155031551315523155331554315553155631557315583155931560315613156231563315643156531566315673156831569315703157131572315733157431575315763157731578315793158031581315823158331584315853158631587315883158931590315913159231593315943159531596315973159831599316003160131602316033160431605316063160731608316093161031611316123161331614316153161631617316183161931620316213162231623316243162531626316273162831629316303163131632316333163431635316363163731638316393164031641316423164331644316453164631647316483164931650316513165231653316543165531656316573165831659316603166131662316633166431665316663166731668316693167031671316723167331674316753167631677316783167931680316813168231683316843168531686316873168831689316903169131692316933169431695316963169731698316993170031701317023170331704317053170631707317083170931710317113171231713317143171531716317173171831719317203172131722317233172431725317263172731728317293173031731317323173331734317353173631737317383173931740317413174231743317443174531746317473174831749317503175131752317533175431755317563175731758317593176031761317623176331764317653176631767317683176931770317713177231773317743177531776317773177831779317803178131782317833178431785317863178731788317893179031791317923179331794317953179631797317983179931800318013180231803318043180531806318073180831809318103181131812318133181431815318163181731818318193182031821318223182331824318253182631827318283182931830318313183231833318343183531836318373183831839318403184131842318433184431845318463184731848318493185031851318523185331854318553185631857318583185931860318613186231863318643186531866318673186831869318703187131872318733187431875318763187731878318793188031881318823188331884318853188631887318883188931890318913189231893318943189531896318973189831899319003190131902319033190431905319063190731908319093191031911319123191331914319153191631917319183191931920319213192231923319243192531926319273192831929319303193131932319333193431935319363193731938319393194031941319423194331944319453194631947319483194931950319513195231953319543195531956319573195831959319603196131962319633196431965319663196731968319693197031971319723197331974319753197631977319783197931980319813198231983319843198531986319873198831989319903199131992319933199431995319963199731998319993200032001320023200332004320053200632007320083200932010320113201232013320143201532016320173201832019320203202132022320233202432025320263202732028320293203032031320323203332034320353203632037320383203932040320413204232043320443204532046320473204832049320503205132052320533205432055320563205732058320593206032061320623206332064320653206632067320683206932070320713207232073320743207532076320773207832079320803208132082320833208432085320863208732088320893209032091320923209332094320953209632097320983209932100321013210232103321043210532106321073210832109321103211132112321133211432115321163211732118321193212032121321223212332124321253212632127321283212932130321313213232133321343213532136321373213832139321403214132142321433214432145321463214732148321493215032151321523215332154321553215632157321583215932160321613216232163321643216532166321673216832169321703217132172321733217432175321763217732178321793218032181321823218332184321853218632187321883218932190321913219232193321943219532196321973219832199322003220132202322033220432205322063220732208322093221032211322123221332214322153221632217322183221932220322213222232223322243222532226322273222832229322303223132232322333223432235322363223732238322393224032241322423224332244322453224632247322483224932250322513225232253322543225532256322573225832259322603226132262322633226432265322663226732268322693227032271322723227332274322753227632277322783227932280322813228232283322843228532286322873228832289322903229132292322933229432295322963229732298322993230032301323023230332304323053230632307323083230932310323113231232313323143231532316323173231832319323203232132322323233232432325323263232732328323293233032331323323233332334323353233632337323383233932340323413234232343323443234532346323473234832349323503235132352323533235432355323563235732358323593236032361323623236332364323653236632367323683236932370323713237232373323743237532376323773237832379323803238132382323833238432385323863238732388323893239032391323923239332394323953239632397323983239932400324013240232403324043240532406324073240832409324103241132412324133241432415324163241732418324193242032421324223242332424324253242632427324283242932430324313243232433324343243532436324373243832439324403244132442324433244432445324463244732448324493245032451324523245332454324553245632457324583245932460324613246232463324643246532466324673246832469324703247132472324733247432475324763247732478324793248032481324823248332484324853248632487324883248932490324913249232493324943249532496324973249832499325003250132502325033250432505325063250732508325093251032511325123251332514325153251632517325183251932520325213252232523325243252532526325273252832529325303253132532325333253432535325363253732538325393254032541325423254332544325453254632547325483254932550325513255232553325543255532556325573255832559325603256132562325633256432565325663256732568325693257032571325723257332574325753257632577325783257932580325813258232583325843258532586325873258832589325903259132592325933259432595325963259732598325993260032601326023260332604326053260632607326083260932610326113261232613326143261532616326173261832619326203262132622326233262432625326263262732628326293263032631326323263332634326353263632637326383263932640326413264232643326443264532646326473264832649326503265132652326533265432655326563265732658326593266032661326623266332664326653266632667326683266932670326713267232673326743267532676326773267832679326803268132682326833268432685326863268732688326893269032691326923269332694326953269632697326983269932700327013270232703327043270532706327073270832709327103271132712327133271432715327163271732718327193272032721327223272332724327253272632727327283272932730327313273232733327343273532736327373273832739327403274132742327433274432745327463274732748327493275032751327523275332754327553275632757327583275932760327613276232763327643276532766327673276832769327703277132772327733277432775327763277732778327793278032781327823278332784327853278632787327883278932790327913279232793327943279532796327973279832799328003280132802328033280432805328063280732808328093281032811328123281332814328153281632817328183281932820328213282232823328243282532826328273282832829328303283132832328333283432835328363283732838328393284032841328423284332844328453284632847328483284932850328513285232853328543285532856328573285832859328603286132862328633286432865328663286732868328693287032871328723287332874328753287632877328783287932880328813288232883328843288532886328873288832889328903289132892328933289432895328963289732898328993290032901329023290332904329053290632907329083290932910329113291232913329143291532916329173291832919329203292132922329233292432925329263292732928329293293032931329323293332934329353293632937329383293932940329413294232943329443294532946329473294832949329503295132952329533295432955329563295732958329593296032961329623296332964329653296632967329683296932970329713297232973329743297532976329773297832979329803298132982329833298432985329863298732988329893299032991329923299332994329953299632997329983299933000330013300233003330043300533006330073300833009330103301133012330133301433015330163301733018330193302033021330223302333024330253302633027330283302933030330313303233033330343303533036330373303833039330403304133042330433304433045330463304733048330493305033051330523305333054330553305633057330583305933060330613306233063330643306533066330673306833069330703307133072330733307433075330763307733078330793308033081330823308333084330853308633087330883308933090330913309233093330943309533096330973309833099331003310133102331033310433105331063310733108331093311033111331123311333114331153311633117331183311933120331213312233123331243312533126331273312833129331303313133132331333313433135331363313733138331393314033141331423314333144331453314633147331483314933150331513315233153331543315533156331573315833159331603316133162331633316433165331663316733168331693317033171331723317333174331753317633177331783317933180331813318233183331843318533186331873318833189331903319133192331933319433195331963319733198331993320033201332023320333204332053320633207332083320933210332113321233213332143321533216332173321833219332203322133222332233322433225332263322733228332293323033231332323323333234332353323633237332383323933240332413324233243332443324533246332473324833249332503325133252332533325433255332563325733258332593326033261332623326333264332653326633267332683326933270332713327233273332743327533276332773327833279332803328133282332833328433285332863328733288332893329033291332923329333294332953329633297332983329933300333013330233303333043330533306333073330833309333103331133312333133331433315333163331733318333193332033321333223332333324333253332633327333283332933330333313333233333333343333533336333373333833339333403334133342333433334433345333463334733348333493335033351333523335333354333553335633357333583335933360333613336233363333643336533366333673336833369333703337133372333733337433375333763337733378333793338033381333823338333384333853338633387333883338933390333913339233393333943339533396333973339833399334003340133402334033340433405334063340733408334093341033411334123341333414334153341633417334183341933420334213342233423334243342533426334273342833429334303343133432334333343433435334363343733438334393344033441334423344333444334453344633447334483344933450334513345233453334543345533456334573345833459334603346133462334633346433465334663346733468334693347033471334723347333474334753347633477334783347933480334813348233483334843348533486334873348833489334903349133492334933349433495334963349733498334993350033501335023350333504335053350633507335083350933510335113351233513335143351533516335173351833519335203352133522335233352433525335263352733528335293353033531335323353333534335353353633537335383353933540335413354233543335443354533546335473354833549335503355133552335533355433555335563355733558335593356033561335623356333564335653356633567335683356933570335713357233573335743357533576335773357833579335803358133582335833358433585335863358733588335893359033591335923359333594335953359633597335983359933600336013360233603336043360533606336073360833609336103361133612336133361433615336163361733618336193362033621336223362333624336253362633627336283362933630336313363233633336343363533636336373363833639336403364133642336433364433645336463364733648336493365033651336523365333654336553365633657336583365933660336613366233663336643366533666336673366833669336703367133672336733367433675336763367733678336793368033681336823368333684336853368633687336883368933690336913369233693336943369533696336973369833699337003370133702337033370433705337063370733708337093371033711337123371333714337153371633717337183371933720337213372233723337243372533726337273372833729337303373133732337333373433735337363373733738337393374033741337423374333744337453374633747337483374933750337513375233753337543375533756337573375833759337603376133762337633376433765337663376733768337693377033771337723377333774337753377633777337783377933780337813378233783337843378533786337873378833789337903379133792337933379433795337963379733798337993380033801338023380333804338053380633807338083380933810338113381233813338143381533816338173381833819338203382133822338233382433825338263382733828338293383033831338323383333834338353383633837338383383933840338413384233843338443384533846338473384833849338503385133852338533385433855338563385733858338593386033861338623386333864338653386633867338683386933870338713387233873338743387533876338773387833879338803388133882338833388433885338863388733888338893389033891338923389333894338953389633897338983389933900339013390233903339043390533906339073390833909339103391133912339133391433915339163391733918339193392033921339223392333924339253392633927339283392933930339313393233933339343393533936339373393833939339403394133942339433394433945339463394733948339493395033951339523395333954339553395633957339583395933960339613396233963339643396533966339673396833969339703397133972339733397433975339763397733978339793398033981339823398333984339853398633987339883398933990339913399233993339943399533996339973399833999340003400134002340033400434005340063400734008340093401034011340123401334014340153401634017340183401934020340213402234023340243402534026340273402834029340303403134032340333403434035340363403734038340393404034041340423404334044340453404634047340483404934050340513405234053340543405534056340573405834059340603406134062340633406434065340663406734068340693407034071340723407334074340753407634077340783407934080340813408234083340843408534086340873408834089340903409134092340933409434095340963409734098340993410034101341023410334104341053410634107341083410934110341113411234113341143411534116341173411834119341203412134122341233412434125341263412734128341293413034131341323413334134341353413634137341383413934140341413414234143341443414534146341473414834149341503415134152341533415434155341563415734158341593416034161341623416334164341653416634167341683416934170341713417234173341743417534176341773417834179341803418134182341833418434185341863418734188341893419034191341923419334194341953419634197341983419934200342013420234203342043420534206342073420834209342103421134212342133421434215342163421734218342193422034221342223422334224342253422634227342283422934230342313423234233342343423534236342373423834239342403424134242342433424434245342463424734248342493425034251342523425334254342553425634257342583425934260342613426234263342643426534266342673426834269342703427134272342733427434275342763427734278342793428034281342823428334284342853428634287342883428934290342913429234293342943429534296342973429834299343003430134302343033430434305343063430734308343093431034311343123431334314343153431634317343183431934320343213432234323343243432534326343273432834329343303433134332343333433434335343363433734338343393434034341343423434334344343453434634347343483434934350343513435234353343543435534356343573435834359343603436134362343633436434365343663436734368343693437034371343723437334374343753437634377343783437934380343813438234383343843438534386343873438834389343903439134392343933439434395343963439734398343993440034401344023440334404344053440634407344083440934410344113441234413344143441534416344173441834419344203442134422344233442434425344263442734428344293443034431344323443334434344353443634437344383443934440344413444234443344443444534446344473444834449344503445134452344533445434455344563445734458344593446034461344623446334464344653446634467344683446934470344713447234473344743447534476344773447834479344803448134482344833448434485344863448734488344893449034491344923449334494344953449634497344983449934500345013450234503345043450534506345073450834509345103451134512345133451434515345163451734518345193452034521345223452334524345253452634527345283452934530345313453234533345343453534536345373453834539345403454134542345433454434545345463454734548345493455034551345523455334554345553455634557345583455934560345613456234563345643456534566345673456834569345703457134572345733457434575345763457734578345793458034581345823458334584345853458634587345883458934590345913459234593345943459534596345973459834599346003460134602346033460434605346063460734608346093461034611346123461334614346153461634617346183461934620346213462234623346243462534626346273462834629346303463134632346333463434635346363463734638346393464034641346423464334644346453464634647346483464934650346513465234653346543465534656346573465834659346603466134662346633466434665346663466734668346693467034671346723467334674346753467634677346783467934680346813468234683346843468534686346873468834689346903469134692346933469434695346963469734698346993470034701347023470334704347053470634707347083470934710347113471234713347143471534716347173471834719347203472134722347233472434725347263472734728347293473034731347323473334734347353473634737347383473934740347413474234743347443474534746347473474834749347503475134752347533475434755347563475734758347593476034761347623476334764347653476634767347683476934770347713477234773347743477534776347773477834779347803478134782347833478434785347863478734788347893479034791347923479334794347953479634797347983479934800348013480234803348043480534806348073480834809348103481134812348133481434815348163481734818348193482034821348223482334824348253482634827348283482934830348313483234833348343483534836348373483834839348403484134842348433484434845348463484734848348493485034851348523485334854348553485634857348583485934860348613486234863348643486534866348673486834869348703487134872348733487434875348763487734878348793488034881348823488334884348853488634887348883488934890348913489234893348943489534896348973489834899349003490134902349033490434905349063490734908349093491034911349123491334914349153491634917349183491934920349213492234923349243492534926349273492834929349303493134932349333493434935349363493734938349393494034941349423494334944349453494634947349483494934950349513495234953349543495534956349573495834959349603496134962349633496434965349663496734968349693497034971349723497334974349753497634977349783497934980349813498234983349843498534986349873498834989349903499134992349933499434995349963499734998349993500035001350023500335004350053500635007350083500935010350113501235013350143501535016350173501835019350203502135022350233502435025350263502735028350293503035031350323503335034350353503635037350383503935040350413504235043350443504535046350473504835049350503505135052350533505435055350563505735058350593506035061350623506335064350653506635067350683506935070350713507235073350743507535076350773507835079350803508135082350833508435085350863508735088350893509035091350923509335094350953509635097350983509935100351013510235103351043510535106351073510835109351103511135112351133511435115351163511735118351193512035121351223512335124351253512635127351283512935130351313513235133351343513535136351373513835139351403514135142351433514435145351463514735148351493515035151351523515335154351553515635157351583515935160351613516235163351643516535166351673516835169351703517135172351733517435175351763517735178351793518035181351823518335184351853518635187351883518935190351913519235193351943519535196351973519835199352003520135202352033520435205352063520735208352093521035211352123521335214352153521635217352183521935220352213522235223352243522535226352273522835229352303523135232352333523435235352363523735238352393524035241352423524335244352453524635247352483524935250352513525235253352543525535256352573525835259352603526135262352633526435265352663526735268352693527035271352723527335274352753527635277352783527935280352813528235283352843528535286352873528835289352903529135292352933529435295352963529735298352993530035301353023530335304353053530635307353083530935310353113531235313353143531535316353173531835319353203532135322353233532435325353263532735328353293533035331353323533335334353353533635337353383533935340353413534235343353443534535346353473534835349353503535135352353533535435355353563535735358353593536035361353623536335364353653536635367353683536935370353713537235373353743537535376353773537835379353803538135382353833538435385353863538735388353893539035391353923539335394353953539635397353983539935400354013540235403354043540535406354073540835409354103541135412354133541435415354163541735418354193542035421354223542335424354253542635427354283542935430354313543235433354343543535436354373543835439354403544135442354433544435445354463544735448354493545035451354523545335454354553545635457354583545935460354613546235463354643546535466354673546835469354703547135472354733547435475354763547735478354793548035481354823548335484354853548635487354883548935490354913549235493354943549535496354973549835499355003550135502355033550435505355063550735508355093551035511355123551335514355153551635517355183551935520355213552235523355243552535526355273552835529355303553135532355333553435535355363553735538355393554035541355423554335544355453554635547355483554935550355513555235553355543555535556355573555835559355603556135562355633556435565355663556735568355693557035571355723557335574355753557635577355783557935580355813558235583355843558535586355873558835589355903559135592355933559435595355963559735598355993560035601356023560335604356053560635607356083560935610356113561235613356143561535616356173561835619356203562135622356233562435625356263562735628356293563035631356323563335634356353563635637356383563935640356413564235643356443564535646356473564835649356503565135652356533565435655356563565735658356593566035661356623566335664356653566635667356683566935670356713567235673356743567535676356773567835679356803568135682356833568435685356863568735688356893569035691356923569335694356953569635697356983569935700357013570235703357043570535706357073570835709357103571135712357133571435715357163571735718357193572035721357223572335724357253572635727357283572935730357313573235733357343573535736357373573835739357403574135742357433574435745357463574735748357493575035751357523575335754357553575635757357583575935760357613576235763357643576535766357673576835769357703577135772357733577435775357763577735778357793578035781357823578335784357853578635787357883578935790357913579235793357943579535796357973579835799358003580135802358033580435805358063580735808358093581035811358123581335814358153581635817358183581935820358213582235823358243582535826358273582835829358303583135832358333583435835358363583735838358393584035841358423584335844358453584635847358483584935850358513585235853358543585535856358573585835859358603586135862358633586435865358663586735868358693587035871358723587335874358753587635877358783587935880358813588235883358843588535886358873588835889358903589135892358933589435895358963589735898358993590035901359023590335904359053590635907359083590935910359113591235913359143591535916359173591835919359203592135922359233592435925359263592735928359293593035931359323593335934359353593635937359383593935940359413594235943359443594535946359473594835949359503595135952359533595435955359563595735958359593596035961359623596335964359653596635967359683596935970359713597235973359743597535976359773597835979359803598135982359833598435985359863598735988359893599035991359923599335994359953599635997359983599936000360013600236003360043600536006360073600836009360103601136012360133601436015360163601736018360193602036021360223602336024360253602636027360283602936030360313603236033360343603536036360373603836039360403604136042360433604436045360463604736048360493605036051360523605336054360553605636057360583605936060360613606236063360643606536066360673606836069360703607136072360733607436075360763607736078360793608036081360823608336084360853608636087360883608936090360913609236093360943609536096360973609836099361003610136102361033610436105361063610736108361093611036111361123611336114361153611636117361183611936120361213612236123361243612536126361273612836129361303613136132361333613436135361363613736138361393614036141361423614336144361453614636147361483614936150361513615236153361543615536156361573615836159361603616136162361633616436165361663616736168361693617036171361723617336174361753617636177361783617936180361813618236183361843618536186361873618836189361903619136192361933619436195361963619736198361993620036201362023620336204362053620636207362083620936210362113621236213362143621536216362173621836219362203622136222362233622436225362263622736228362293623036231362323623336234362353623636237362383623936240362413624236243362443624536246362473624836249362503625136252362533625436255362563625736258362593626036261362623626336264362653626636267362683626936270362713627236273362743627536276362773627836279362803628136282362833628436285362863628736288362893629036291362923629336294362953629636297362983629936300363013630236303363043630536306363073630836309363103631136312363133631436315363163631736318363193632036321363223632336324363253632636327363283632936330363313633236333363343633536336363373633836339363403634136342363433634436345363463634736348363493635036351363523635336354363553635636357363583635936360363613636236363363643636536366363673636836369363703637136372363733637436375363763637736378363793638036381363823638336384363853638636387363883638936390363913639236393363943639536396363973639836399364003640136402364033640436405364063640736408364093641036411364123641336414364153641636417364183641936420364213642236423364243642536426364273642836429364303643136432364333643436435364363643736438364393644036441364423644336444364453644636447364483644936450364513645236453364543645536456364573645836459364603646136462364633646436465364663646736468364693647036471364723647336474364753647636477364783647936480364813648236483364843648536486364873648836489364903649136492364933649436495364963649736498364993650036501365023650336504365053650636507365083650936510365113651236513365143651536516365173651836519365203652136522365233652436525365263652736528365293653036531365323653336534365353653636537365383653936540365413654236543365443654536546365473654836549365503655136552365533655436555365563655736558365593656036561365623656336564365653656636567365683656936570365713657236573365743657536576365773657836579365803658136582365833658436585365863658736588365893659036591365923659336594365953659636597365983659936600366013660236603366043660536606366073660836609366103661136612366133661436615366163661736618366193662036621366223662336624366253662636627366283662936630366313663236633366343663536636366373663836639366403664136642366433664436645366463664736648366493665036651366523665336654366553665636657366583665936660366613666236663366643666536666366673666836669366703667136672366733667436675366763667736678366793668036681366823668336684366853668636687366883668936690366913669236693366943669536696366973669836699367003670136702367033670436705367063670736708367093671036711367123671336714367153671636717367183671936720367213672236723367243672536726367273672836729367303673136732367333673436735367363673736738367393674036741367423674336744367453674636747367483674936750367513675236753367543675536756367573675836759367603676136762367633676436765367663676736768367693677036771367723677336774367753677636777367783677936780367813678236783367843678536786367873678836789367903679136792367933679436795367963679736798367993680036801368023680336804368053680636807368083680936810368113681236813368143681536816368173681836819368203682136822368233682436825368263682736828368293683036831368323683336834368353683636837368383683936840368413684236843368443684536846368473684836849368503685136852368533685436855368563685736858368593686036861368623686336864368653686636867368683686936870368713687236873368743687536876368773687836879368803688136882368833688436885368863688736888368893689036891368923689336894368953689636897368983689936900369013690236903369043690536906369073690836909369103691136912369133691436915369163691736918369193692036921369223692336924369253692636927369283692936930369313693236933369343693536936369373693836939369403694136942369433694436945369463694736948369493695036951369523695336954369553695636957369583695936960369613696236963369643696536966369673696836969369703697136972369733697436975369763697736978369793698036981369823698336984369853698636987369883698936990369913699236993369943699536996369973699836999370003700137002370033700437005370063700737008370093701037011370123701337014370153701637017370183701937020370213702237023370243702537026370273702837029370303703137032370333703437035370363703737038370393704037041370423704337044370453704637047370483704937050370513705237053370543705537056370573705837059370603706137062370633706437065370663706737068370693707037071370723707337074370753707637077370783707937080370813708237083370843708537086370873708837089370903709137092370933709437095370963709737098370993710037101371023710337104371053710637107371083710937110371113711237113371143711537116371173711837119371203712137122371233712437125371263712737128371293713037131371323713337134371353713637137371383713937140371413714237143371443714537146371473714837149371503715137152371533715437155371563715737158371593716037161371623716337164371653716637167371683716937170371713717237173371743717537176371773717837179371803718137182371833718437185371863718737188371893719037191371923719337194371953719637197371983719937200372013720237203372043720537206372073720837209372103721137212372133721437215372163721737218372193722037221372223722337224372253722637227372283722937230372313723237233372343723537236372373723837239372403724137242372433724437245372463724737248372493725037251372523725337254372553725637257372583725937260372613726237263372643726537266372673726837269372703727137272372733727437275372763727737278372793728037281372823728337284372853728637287372883728937290372913729237293372943729537296372973729837299373003730137302373033730437305373063730737308373093731037311373123731337314373153731637317373183731937320373213732237323373243732537326373273732837329373303733137332373333733437335373363733737338373393734037341373423734337344373453734637347373483734937350373513735237353373543735537356373573735837359373603736137362373633736437365373663736737368373693737037371373723737337374373753737637377373783737937380373813738237383373843738537386373873738837389373903739137392373933739437395373963739737398373993740037401374023740337404374053740637407374083740937410374113741237413374143741537416374173741837419374203742137422374233742437425374263742737428374293743037431374323743337434374353743637437374383743937440374413744237443374443744537446374473744837449374503745137452374533745437455374563745737458374593746037461374623746337464374653746637467374683746937470374713747237473374743747537476374773747837479374803748137482374833748437485374863748737488374893749037491374923749337494374953749637497374983749937500375013750237503375043750537506375073750837509375103751137512375133751437515375163751737518375193752037521375223752337524375253752637527375283752937530375313753237533375343753537536375373753837539375403754137542375433754437545375463754737548375493755037551375523755337554375553755637557375583755937560375613756237563375643756537566375673756837569375703757137572375733757437575375763757737578375793758037581375823758337584375853758637587375883758937590375913759237593375943759537596375973759837599376003760137602376033760437605376063760737608376093761037611376123761337614376153761637617376183761937620376213762237623376243762537626376273762837629376303763137632376333763437635376363763737638376393764037641376423764337644376453764637647376483764937650376513765237653376543765537656376573765837659376603766137662376633766437665376663766737668376693767037671376723767337674376753767637677376783767937680376813768237683376843768537686376873768837689376903769137692376933769437695376963769737698376993770037701377023770337704377053770637707377083770937710377113771237713377143771537716377173771837719377203772137722377233772437725377263772737728377293773037731377323773337734377353773637737377383773937740377413774237743377443774537746377473774837749377503775137752377533775437755377563775737758377593776037761377623776337764377653776637767377683776937770377713777237773377743777537776377773777837779377803778137782377833778437785377863778737788377893779037791377923779337794377953779637797377983779937800378013780237803378043780537806378073780837809378103781137812378133781437815378163781737818378193782037821378223782337824378253782637827378283782937830378313783237833378343783537836378373783837839378403784137842378433784437845378463784737848378493785037851378523785337854378553785637857378583785937860378613786237863378643786537866378673786837869378703787137872378733787437875378763787737878378793788037881378823788337884378853788637887378883788937890378913789237893378943789537896378973789837899379003790137902379033790437905379063790737908379093791037911379123791337914379153791637917379183791937920379213792237923379243792537926379273792837929379303793137932379333793437935379363793737938379393794037941379423794337944379453794637947379483794937950379513795237953379543795537956379573795837959379603796137962379633796437965379663796737968379693797037971379723797337974379753797637977379783797937980379813798237983379843798537986379873798837989379903799137992379933799437995379963799737998379993800038001380023800338004380053800638007380083800938010380113801238013380143801538016380173801838019380203802138022380233802438025380263802738028380293803038031380323803338034380353803638037380383803938040380413804238043380443804538046380473804838049380503805138052380533805438055380563805738058380593806038061380623806338064380653806638067380683806938070380713807238073380743807538076380773807838079380803808138082380833808438085380863808738088380893809038091380923809338094380953809638097380983809938100381013810238103381043810538106381073810838109381103811138112381133811438115381163811738118381193812038121381223812338124381253812638127381283812938130381313813238133381343813538136381373813838139381403814138142381433814438145381463814738148381493815038151381523815338154381553815638157381583815938160381613816238163381643816538166381673816838169381703817138172381733817438175381763817738178381793818038181381823818338184381853818638187381883818938190381913819238193381943819538196381973819838199382003820138202382033820438205382063820738208382093821038211382123821338214382153821638217382183821938220382213822238223382243822538226382273822838229382303823138232382333823438235382363823738238382393824038241382423824338244382453824638247382483824938250382513825238253382543825538256382573825838259382603826138262382633826438265382663826738268382693827038271382723827338274382753827638277382783827938280382813828238283382843828538286382873828838289382903829138292382933829438295382963829738298382993830038301383023830338304383053830638307383083830938310383113831238313383143831538316383173831838319383203832138322383233832438325383263832738328383293833038331383323833338334383353833638337383383833938340383413834238343383443834538346383473834838349383503835138352383533835438355383563835738358383593836038361383623836338364383653836638367383683836938370383713837238373383743837538376383773837838379383803838138382383833838438385383863838738388383893839038391383923839338394383953839638397383983839938400384013840238403384043840538406384073840838409384103841138412384133841438415384163841738418384193842038421384223842338424384253842638427384283842938430384313843238433384343843538436384373843838439384403844138442384433844438445384463844738448384493845038451384523845338454384553845638457384583845938460384613846238463384643846538466384673846838469384703847138472384733847438475384763847738478384793848038481384823848338484384853848638487384883848938490384913849238493384943849538496384973849838499385003850138502385033850438505385063850738508385093851038511385123851338514385153851638517385183851938520385213852238523385243852538526385273852838529385303853138532385333853438535385363853738538385393854038541385423854338544385453854638547385483854938550385513855238553385543855538556385573855838559385603856138562385633856438565385663856738568385693857038571385723857338574385753857638577385783857938580385813858238583385843858538586385873858838589385903859138592385933859438595385963859738598385993860038601386023860338604386053860638607386083860938610386113861238613386143861538616386173861838619386203862138622386233862438625386263862738628386293863038631386323863338634386353863638637386383863938640386413864238643386443864538646386473864838649386503865138652386533865438655386563865738658386593866038661386623866338664386653866638667386683866938670386713867238673386743867538676386773867838679386803868138682386833868438685386863868738688386893869038691386923869338694386953869638697386983869938700387013870238703387043870538706387073870838709387103871138712387133871438715387163871738718387193872038721387223872338724387253872638727387283872938730387313873238733387343873538736387373873838739387403874138742387433874438745387463874738748387493875038751387523875338754387553875638757387583875938760387613876238763387643876538766387673876838769387703877138772387733877438775387763877738778387793878038781387823878338784387853878638787387883878938790387913879238793387943879538796387973879838799388003880138802388033880438805388063880738808388093881038811388123881338814388153881638817388183881938820388213882238823388243882538826388273882838829388303883138832388333883438835388363883738838388393884038841388423884338844388453884638847388483884938850388513885238853388543885538856388573885838859388603886138862388633886438865388663886738868388693887038871388723887338874388753887638877388783887938880388813888238883388843888538886388873888838889388903889138892388933889438895388963889738898388993890038901389023890338904389053890638907389083890938910389113891238913389143891538916389173891838919389203892138922389233892438925389263892738928389293893038931389323893338934389353893638937389383893938940389413894238943389443894538946389473894838949389503895138952389533895438955389563895738958389593896038961389623896338964389653896638967389683896938970389713897238973389743897538976389773897838979389803898138982389833898438985389863898738988389893899038991389923899338994389953899638997389983899939000390013900239003390043900539006390073900839009390103901139012390133901439015390163901739018390193902039021390223902339024390253902639027390283902939030390313903239033390343903539036390373903839039390403904139042390433904439045390463904739048390493905039051390523905339054390553905639057390583905939060390613906239063390643906539066390673906839069390703907139072390733907439075390763907739078390793908039081390823908339084390853908639087390883908939090390913909239093390943909539096390973909839099391003910139102391033910439105391063910739108391093911039111391123911339114391153911639117391183911939120391213912239123391243912539126391273912839129391303913139132391333913439135391363913739138391393914039141391423914339144391453914639147391483914939150391513915239153391543915539156391573915839159391603916139162391633916439165391663916739168391693917039171391723917339174391753917639177391783917939180391813918239183391843918539186391873918839189391903919139192391933919439195391963919739198391993920039201392023920339204392053920639207392083920939210392113921239213392143921539216392173921839219392203922139222392233922439225392263922739228392293923039231392323923339234392353923639237392383923939240392413924239243392443924539246392473924839249392503925139252392533925439255392563925739258392593926039261392623926339264392653926639267392683926939270392713927239273392743927539276392773927839279392803928139282392833928439285392863928739288392893929039291392923929339294392953929639297392983929939300393013930239303393043930539306393073930839309393103931139312393133931439315393163931739318393193932039321393223932339324393253932639327393283932939330393313933239333393343933539336393373933839339393403934139342393433934439345393463934739348393493935039351393523935339354393553935639357393583935939360393613936239363393643936539366393673936839369393703937139372393733937439375393763937739378393793938039381393823938339384393853938639387393883938939390393913939239393393943939539396393973939839399394003940139402394033940439405394063940739408394093941039411394123941339414394153941639417394183941939420394213942239423394243942539426394273942839429394303943139432394333943439435394363943739438394393944039441394423944339444394453944639447394483944939450394513945239453394543945539456394573945839459394603946139462394633946439465394663946739468394693947039471394723947339474394753947639477394783947939480394813948239483394843948539486394873948839489394903949139492394933949439495394963949739498394993950039501395023950339504395053950639507395083950939510395113951239513395143951539516395173951839519395203952139522395233952439525395263952739528395293953039531395323953339534395353953639537395383953939540395413954239543395443954539546395473954839549395503955139552395533955439555395563955739558395593956039561395623956339564395653956639567395683956939570395713957239573395743957539576395773957839579395803958139582395833958439585395863958739588395893959039591395923959339594395953959639597395983959939600396013960239603396043960539606396073960839609396103961139612396133961439615396163961739618396193962039621396223962339624396253962639627396283962939630396313963239633396343963539636396373963839639396403964139642396433964439645396463964739648396493965039651396523965339654396553965639657396583965939660396613966239663396643966539666396673966839669396703967139672396733967439675396763967739678396793968039681396823968339684396853968639687396883968939690396913969239693396943969539696396973969839699397003970139702397033970439705397063970739708397093971039711397123971339714397153971639717397183971939720397213972239723397243972539726397273972839729397303973139732397333973439735397363973739738397393974039741397423974339744397453974639747397483974939750397513975239753397543975539756397573975839759397603976139762397633976439765397663976739768397693977039771397723977339774397753977639777397783977939780397813978239783397843978539786397873978839789397903979139792397933979439795397963979739798397993980039801398023980339804398053980639807398083980939810398113981239813398143981539816398173981839819398203982139822398233982439825398263982739828398293983039831398323983339834398353983639837398383983939840398413984239843398443984539846398473984839849398503985139852398533985439855398563985739858398593986039861398623986339864398653986639867398683986939870398713987239873398743987539876398773987839879398803988139882398833988439885398863988739888398893989039891398923989339894398953989639897398983989939900399013990239903399043990539906399073990839909399103991139912399133991439915399163991739918399193992039921399223992339924399253992639927399283992939930399313993239933399343993539936399373993839939399403994139942399433994439945399463994739948399493995039951399523995339954399553995639957399583995939960399613996239963399643996539966399673996839969399703997139972399733997439975399763997739978399793998039981399823998339984399853998639987399883998939990399913999239993399943999539996399973999839999400004000140002400034000440005400064000740008400094001040011400124001340014400154001640017400184001940020400214002240023400244002540026400274002840029400304003140032400334003440035400364003740038400394004040041400424004340044400454004640047400484004940050400514005240053400544005540056400574005840059400604006140062400634006440065400664006740068400694007040071400724007340074400754007640077400784007940080400814008240083400844008540086400874008840089400904009140092400934009440095400964009740098400994010040101401024010340104401054010640107401084010940110401114011240113401144011540116401174011840119401204012140122401234012440125401264012740128401294013040131401324013340134401354013640137401384013940140401414014240143401444014540146401474014840149401504015140152401534015440155401564015740158401594016040161401624016340164401654016640167401684016940170401714017240173401744017540176401774017840179401804018140182401834018440185401864018740188401894019040191401924019340194401954019640197401984019940200402014020240203402044020540206402074020840209402104021140212402134021440215402164021740218402194022040221402224022340224402254022640227402284022940230402314023240233402344023540236402374023840239402404024140242402434024440245402464024740248402494025040251402524025340254402554025640257402584025940260402614026240263402644026540266402674026840269402704027140272402734027440275402764027740278402794028040281402824028340284402854028640287402884028940290402914029240293402944029540296402974029840299403004030140302403034030440305403064030740308403094031040311403124031340314403154031640317403184031940320403214032240323403244032540326403274032840329403304033140332403334033440335403364033740338403394034040341403424034340344403454034640347403484034940350403514035240353403544035540356403574035840359403604036140362403634036440365403664036740368403694037040371403724037340374403754037640377403784037940380403814038240383403844038540386403874038840389403904039140392403934039440395403964039740398403994040040401404024040340404404054040640407404084040940410404114041240413404144041540416404174041840419404204042140422404234042440425404264042740428404294043040431404324043340434404354043640437404384043940440404414044240443404444044540446404474044840449404504045140452404534045440455404564045740458404594046040461404624046340464404654046640467404684046940470404714047240473404744047540476404774047840479404804048140482404834048440485404864048740488404894049040491404924049340494404954049640497404984049940500405014050240503405044050540506405074050840509405104051140512405134051440515405164051740518405194052040521405224052340524405254052640527405284052940530405314053240533405344053540536405374053840539405404054140542405434054440545405464054740548405494055040551405524055340554405554055640557405584055940560405614056240563405644056540566405674056840569405704057140572405734057440575405764057740578405794058040581405824058340584405854058640587405884058940590405914059240593405944059540596405974059840599406004060140602406034060440605406064060740608406094061040611406124061340614406154061640617406184061940620406214062240623406244062540626406274062840629406304063140632406334063440635406364063740638406394064040641406424064340644406454064640647406484064940650406514065240653406544065540656406574065840659406604066140662406634066440665406664066740668406694067040671406724067340674406754067640677406784067940680406814068240683406844068540686406874068840689406904069140692406934069440695406964069740698406994070040701407024070340704407054070640707407084070940710407114071240713407144071540716407174071840719407204072140722407234072440725407264072740728407294073040731407324073340734407354073640737407384073940740407414074240743407444074540746407474074840749407504075140752407534075440755407564075740758407594076040761407624076340764407654076640767407684076940770407714077240773407744077540776407774077840779407804078140782407834078440785407864078740788407894079040791407924079340794407954079640797407984079940800408014080240803408044080540806408074080840809408104081140812408134081440815408164081740818408194082040821408224082340824408254082640827408284082940830408314083240833408344083540836408374083840839408404084140842408434084440845408464084740848408494085040851408524085340854408554085640857408584085940860408614086240863408644086540866408674086840869408704087140872408734087440875408764087740878408794088040881408824088340884408854088640887408884088940890408914089240893408944089540896408974089840899409004090140902409034090440905409064090740908409094091040911409124091340914409154091640917409184091940920409214092240923409244092540926409274092840929409304093140932409334093440935409364093740938409394094040941409424094340944409454094640947409484094940950409514095240953409544095540956409574095840959409604096140962409634096440965409664096740968409694097040971409724097340974409754097640977409784097940980409814098240983409844098540986409874098840989409904099140992409934099440995409964099740998409994100041001410024100341004410054100641007410084100941010410114101241013410144101541016410174101841019410204102141022410234102441025410264102741028410294103041031410324103341034410354103641037410384103941040410414104241043410444104541046410474104841049410504105141052410534105441055410564105741058410594106041061410624106341064410654106641067410684106941070410714107241073410744107541076410774107841079410804108141082410834108441085410864108741088410894109041091410924109341094410954109641097410984109941100411014110241103411044110541106411074110841109411104111141112411134111441115411164111741118411194112041121411224112341124411254112641127411284112941130411314113241133411344113541136411374113841139411404114141142411434114441145411464114741148411494115041151411524115341154411554115641157411584115941160411614116241163411644116541166411674116841169411704117141172411734117441175411764117741178411794118041181411824118341184411854118641187411884118941190411914119241193411944119541196411974119841199412004120141202412034120441205412064120741208412094121041211412124121341214412154121641217412184121941220412214122241223412244122541226412274122841229412304123141232412334123441235412364123741238412394124041241412424124341244412454124641247412484124941250412514125241253412544125541256412574125841259412604126141262412634126441265412664126741268412694127041271412724127341274412754127641277412784127941280412814128241283412844128541286412874128841289412904129141292412934129441295412964129741298412994130041301413024130341304413054130641307413084130941310413114131241313413144131541316413174131841319413204132141322413234132441325413264132741328413294133041331413324133341334413354133641337413384133941340413414134241343413444134541346413474134841349413504135141352413534135441355413564135741358413594136041361413624136341364413654136641367413684136941370413714137241373413744137541376413774137841379413804138141382413834138441385413864138741388413894139041391413924139341394413954139641397413984139941400414014140241403414044140541406414074140841409414104141141412414134141441415414164141741418414194142041421414224142341424414254142641427414284142941430414314143241433414344143541436414374143841439414404144141442414434144441445414464144741448414494145041451414524145341454414554145641457414584145941460414614146241463414644146541466414674146841469414704147141472414734147441475414764147741478414794148041481414824148341484414854148641487414884148941490414914149241493414944149541496414974149841499415004150141502415034150441505415064150741508415094151041511415124151341514415154151641517415184151941520415214152241523415244152541526415274152841529415304153141532415334153441535415364153741538415394154041541415424154341544415454154641547415484154941550415514155241553415544155541556415574155841559415604156141562415634156441565415664156741568415694157041571415724157341574415754157641577415784157941580415814158241583415844158541586415874158841589415904159141592415934159441595415964159741598415994160041601416024160341604416054160641607416084160941610416114161241613416144161541616416174161841619416204162141622416234162441625416264162741628416294163041631416324163341634416354163641637416384163941640416414164241643416444164541646416474164841649416504165141652416534165441655416564165741658416594166041661416624166341664416654166641667416684166941670416714167241673416744167541676416774167841679416804168141682416834168441685416864168741688416894169041691416924169341694416954169641697416984169941700417014170241703417044170541706417074170841709417104171141712417134171441715417164171741718417194172041721417224172341724417254172641727417284172941730417314173241733417344173541736417374173841739417404174141742417434174441745417464174741748417494175041751417524175341754417554175641757417584175941760417614176241763417644176541766417674176841769417704177141772417734177441775417764177741778417794178041781417824178341784417854178641787417884178941790417914179241793417944179541796417974179841799418004180141802418034180441805418064180741808418094181041811418124181341814418154181641817418184181941820418214182241823418244182541826418274182841829418304183141832418334183441835418364183741838418394184041841418424184341844418454184641847418484184941850418514185241853418544185541856418574185841859418604186141862418634186441865418664186741868418694187041871418724187341874418754187641877418784187941880418814188241883418844188541886418874188841889418904189141892418934189441895418964189741898418994190041901419024190341904419054190641907419084190941910419114191241913419144191541916419174191841919419204192141922419234192441925419264192741928419294193041931419324193341934419354193641937419384193941940419414194241943419444194541946419474194841949419504195141952419534195441955419564195741958419594196041961419624196341964419654196641967419684196941970419714197241973419744197541976419774197841979419804198141982419834198441985419864198741988419894199041991419924199341994419954199641997419984199942000420014200242003420044200542006420074200842009420104201142012420134201442015420164201742018420194202042021420224202342024420254202642027420284202942030420314203242033420344203542036420374203842039420404204142042420434204442045420464204742048420494205042051420524205342054420554205642057420584205942060420614206242063420644206542066420674206842069420704207142072420734207442075420764207742078420794208042081420824208342084420854208642087420884208942090420914209242093420944209542096420974209842099421004210142102421034210442105421064210742108421094211042111421124211342114421154211642117421184211942120421214212242123421244212542126421274212842129421304213142132421334213442135421364213742138421394214042141421424214342144421454214642147421484214942150421514215242153421544215542156421574215842159421604216142162421634216442165421664216742168421694217042171421724217342174421754217642177421784217942180421814218242183421844218542186421874218842189421904219142192421934219442195421964219742198421994220042201422024220342204422054220642207422084220942210422114221242213422144221542216422174221842219422204222142222422234222442225422264222742228422294223042231422324223342234422354223642237422384223942240422414224242243422444224542246422474224842249422504225142252422534225442255422564225742258422594226042261422624226342264422654226642267422684226942270422714227242273422744227542276422774227842279422804228142282422834228442285422864228742288422894229042291422924229342294422954229642297422984229942300423014230242303423044230542306423074230842309423104231142312423134231442315423164231742318423194232042321423224232342324423254232642327423284232942330423314233242333423344233542336423374233842339423404234142342423434234442345423464234742348423494235042351423524235342354423554235642357423584235942360423614236242363423644236542366423674236842369423704237142372423734237442375423764237742378423794238042381423824238342384423854238642387423884238942390423914239242393423944239542396423974239842399424004240142402424034240442405424064240742408424094241042411424124241342414424154241642417424184241942420424214242242423424244242542426424274242842429424304243142432424334243442435424364243742438424394244042441424424244342444424454244642447424484244942450424514245242453424544245542456424574245842459424604246142462424634246442465424664246742468424694247042471424724247342474424754247642477424784247942480424814248242483424844248542486424874248842489424904249142492424934249442495424964249742498424994250042501425024250342504425054250642507425084250942510425114251242513425144251542516425174251842519425204252142522425234252442525425264252742528425294253042531425324253342534425354253642537425384253942540425414254242543425444254542546425474254842549425504255142552425534255442555425564255742558425594256042561425624256342564425654256642567425684256942570425714257242573425744257542576425774257842579425804258142582425834258442585425864258742588425894259042591425924259342594425954259642597425984259942600426014260242603426044260542606426074260842609426104261142612426134261442615426164261742618426194262042621426224262342624426254262642627426284262942630426314263242633426344263542636426374263842639426404264142642426434264442645426464264742648426494265042651426524265342654426554265642657426584265942660426614266242663426644266542666426674266842669426704267142672426734267442675426764267742678426794268042681426824268342684426854268642687426884268942690426914269242693426944269542696426974269842699427004270142702427034270442705427064270742708427094271042711427124271342714427154271642717427184271942720427214272242723427244272542726427274272842729427304273142732427334273442735427364273742738427394274042741427424274342744427454274642747427484274942750427514275242753427544275542756427574275842759427604276142762427634276442765427664276742768427694277042771427724277342774427754277642777427784277942780427814278242783427844278542786427874278842789427904279142792427934279442795427964279742798427994280042801428024280342804428054280642807428084280942810428114281242813428144281542816428174281842819428204282142822428234282442825428264282742828428294283042831428324283342834428354283642837428384283942840428414284242843428444284542846428474284842849428504285142852428534285442855428564285742858428594286042861428624286342864428654286642867428684286942870428714287242873428744287542876428774287842879428804288142882428834288442885428864288742888428894289042891428924289342894428954289642897428984289942900429014290242903429044290542906429074290842909429104291142912429134291442915429164291742918429194292042921429224292342924429254292642927429284292942930429314293242933429344293542936429374293842939429404294142942429434294442945429464294742948429494295042951429524295342954429554295642957429584295942960429614296242963429644296542966429674296842969429704297142972429734297442975429764297742978429794298042981429824298342984429854298642987429884298942990429914299242993429944299542996429974299842999430004300143002430034300443005430064300743008430094301043011430124301343014430154301643017430184301943020430214302243023430244302543026430274302843029430304303143032430334303443035430364303743038430394304043041430424304343044430454304643047430484304943050430514305243053430544305543056430574305843059430604306143062430634306443065430664306743068430694307043071430724307343074430754307643077430784307943080430814308243083430844308543086430874308843089430904309143092430934309443095430964309743098430994310043101431024310343104431054310643107431084310943110431114311243113431144311543116431174311843119431204312143122431234312443125431264312743128431294313043131431324313343134431354313643137431384313943140431414314243143431444314543146431474314843149431504315143152431534315443155431564315743158431594316043161431624316343164431654316643167431684316943170431714317243173431744317543176431774317843179431804318143182431834318443185431864318743188431894319043191431924319343194431954319643197431984319943200432014320243203432044320543206432074320843209432104321143212432134321443215432164321743218432194322043221432224322343224432254322643227432284322943230432314323243233432344323543236432374323843239432404324143242432434324443245432464324743248432494325043251432524325343254432554325643257432584325943260432614326243263432644326543266432674326843269432704327143272432734327443275432764327743278432794328043281432824328343284432854328643287432884328943290432914329243293432944329543296432974329843299433004330143302433034330443305433064330743308433094331043311433124331343314433154331643317433184331943320433214332243323433244332543326433274332843329433304333143332433334333443335433364333743338433394334043341433424334343344433454334643347433484334943350433514335243353433544335543356433574335843359433604336143362433634336443365433664336743368433694337043371433724337343374433754337643377433784337943380433814338243383433844338543386433874338843389433904339143392433934339443395433964339743398433994340043401434024340343404434054340643407434084340943410434114341243413434144341543416434174341843419434204342143422434234342443425434264342743428434294343043431434324343343434434354343643437434384343943440434414344243443434444344543446434474344843449434504345143452434534345443455434564345743458434594346043461434624346343464434654346643467434684346943470434714347243473434744347543476434774347843479434804348143482434834348443485434864348743488434894349043491434924349343494434954349643497434984349943500435014350243503435044350543506435074350843509435104351143512435134351443515435164351743518435194352043521435224352343524435254352643527435284352943530435314353243533435344353543536435374353843539435404354143542435434354443545435464354743548435494355043551435524355343554435554355643557435584355943560435614356243563435644356543566435674356843569435704357143572435734357443575435764357743578435794358043581435824358343584435854358643587435884358943590435914359243593435944359543596435974359843599436004360143602436034360443605436064360743608436094361043611436124361343614436154361643617436184361943620436214362243623436244362543626436274362843629436304363143632436334363443635436364363743638436394364043641436424364343644436454364643647436484364943650436514365243653436544365543656436574365843659436604366143662436634366443665436664366743668436694367043671436724367343674436754367643677436784367943680436814368243683436844368543686436874368843689436904369143692436934369443695436964369743698436994370043701437024370343704437054370643707437084370943710437114371243713437144371543716437174371843719437204372143722437234372443725437264372743728437294373043731437324373343734437354373643737437384373943740437414374243743437444374543746437474374843749437504375143752437534375443755437564375743758437594376043761437624376343764437654376643767437684376943770437714377243773437744377543776437774377843779437804378143782437834378443785437864378743788437894379043791437924379343794437954379643797437984379943800438014380243803438044380543806438074380843809438104381143812438134381443815438164381743818438194382043821438224382343824438254382643827438284382943830438314383243833438344383543836438374383843839438404384143842438434384443845438464384743848438494385043851438524385343854438554385643857438584385943860438614386243863438644386543866438674386843869438704387143872438734387443875438764387743878438794388043881438824388343884438854388643887438884388943890438914389243893438944389543896438974389843899439004390143902439034390443905439064390743908439094391043911439124391343914439154391643917439184391943920439214392243923439244392543926439274392843929439304393143932439334393443935439364393743938439394394043941439424394343944439454394643947439484394943950439514395243953439544395543956439574395843959439604396143962439634396443965439664396743968439694397043971439724397343974439754397643977439784397943980439814398243983439844398543986439874398843989439904399143992439934399443995439964399743998439994400044001440024400344004440054400644007440084400944010440114401244013440144401544016440174401844019440204402144022440234402444025440264402744028440294403044031440324403344034440354403644037440384403944040440414404244043440444404544046440474404844049440504405144052440534405444055440564405744058440594406044061440624406344064440654406644067440684406944070440714407244073440744407544076440774407844079440804408144082440834408444085440864408744088440894409044091440924409344094440954409644097440984409944100441014410244103441044410544106441074410844109441104411144112441134411444115441164411744118441194412044121441224412344124441254412644127441284412944130441314413244133441344413544136441374413844139441404414144142441434414444145441464414744148441494415044151441524415344154441554415644157441584415944160441614416244163441644416544166441674416844169441704417144172441734417444175441764417744178441794418044181441824418344184441854418644187441884418944190441914419244193441944419544196441974419844199442004420144202442034420444205442064420744208442094421044211442124421344214442154421644217442184421944220442214422244223442244422544226442274422844229442304423144232442334423444235442364423744238442394424044241442424424344244442454424644247442484424944250442514425244253442544425544256442574425844259442604426144262442634426444265442664426744268442694427044271442724427344274442754427644277442784427944280442814428244283442844428544286442874428844289442904429144292442934429444295442964429744298442994430044301443024430344304443054430644307443084430944310443114431244313443144431544316443174431844319443204432144322443234432444325443264432744328443294433044331443324433344334443354433644337443384433944340443414434244343443444434544346443474434844349443504435144352443534435444355443564435744358443594436044361443624436344364443654436644367443684436944370443714437244373443744437544376443774437844379443804438144382443834438444385443864438744388443894439044391443924439344394443954439644397443984439944400444014440244403444044440544406444074440844409444104441144412444134441444415444164441744418444194442044421444224442344424444254442644427444284442944430444314443244433444344443544436444374443844439444404444144442444434444444445444464444744448444494445044451444524445344454444554445644457444584445944460444614446244463444644446544466444674446844469444704447144472444734447444475444764447744478444794448044481444824448344484444854448644487444884448944490444914449244493444944449544496444974449844499445004450144502445034450444505445064450744508445094451044511445124451344514445154451644517445184451944520445214452244523445244452544526445274452844529445304453144532445334453444535445364453744538445394454044541445424454344544445454454644547445484454944550445514455244553445544455544556445574455844559445604456144562445634456444565445664456744568445694457044571445724457344574445754457644577445784457944580445814458244583445844458544586445874458844589445904459144592445934459444595445964459744598445994460044601446024460344604446054460644607446084460944610446114461244613446144461544616446174461844619446204462144622446234462444625446264462744628446294463044631446324463344634446354463644637446384463944640446414464244643446444464544646446474464844649446504465144652446534465444655446564465744658446594466044661446624466344664446654466644667446684466944670446714467244673446744467544676446774467844679446804468144682446834468444685446864468744688446894469044691446924469344694446954469644697446984469944700447014470244703447044470544706447074470844709447104471144712447134471444715447164471744718447194472044721447224472344724447254472644727447284472944730447314473244733447344473544736447374473844739447404474144742447434474444745447464474744748447494475044751447524475344754447554475644757447584475944760447614476244763447644476544766447674476844769447704477144772447734477444775447764477744778447794478044781447824478344784447854478644787447884478944790447914479244793447944479544796447974479844799448004480144802448034480444805448064480744808448094481044811448124481344814448154481644817448184481944820448214482244823448244482544826448274482844829448304483144832448334483444835448364483744838448394484044841448424484344844448454484644847448484484944850448514485244853448544485544856448574485844859448604486144862448634486444865448664486744868448694487044871448724487344874448754487644877448784487944880448814488244883448844488544886448874488844889448904489144892448934489444895448964489744898448994490044901449024490344904449054490644907449084490944910449114491244913449144491544916449174491844919449204492144922449234492444925449264492744928449294493044931449324493344934449354493644937449384493944940449414494244943449444494544946449474494844949449504495144952449534495444955449564495744958449594496044961449624496344964449654496644967449684496944970449714497244973449744497544976449774497844979449804498144982449834498444985449864498744988449894499044991449924499344994449954499644997449984499945000450014500245003450044500545006450074500845009450104501145012450134501445015450164501745018450194502045021450224502345024450254502645027450284502945030450314503245033450344503545036450374503845039450404504145042450434504445045450464504745048450494505045051450524505345054450554505645057450584505945060450614506245063450644506545066450674506845069450704507145072450734507445075450764507745078450794508045081450824508345084450854508645087450884508945090450914509245093450944509545096450974509845099451004510145102451034510445105451064510745108451094511045111451124511345114451154511645117451184511945120451214512245123451244512545126451274512845129451304513145132451334513445135451364513745138451394514045141451424514345144451454514645147451484514945150451514515245153451544515545156451574515845159451604516145162451634516445165451664516745168451694517045171451724517345174451754517645177451784517945180451814518245183451844518545186451874518845189451904519145192451934519445195451964519745198451994520045201452024520345204452054520645207452084520945210452114521245213452144521545216452174521845219452204522145222452234522445225452264522745228452294523045231452324523345234452354523645237452384523945240452414524245243452444524545246452474524845249452504525145252452534525445255452564525745258452594526045261452624526345264452654526645267452684526945270452714527245273452744527545276452774527845279452804528145282452834528445285452864528745288452894529045291452924529345294452954529645297452984529945300453014530245303453044530545306453074530845309453104531145312453134531445315453164531745318453194532045321453224532345324453254532645327453284532945330453314533245333453344533545336453374533845339453404534145342453434534445345453464534745348453494535045351453524535345354453554535645357453584535945360453614536245363453644536545366453674536845369453704537145372453734537445375453764537745378453794538045381453824538345384453854538645387453884538945390453914539245393453944539545396453974539845399454004540145402454034540445405454064540745408454094541045411454124541345414454154541645417454184541945420454214542245423454244542545426454274542845429454304543145432454334543445435454364543745438454394544045441454424544345444454454544645447454484544945450454514545245453454544545545456454574545845459454604546145462454634546445465454664546745468454694547045471454724547345474454754547645477454784547945480454814548245483454844548545486454874548845489454904549145492454934549445495454964549745498454994550045501455024550345504455054550645507455084550945510455114551245513455144551545516455174551845519455204552145522455234552445525455264552745528455294553045531455324553345534455354553645537455384553945540455414554245543455444554545546455474554845549455504555145552455534555445555455564555745558455594556045561455624556345564455654556645567455684556945570455714557245573455744557545576455774557845579455804558145582455834558445585455864558745588455894559045591455924559345594455954559645597455984559945600456014560245603456044560545606456074560845609456104561145612456134561445615456164561745618456194562045621456224562345624456254562645627456284562945630456314563245633456344563545636456374563845639456404564145642456434564445645456464564745648456494565045651456524565345654456554565645657456584565945660456614566245663456644566545666456674566845669456704567145672456734567445675456764567745678456794568045681456824568345684456854568645687456884568945690456914569245693456944569545696456974569845699457004570145702457034570445705457064570745708457094571045711457124571345714457154571645717457184571945720457214572245723457244572545726457274572845729457304573145732457334573445735457364573745738457394574045741457424574345744457454574645747457484574945750457514575245753457544575545756457574575845759457604576145762457634576445765457664576745768457694577045771457724577345774457754577645777457784577945780457814578245783457844578545786457874578845789457904579145792457934579445795457964579745798457994580045801458024580345804458054580645807458084580945810458114581245813458144581545816458174581845819458204582145822458234582445825458264582745828458294583045831458324583345834458354583645837458384583945840458414584245843458444584545846458474584845849458504585145852458534585445855458564585745858458594586045861458624586345864458654586645867458684586945870458714587245873458744587545876458774587845879458804588145882458834588445885458864588745888458894589045891458924589345894458954589645897458984589945900459014590245903459044590545906459074590845909459104591145912459134591445915459164591745918459194592045921459224592345924459254592645927459284592945930459314593245933459344593545936459374593845939459404594145942459434594445945459464594745948459494595045951459524595345954459554595645957459584595945960459614596245963459644596545966459674596845969459704597145972459734597445975459764597745978459794598045981459824598345984459854598645987459884598945990459914599245993459944599545996459974599845999460004600146002460034600446005460064600746008460094601046011460124601346014460154601646017460184601946020460214602246023460244602546026460274602846029460304603146032460334603446035460364603746038460394604046041460424604346044460454604646047460484604946050460514605246053460544605546056460574605846059460604606146062460634606446065460664606746068460694607046071460724607346074460754607646077460784607946080460814608246083460844608546086460874608846089460904609146092460934609446095460964609746098460994610046101461024610346104461054610646107461084610946110461114611246113461144611546116461174611846119461204612146122461234612446125461264612746128461294613046131461324613346134461354613646137461384613946140461414614246143461444614546146461474614846149461504615146152461534615446155461564615746158461594616046161461624616346164461654616646167461684616946170461714617246173461744617546176461774617846179461804618146182461834618446185461864618746188461894619046191461924619346194461954619646197461984619946200462014620246203462044620546206462074620846209462104621146212462134621446215462164621746218462194622046221462224622346224462254622646227462284622946230462314623246233462344623546236462374623846239462404624146242462434624446245462464624746248462494625046251462524625346254462554625646257462584625946260462614626246263462644626546266462674626846269462704627146272462734627446275462764627746278462794628046281462824628346284462854628646287462884628946290462914629246293462944629546296462974629846299463004630146302463034630446305463064630746308463094631046311463124631346314463154631646317463184631946320463214632246323463244632546326463274632846329463304633146332463334633446335463364633746338463394634046341463424634346344463454634646347463484634946350463514635246353463544635546356463574635846359463604636146362463634636446365463664636746368463694637046371463724637346374463754637646377463784637946380463814638246383463844638546386463874638846389463904639146392463934639446395463964639746398463994640046401464024640346404464054640646407464084640946410464114641246413464144641546416464174641846419464204642146422464234642446425464264642746428464294643046431464324643346434464354643646437464384643946440464414644246443464444644546446464474644846449464504645146452464534645446455464564645746458464594646046461464624646346464464654646646467464684646946470464714647246473464744647546476464774647846479464804648146482464834648446485464864648746488464894649046491464924649346494464954649646497464984649946500465014650246503465044650546506465074650846509465104651146512465134651446515465164651746518465194652046521465224652346524465254652646527465284652946530465314653246533465344653546536465374653846539465404654146542465434654446545465464654746548465494655046551465524655346554465554655646557465584655946560465614656246563465644656546566465674656846569465704657146572465734657446575465764657746578465794658046581465824658346584465854658646587465884658946590465914659246593465944659546596465974659846599466004660146602466034660446605466064660746608466094661046611466124661346614466154661646617466184661946620466214662246623466244662546626466274662846629466304663146632466334663446635466364663746638466394664046641466424664346644466454664646647466484664946650466514665246653466544665546656466574665846659466604666146662466634666446665466664666746668466694667046671466724667346674466754667646677466784667946680466814668246683466844668546686466874668846689466904669146692466934669446695466964669746698466994670046701467024670346704467054670646707467084670946710467114671246713467144671546716467174671846719467204672146722467234672446725467264672746728467294673046731467324673346734467354673646737467384673946740467414674246743467444674546746467474674846749467504675146752467534675446755467564675746758467594676046761467624676346764467654676646767467684676946770467714677246773467744677546776467774677846779467804678146782467834678446785467864678746788467894679046791467924679346794467954679646797467984679946800468014680246803468044680546806468074680846809468104681146812468134681446815468164681746818468194682046821468224682346824468254682646827468284682946830468314683246833468344683546836468374683846839468404684146842468434684446845468464684746848468494685046851468524685346854468554685646857468584685946860468614686246863468644686546866468674686846869468704687146872468734687446875468764687746878468794688046881468824688346884468854688646887468884688946890468914689246893468944689546896468974689846899469004690146902469034690446905469064690746908469094691046911469124691346914469154691646917469184691946920469214692246923469244692546926469274692846929469304693146932469334693446935469364693746938469394694046941469424694346944469454694646947469484694946950469514695246953469544695546956469574695846959469604696146962469634696446965469664696746968469694697046971469724697346974469754697646977469784697946980469814698246983469844698546986469874698846989469904699146992469934699446995469964699746998469994700047001470024700347004470054700647007470084700947010470114701247013470144701547016470174701847019470204702147022470234702447025470264702747028470294703047031470324703347034470354703647037470384703947040470414704247043470444704547046470474704847049470504705147052470534705447055470564705747058470594706047061470624706347064470654706647067470684706947070470714707247073470744707547076470774707847079470804708147082470834708447085470864708747088470894709047091470924709347094470954709647097470984709947100471014710247103471044710547106471074710847109471104711147112471134711447115471164711747118471194712047121471224712347124471254712647127471284712947130471314713247133471344713547136471374713847139471404714147142471434714447145471464714747148471494715047151471524715347154471554715647157471584715947160471614716247163471644716547166471674716847169471704717147172471734717447175471764717747178471794718047181471824718347184471854718647187471884718947190471914719247193471944719547196471974719847199472004720147202472034720447205472064720747208472094721047211472124721347214472154721647217472184721947220472214722247223472244722547226472274722847229472304723147232472334723447235472364723747238472394724047241472424724347244472454724647247472484724947250472514725247253472544725547256472574725847259472604726147262472634726447265472664726747268472694727047271472724727347274472754727647277472784727947280472814728247283472844728547286472874728847289472904729147292472934729447295472964729747298472994730047301473024730347304473054730647307473084730947310473114731247313473144731547316473174731847319473204732147322473234732447325473264732747328473294733047331473324733347334473354733647337473384733947340473414734247343473444734547346473474734847349473504735147352473534735447355473564735747358473594736047361473624736347364473654736647367473684736947370473714737247373473744737547376473774737847379473804738147382473834738447385473864738747388473894739047391473924739347394473954739647397473984739947400474014740247403474044740547406474074740847409474104741147412474134741447415474164741747418474194742047421474224742347424474254742647427474284742947430474314743247433474344743547436474374743847439474404744147442474434744447445474464744747448474494745047451474524745347454474554745647457474584745947460474614746247463474644746547466474674746847469474704747147472474734747447475474764747747478474794748047481474824748347484474854748647487474884748947490474914749247493474944749547496474974749847499475004750147502475034750447505475064750747508475094751047511475124751347514475154751647517475184751947520475214752247523475244752547526475274752847529475304753147532475334753447535475364753747538475394754047541475424754347544475454754647547475484754947550475514755247553475544755547556475574755847559475604756147562475634756447565475664756747568475694757047571475724757347574475754757647577475784757947580475814758247583475844758547586475874758847589475904759147592475934759447595475964759747598475994760047601476024760347604476054760647607476084760947610476114761247613476144761547616476174761847619476204762147622476234762447625476264762747628476294763047631476324763347634476354763647637476384763947640476414764247643476444764547646476474764847649476504765147652476534765447655476564765747658476594766047661476624766347664476654766647667476684766947670476714767247673476744767547676476774767847679476804768147682476834768447685476864768747688476894769047691476924769347694476954769647697476984769947700477014770247703477044770547706477074770847709477104771147712477134771447715477164771747718477194772047721477224772347724477254772647727477284772947730477314773247733477344773547736477374773847739477404774147742477434774447745477464774747748477494775047751477524775347754477554775647757477584775947760477614776247763477644776547766477674776847769477704777147772477734777447775477764777747778477794778047781477824778347784477854778647787477884778947790477914779247793477944779547796477974779847799478004780147802478034780447805478064780747808478094781047811478124781347814478154781647817478184781947820478214782247823478244782547826478274782847829478304783147832478334783447835478364783747838478394784047841478424784347844478454784647847478484784947850478514785247853478544785547856478574785847859478604786147862478634786447865478664786747868478694787047871478724787347874478754787647877478784787947880478814788247883478844788547886478874788847889478904789147892478934789447895478964789747898478994790047901479024790347904479054790647907479084790947910479114791247913479144791547916479174791847919479204792147922479234792447925479264792747928479294793047931479324793347934479354793647937479384793947940479414794247943479444794547946479474794847949479504795147952479534795447955479564795747958479594796047961479624796347964479654796647967479684796947970479714797247973479744797547976479774797847979479804798147982479834798447985479864798747988479894799047991479924799347994479954799647997479984799948000480014800248003480044800548006480074800848009480104801148012480134801448015480164801748018480194802048021480224802348024480254802648027480284802948030480314803248033480344803548036480374803848039480404804148042480434804448045480464804748048480494805048051480524805348054480554805648057480584805948060480614806248063480644806548066480674806848069480704807148072480734807448075480764807748078480794808048081480824808348084480854808648087480884808948090480914809248093480944809548096480974809848099481004810148102481034810448105481064810748108481094811048111481124811348114481154811648117481184811948120481214812248123481244812548126481274812848129481304813148132481334813448135481364813748138481394814048141481424814348144481454814648147481484814948150481514815248153481544815548156481574815848159481604816148162481634816448165481664816748168481694817048171481724817348174481754817648177481784817948180481814818248183481844818548186481874818848189481904819148192481934819448195481964819748198481994820048201482024820348204482054820648207482084820948210482114821248213482144821548216482174821848219482204822148222482234822448225482264822748228482294823048231482324823348234482354823648237482384823948240482414824248243482444824548246482474824848249482504825148252482534825448255482564825748258482594826048261482624826348264482654826648267482684826948270482714827248273482744827548276482774827848279482804828148282482834828448285482864828748288482894829048291482924829348294482954829648297482984829948300483014830248303483044830548306483074830848309483104831148312483134831448315483164831748318483194832048321483224832348324483254832648327483284832948330483314833248333483344833548336483374833848339483404834148342483434834448345483464834748348483494835048351483524835348354483554835648357483584835948360483614836248363483644836548366483674836848369483704837148372483734837448375483764837748378483794838048381483824838348384483854838648387483884838948390483914839248393483944839548396483974839848399484004840148402484034840448405484064840748408484094841048411484124841348414484154841648417484184841948420484214842248423484244842548426484274842848429484304843148432484334843448435484364843748438484394844048441484424844348444484454844648447484484844948450484514845248453484544845548456484574845848459484604846148462484634846448465484664846748468484694847048471484724847348474484754847648477484784847948480484814848248483484844848548486484874848848489484904849148492484934849448495484964849748498484994850048501485024850348504485054850648507485084850948510485114851248513485144851548516485174851848519485204852148522485234852448525485264852748528485294853048531485324853348534485354853648537485384853948540485414854248543485444854548546485474854848549485504855148552485534855448555485564855748558485594856048561485624856348564485654856648567485684856948570485714857248573485744857548576485774857848579485804858148582485834858448585485864858748588485894859048591485924859348594485954859648597485984859948600486014860248603486044860548606486074860848609486104861148612486134861448615486164861748618486194862048621486224862348624486254862648627486284862948630486314863248633486344863548636486374863848639486404864148642486434864448645486464864748648486494865048651486524865348654486554865648657486584865948660486614866248663486644866548666486674866848669486704867148672486734867448675486764867748678486794868048681486824868348684486854868648687486884868948690486914869248693486944869548696486974869848699487004870148702487034870448705487064870748708487094871048711487124871348714487154871648717487184871948720487214872248723487244872548726487274872848729487304873148732487334873448735487364873748738487394874048741487424874348744487454874648747487484874948750487514875248753487544875548756487574875848759487604876148762487634876448765487664876748768487694877048771487724877348774487754877648777487784877948780487814878248783487844878548786487874878848789487904879148792487934879448795487964879748798487994880048801488024880348804488054880648807488084880948810488114881248813488144881548816488174881848819488204882148822488234882448825488264882748828488294883048831488324883348834488354883648837488384883948840488414884248843488444884548846488474884848849488504885148852488534885448855488564885748858488594886048861488624886348864488654886648867488684886948870488714887248873488744887548876488774887848879488804888148882488834888448885488864888748888488894889048891488924889348894488954889648897488984889948900489014890248903489044890548906489074890848909489104891148912489134891448915489164891748918489194892048921489224892348924489254892648927489284892948930489314893248933489344893548936489374893848939489404894148942489434894448945489464894748948489494895048951489524895348954489554895648957489584895948960489614896248963489644896548966489674896848969489704897148972489734897448975489764897748978489794898048981489824898348984489854898648987489884898948990489914899248993489944899548996489974899848999490004900149002490034900449005490064900749008490094901049011490124901349014490154901649017490184901949020490214902249023490244902549026490274902849029490304903149032490334903449035490364903749038490394904049041490424904349044490454904649047490484904949050490514905249053490544905549056490574905849059490604906149062490634906449065490664906749068490694907049071490724907349074490754907649077490784907949080490814908249083490844908549086490874908849089490904909149092490934909449095490964909749098490994910049101491024910349104491054910649107491084910949110491114911249113491144911549116491174911849119491204912149122491234912449125491264912749128491294913049131491324913349134491354913649137491384913949140491414914249143491444914549146491474914849149491504915149152491534915449155491564915749158491594916049161491624916349164491654916649167491684916949170491714917249173491744917549176491774917849179491804918149182491834918449185491864918749188491894919049191491924919349194491954919649197491984919949200492014920249203492044920549206492074920849209492104921149212492134921449215492164921749218492194922049221492224922349224492254922649227492284922949230492314923249233492344923549236492374923849239492404924149242492434924449245492464924749248492494925049251492524925349254492554925649257492584925949260492614926249263492644926549266492674926849269492704927149272492734927449275492764927749278492794928049281492824928349284492854928649287492884928949290492914929249293492944929549296492974929849299493004930149302493034930449305493064930749308493094931049311493124931349314493154931649317493184931949320493214932249323493244932549326493274932849329493304933149332493334933449335493364933749338493394934049341493424934349344493454934649347493484934949350493514935249353493544935549356493574935849359493604936149362493634936449365493664936749368493694937049371493724937349374493754937649377493784937949380493814938249383493844938549386493874938849389493904939149392493934939449395493964939749398493994940049401494024940349404494054940649407494084940949410494114941249413494144941549416494174941849419494204942149422494234942449425494264942749428494294943049431494324943349434494354943649437494384943949440494414944249443494444944549446494474944849449494504945149452494534945449455494564945749458494594946049461494624946349464494654946649467494684946949470494714947249473494744947549476494774947849479494804948149482494834948449485494864948749488494894949049491494924949349494494954949649497494984949949500495014950249503495044950549506495074950849509495104951149512495134951449515495164951749518495194952049521495224952349524495254952649527495284952949530495314953249533495344953549536495374953849539495404954149542495434954449545495464954749548495494955049551495524955349554495554955649557495584955949560495614956249563495644956549566495674956849569495704957149572495734957449575495764957749578495794958049581495824958349584495854958649587495884958949590495914959249593495944959549596495974959849599496004960149602496034960449605496064960749608496094961049611496124961349614496154961649617496184961949620496214962249623496244962549626496274962849629496304963149632496334963449635496364963749638496394964049641496424964349644496454964649647496484964949650496514965249653496544965549656496574965849659496604966149662496634966449665496664966749668496694967049671496724967349674496754967649677496784967949680496814968249683496844968549686496874968849689496904969149692496934969449695496964969749698496994970049701497024970349704497054970649707497084970949710497114971249713497144971549716497174971849719497204972149722497234972449725497264972749728497294973049731497324973349734497354973649737497384973949740497414974249743497444974549746497474974849749497504975149752497534975449755497564975749758497594976049761497624976349764497654976649767497684976949770497714977249773497744977549776497774977849779497804978149782497834978449785497864978749788497894979049791497924979349794497954979649797497984979949800498014980249803498044980549806498074980849809498104981149812498134981449815498164981749818498194982049821498224982349824498254982649827498284982949830498314983249833498344983549836498374983849839498404984149842498434984449845498464984749848498494985049851498524985349854498554985649857498584985949860498614986249863498644986549866498674986849869498704987149872498734987449875498764987749878498794988049881498824988349884498854988649887498884988949890498914989249893498944989549896498974989849899499004990149902499034990449905499064990749908499094991049911499124991349914499154991649917499184991949920499214992249923499244992549926499274992849929499304993149932499334993449935499364993749938499394994049941499424994349944499454994649947499484994949950499514995249953499544995549956499574995849959499604996149962499634996449965499664996749968499694997049971499724997349974499754997649977499784997949980499814998249983499844998549986499874998849989499904999149992499934999449995499964999749998499995000050001500025000350004500055000650007500085000950010500115001250013500145001550016500175001850019500205002150022500235002450025500265002750028500295003050031500325003350034500355003650037500385003950040500415004250043500445004550046500475004850049500505005150052500535005450055500565005750058500595006050061500625006350064500655006650067500685006950070500715007250073500745007550076500775007850079500805008150082500835008450085500865008750088500895009050091500925009350094500955009650097500985009950100501015010250103501045010550106501075010850109501105011150112501135011450115501165011750118501195012050121501225012350124501255012650127501285012950130501315013250133501345013550136501375013850139501405014150142501435014450145501465014750148501495015050151501525015350154501555015650157501585015950160501615016250163501645016550166501675016850169501705017150172501735017450175501765017750178501795018050181501825018350184501855018650187501885018950190501915019250193501945019550196501975019850199502005020150202502035020450205502065020750208502095021050211502125021350214502155021650217502185021950220502215022250223502245022550226502275022850229502305023150232502335023450235502365023750238502395024050241502425024350244502455024650247502485024950250502515025250253502545025550256502575025850259502605026150262502635026450265502665026750268502695027050271502725027350274502755027650277502785027950280502815028250283502845028550286502875028850289502905029150292502935029450295502965029750298502995030050301503025030350304503055030650307503085030950310503115031250313503145031550316503175031850319503205032150322503235032450325503265032750328503295033050331503325033350334503355033650337503385033950340503415034250343503445034550346503475034850349503505035150352503535035450355503565035750358503595036050361503625036350364503655036650367503685036950370503715037250373503745037550376503775037850379503805038150382503835038450385503865038750388503895039050391503925039350394503955039650397503985039950400504015040250403504045040550406504075040850409504105041150412504135041450415504165041750418504195042050421504225042350424504255042650427504285042950430504315043250433504345043550436504375043850439504405044150442504435044450445504465044750448504495045050451504525045350454504555045650457504585045950460504615046250463504645046550466504675046850469504705047150472504735047450475504765047750478504795048050481504825048350484504855048650487504885048950490504915049250493504945049550496504975049850499505005050150502505035050450505505065050750508505095051050511505125051350514505155051650517505185051950520505215052250523505245052550526505275052850529505305053150532505335053450535505365053750538505395054050541505425054350544505455054650547505485054950550505515055250553505545055550556505575055850559505605056150562505635056450565505665056750568505695057050571505725057350574505755057650577505785057950580505815058250583505845058550586505875058850589505905059150592505935059450595505965059750598505995060050601506025060350604506055060650607506085060950610506115061250613506145061550616506175061850619506205062150622506235062450625506265062750628506295063050631506325063350634506355063650637506385063950640506415064250643506445064550646506475064850649506505065150652506535065450655506565065750658506595066050661506625066350664506655066650667506685066950670506715067250673506745067550676506775067850679506805068150682506835068450685506865068750688506895069050691506925069350694506955069650697506985069950700507015070250703507045070550706507075070850709507105071150712507135071450715507165071750718507195072050721507225072350724507255072650727507285072950730507315073250733507345073550736507375073850739507405074150742507435074450745507465074750748507495075050751507525075350754507555075650757507585075950760507615076250763507645076550766507675076850769507705077150772507735077450775507765077750778507795078050781507825078350784507855078650787507885078950790507915079250793507945079550796507975079850799508005080150802508035080450805508065080750808508095081050811508125081350814508155081650817508185081950820508215082250823508245082550826508275082850829508305083150832508335083450835508365083750838508395084050841508425084350844508455084650847508485084950850508515085250853508545085550856508575085850859508605086150862508635086450865508665086750868508695087050871508725087350874508755087650877508785087950880508815088250883508845088550886508875088850889508905089150892508935089450895508965089750898508995090050901509025090350904509055090650907509085090950910509115091250913509145091550916509175091850919509205092150922509235092450925509265092750928509295093050931509325093350934509355093650937509385093950940509415094250943509445094550946509475094850949509505095150952509535095450955509565095750958509595096050961509625096350964509655096650967509685096950970509715097250973509745097550976509775097850979509805098150982509835098450985509865098750988509895099050991509925099350994509955099650997509985099951000510015100251003510045100551006510075100851009510105101151012510135101451015510165101751018510195102051021510225102351024510255102651027510285102951030510315103251033510345103551036510375103851039510405104151042510435104451045510465104751048510495105051051510525105351054510555105651057510585105951060510615106251063510645106551066510675106851069510705107151072510735107451075510765107751078510795108051081510825108351084510855108651087510885108951090510915109251093510945109551096510975109851099511005110151102511035110451105511065110751108511095111051111511125111351114511155111651117511185111951120511215112251123511245112551126511275112851129511305113151132511335113451135511365113751138511395114051141511425114351144511455114651147511485114951150511515115251153511545115551156511575115851159511605116151162511635116451165511665116751168511695117051171511725117351174511755117651177511785117951180511815118251183511845118551186511875118851189511905119151192511935119451195511965119751198511995120051201512025120351204512055120651207512085120951210512115121251213512145121551216512175121851219512205122151222512235122451225512265122751228512295123051231512325123351234512355123651237512385123951240512415124251243512445124551246512475124851249512505125151252512535125451255512565125751258512595126051261512625126351264512655126651267512685126951270512715127251273512745127551276512775127851279512805128151282512835128451285512865128751288512895129051291512925129351294512955129651297512985129951300513015130251303513045130551306513075130851309513105131151312513135131451315513165131751318513195132051321513225132351324513255132651327513285132951330513315133251333513345133551336513375133851339513405134151342513435134451345513465134751348513495135051351513525135351354513555135651357513585135951360513615136251363513645136551366513675136851369513705137151372513735137451375513765137751378513795138051381513825138351384513855138651387513885138951390513915139251393513945139551396513975139851399514005140151402514035140451405514065140751408514095141051411514125141351414514155141651417514185141951420514215142251423514245142551426514275142851429514305143151432514335143451435514365143751438514395144051441514425144351444514455144651447514485144951450514515145251453514545145551456514575145851459514605146151462514635146451465514665146751468514695147051471514725147351474514755147651477514785147951480514815148251483514845148551486514875148851489514905149151492514935149451495514965149751498514995150051501515025150351504515055150651507515085150951510515115151251513515145151551516515175151851519515205152151522515235152451525515265152751528515295153051531515325153351534515355153651537515385153951540515415154251543515445154551546515475154851549515505155151552515535155451555515565155751558515595156051561515625156351564515655156651567515685156951570515715157251573515745157551576515775157851579515805158151582515835158451585515865158751588515895159051591515925159351594515955159651597515985159951600516015160251603516045160551606516075160851609516105161151612516135161451615516165161751618516195162051621516225162351624516255162651627516285162951630516315163251633516345163551636516375163851639516405164151642516435164451645516465164751648516495165051651516525165351654516555165651657516585165951660516615166251663516645166551666516675166851669516705167151672516735167451675516765167751678516795168051681516825168351684516855168651687516885168951690516915169251693516945169551696516975169851699517005170151702517035170451705517065170751708517095171051711517125171351714517155171651717517185171951720517215172251723517245172551726517275172851729517305173151732517335173451735517365173751738517395174051741517425174351744517455174651747517485174951750517515175251753517545175551756517575175851759517605176151762517635176451765517665176751768517695177051771517725177351774517755177651777517785177951780517815178251783517845178551786517875178851789517905179151792517935179451795517965179751798517995180051801518025180351804518055180651807518085180951810518115181251813518145181551816518175181851819518205182151822518235182451825518265182751828518295183051831518325183351834518355183651837518385183951840518415184251843518445184551846518475184851849518505185151852518535185451855518565185751858518595186051861518625186351864518655186651867518685186951870518715187251873518745187551876518775187851879518805188151882518835188451885518865188751888518895189051891518925189351894518955189651897518985189951900519015190251903519045190551906519075190851909519105191151912519135191451915519165191751918519195192051921519225192351924519255192651927519285192951930519315193251933519345193551936519375193851939519405194151942519435194451945519465194751948519495195051951519525195351954519555195651957519585195951960519615196251963519645196551966519675196851969519705197151972519735197451975519765197751978519795198051981519825198351984519855198651987519885198951990519915199251993519945199551996519975199851999520005200152002520035200452005520065200752008520095201052011520125201352014520155201652017520185201952020520215202252023520245202552026520275202852029520305203152032520335203452035520365203752038520395204052041520425204352044520455204652047520485204952050520515205252053520545205552056520575205852059520605206152062520635206452065520665206752068520695207052071520725207352074520755207652077520785207952080520815208252083520845208552086520875208852089520905209152092520935209452095520965209752098520995210052101521025210352104521055210652107521085210952110521115211252113521145211552116521175211852119521205212152122521235212452125521265212752128521295213052131521325213352134521355213652137521385213952140521415214252143521445214552146521475214852149521505215152152521535215452155521565215752158521595216052161521625216352164521655216652167521685216952170521715217252173521745217552176521775217852179521805218152182521835218452185521865218752188521895219052191521925219352194521955219652197521985219952200522015220252203522045220552206522075220852209522105221152212522135221452215522165221752218522195222052221522225222352224522255222652227522285222952230522315223252233522345223552236522375223852239522405224152242522435224452245522465224752248522495225052251522525225352254522555225652257522585225952260522615226252263522645226552266522675226852269522705227152272522735227452275522765227752278522795228052281522825228352284522855228652287522885228952290522915229252293522945229552296522975229852299523005230152302523035230452305523065230752308523095231052311523125231352314523155231652317523185231952320523215232252323523245232552326523275232852329523305233152332523335233452335523365233752338523395234052341523425234352344523455234652347523485234952350523515235252353523545235552356523575235852359523605236152362523635236452365523665236752368523695237052371523725237352374523755237652377523785237952380523815238252383523845238552386523875238852389523905239152392523935239452395523965239752398523995240052401524025240352404524055240652407524085240952410524115241252413524145241552416524175241852419524205242152422524235242452425524265242752428524295243052431524325243352434524355243652437524385243952440524415244252443524445244552446524475244852449524505245152452524535245452455524565245752458524595246052461524625246352464524655246652467524685246952470524715247252473524745247552476524775247852479524805248152482524835248452485524865248752488524895249052491524925249352494524955249652497524985249952500525015250252503525045250552506525075250852509525105251152512525135251452515525165251752518525195252052521525225252352524525255252652527525285252952530525315253252533525345253552536525375253852539525405254152542525435254452545525465254752548525495255052551525525255352554525555255652557525585255952560525615256252563525645256552566525675256852569525705257152572525735257452575525765257752578525795258052581525825258352584525855258652587525885258952590525915259252593525945259552596525975259852599526005260152602526035260452605526065260752608526095261052611526125261352614526155261652617526185261952620526215262252623526245262552626526275262852629526305263152632526335263452635526365263752638526395264052641526425264352644526455264652647526485264952650526515265252653526545265552656526575265852659526605266152662526635266452665526665266752668526695267052671526725267352674526755267652677526785267952680526815268252683526845268552686526875268852689526905269152692526935269452695526965269752698526995270052701527025270352704527055270652707527085270952710527115271252713527145271552716527175271852719527205272152722527235272452725527265272752728527295273052731527325273352734527355273652737527385273952740527415274252743527445274552746527475274852749527505275152752527535275452755527565275752758527595276052761527625276352764527655276652767527685276952770527715277252773527745277552776527775277852779527805278152782527835278452785527865278752788527895279052791527925279352794527955279652797527985279952800528015280252803528045280552806528075280852809528105281152812528135281452815528165281752818528195282052821528225282352824528255282652827528285282952830528315283252833528345283552836528375283852839528405284152842528435284452845528465284752848528495285052851528525285352854528555285652857528585285952860528615286252863528645286552866528675286852869528705287152872528735287452875528765287752878528795288052881528825288352884528855288652887528885288952890528915289252893528945289552896528975289852899529005290152902529035290452905529065290752908529095291052911529125291352914529155291652917529185291952920529215292252923529245292552926529275292852929529305293152932529335293452935529365293752938529395294052941529425294352944529455294652947529485294952950529515295252953529545295552956529575295852959529605296152962529635296452965529665296752968529695297052971529725297352974529755297652977529785297952980529815298252983529845298552986529875298852989529905299152992529935299452995529965299752998529995300053001530025300353004530055300653007530085300953010530115301253013530145301553016530175301853019530205302153022530235302453025530265302753028530295303053031530325303353034530355303653037530385303953040530415304253043530445304553046530475304853049530505305153052530535305453055530565305753058530595306053061530625306353064530655306653067530685306953070530715307253073530745307553076530775307853079530805308153082530835308453085530865308753088530895309053091530925309353094530955309653097530985309953100531015310253103531045310553106531075310853109531105311153112531135311453115531165311753118531195312053121531225312353124531255312653127531285312953130531315313253133531345313553136531375313853139531405314153142531435314453145531465314753148531495315053151531525315353154531555315653157531585315953160531615316253163531645316553166531675316853169531705317153172531735317453175531765317753178531795318053181531825318353184531855318653187531885318953190531915319253193531945319553196531975319853199532005320153202532035320453205532065320753208532095321053211532125321353214532155321653217532185321953220532215322253223532245322553226532275322853229532305323153232532335323453235532365323753238532395324053241532425324353244532455324653247532485324953250532515325253253532545325553256532575325853259532605326153262532635326453265532665326753268532695327053271532725327353274532755327653277532785327953280532815328253283532845328553286532875328853289532905329153292532935329453295532965329753298532995330053301533025330353304533055330653307533085330953310533115331253313533145331553316533175331853319533205332153322533235332453325533265332753328533295333053331533325333353334533355333653337533385333953340533415334253343533445334553346533475334853349533505335153352533535335453355533565335753358533595336053361533625336353364533655336653367533685336953370533715337253373533745337553376533775337853379533805338153382533835338453385533865338753388533895339053391533925339353394533955339653397533985339953400534015340253403534045340553406534075340853409534105341153412534135341453415534165341753418534195342053421534225342353424534255342653427534285342953430534315343253433534345343553436534375343853439534405344153442534435344453445534465344753448534495345053451534525345353454534555345653457534585345953460534615346253463534645346553466534675346853469534705347153472534735347453475534765347753478534795348053481534825348353484534855348653487534885348953490534915349253493534945349553496534975349853499535005350153502535035350453505535065350753508535095351053511535125351353514535155351653517535185351953520535215352253523535245352553526535275352853529535305353153532535335353453535535365353753538535395354053541535425354353544535455354653547535485354953550535515355253553535545355553556535575355853559535605356153562535635356453565535665356753568535695357053571535725357353574535755357653577535785357953580535815358253583535845358553586535875358853589535905359153592535935359453595535965359753598535995360053601536025360353604536055360653607536085360953610536115361253613536145361553616536175361853619536205362153622536235362453625536265362753628536295363053631536325363353634536355363653637536385363953640536415364253643536445364553646536475364853649536505365153652536535365453655536565365753658536595366053661536625366353664536655366653667536685366953670536715367253673536745367553676536775367853679536805368153682536835368453685536865368753688536895369053691536925369353694536955369653697536985369953700537015370253703537045370553706537075370853709537105371153712537135371453715537165371753718537195372053721537225372353724537255372653727537285372953730537315373253733537345373553736537375373853739537405374153742537435374453745537465374753748537495375053751537525375353754537555375653757537585375953760537615376253763537645376553766537675376853769537705377153772537735377453775537765377753778537795378053781537825378353784537855378653787537885378953790537915379253793537945379553796537975379853799538005380153802538035380453805538065380753808538095381053811538125381353814538155381653817538185381953820538215382253823538245382553826538275382853829538305383153832538335383453835538365383753838538395384053841538425384353844538455384653847538485384953850538515385253853538545385553856538575385853859538605386153862538635386453865538665386753868538695387053871538725387353874538755387653877538785387953880538815388253883538845388553886538875388853889538905389153892538935389453895538965389753898538995390053901539025390353904539055390653907539085390953910539115391253913539145391553916539175391853919539205392153922539235392453925539265392753928539295393053931539325393353934539355393653937539385393953940539415394253943539445394553946539475394853949539505395153952539535395453955539565395753958539595396053961539625396353964539655396653967539685396953970539715397253973539745397553976539775397853979539805398153982539835398453985539865398753988539895399053991539925399353994539955399653997539985399954000540015400254003540045400554006540075400854009540105401154012540135401454015540165401754018540195402054021540225402354024540255402654027540285402954030540315403254033540345403554036540375403854039540405404154042540435404454045540465404754048540495405054051540525405354054540555405654057540585405954060540615406254063540645406554066540675406854069540705407154072540735407454075540765407754078540795408054081540825408354084540855408654087540885408954090540915409254093540945409554096540975409854099541005410154102541035410454105541065410754108541095411054111541125411354114541155411654117541185411954120541215412254123541245412554126541275412854129541305413154132541335413454135541365413754138541395414054141541425414354144541455414654147541485414954150541515415254153541545415554156541575415854159541605416154162541635416454165541665416754168541695417054171541725417354174541755417654177541785417954180541815418254183541845418554186541875418854189541905419154192541935419454195541965419754198541995420054201542025420354204542055420654207542085420954210542115421254213542145421554216542175421854219542205422154222542235422454225542265422754228542295423054231542325423354234542355423654237542385423954240542415424254243542445424554246542475424854249542505425154252542535425454255542565425754258542595426054261542625426354264542655426654267542685426954270542715427254273542745427554276542775427854279542805428154282542835428454285542865428754288542895429054291542925429354294542955429654297542985429954300543015430254303543045430554306543075430854309543105431154312543135431454315543165431754318543195432054321543225432354324543255432654327543285432954330543315433254333543345433554336543375433854339543405434154342543435434454345543465434754348543495435054351543525435354354543555435654357543585435954360543615436254363543645436554366543675436854369543705437154372543735437454375543765437754378543795438054381543825438354384543855438654387543885438954390543915439254393543945439554396543975439854399544005440154402544035440454405544065440754408544095441054411544125441354414544155441654417544185441954420544215442254423544245442554426544275442854429544305443154432544335443454435544365443754438544395444054441544425444354444544455444654447544485444954450544515445254453544545445554456544575445854459544605446154462544635446454465544665446754468544695447054471544725447354474544755447654477544785447954480544815448254483544845448554486544875448854489544905449154492544935449454495544965449754498544995450054501545025450354504545055450654507545085450954510545115451254513545145451554516545175451854519545205452154522545235452454525545265452754528545295453054531545325453354534545355453654537545385453954540545415454254543545445454554546545475454854549545505455154552545535455454555545565455754558545595456054561545625456354564545655456654567545685456954570545715457254573545745457554576545775457854579545805458154582545835458454585545865458754588545895459054591545925459354594545955459654597545985459954600546015460254603546045460554606546075460854609546105461154612546135461454615546165461754618546195462054621546225462354624546255462654627546285462954630546315463254633546345463554636546375463854639546405464154642546435464454645546465464754648546495465054651546525465354654546555465654657546585465954660546615466254663546645466554666546675466854669546705467154672546735467454675546765467754678546795468054681546825468354684546855468654687546885468954690546915469254693546945469554696546975469854699547005470154702547035470454705547065470754708547095471054711547125471354714547155471654717547185471954720547215472254723547245472554726547275472854729547305473154732547335473454735547365473754738547395474054741547425474354744547455474654747547485474954750547515475254753547545475554756547575475854759547605476154762547635476454765547665476754768547695477054771547725477354774547755477654777547785477954780547815478254783547845478554786547875478854789547905479154792547935479454795547965479754798547995480054801548025480354804548055480654807548085480954810548115481254813548145481554816548175481854819548205482154822548235482454825548265482754828548295483054831548325483354834548355483654837548385483954840548415484254843548445484554846548475484854849548505485154852548535485454855548565485754858548595486054861548625486354864548655486654867548685486954870548715487254873548745487554876548775487854879548805488154882548835488454885548865488754888548895489054891548925489354894548955489654897548985489954900549015490254903549045490554906549075490854909549105491154912549135491454915549165491754918549195492054921549225492354924549255492654927549285492954930549315493254933549345493554936549375493854939549405494154942549435494454945549465494754948549495495054951549525495354954549555495654957549585495954960549615496254963549645496554966549675496854969549705497154972549735497454975549765497754978549795498054981549825498354984549855498654987549885498954990549915499254993549945499554996549975499854999550005500155002550035500455005550065500755008550095501055011550125501355014550155501655017550185501955020550215502255023550245502555026550275502855029550305503155032550335503455035550365503755038550395504055041550425504355044550455504655047550485504955050550515505255053550545505555056550575505855059550605506155062550635506455065550665506755068550695507055071550725507355074550755507655077550785507955080550815508255083550845508555086550875508855089550905509155092550935509455095550965509755098550995510055101551025510355104551055510655107551085510955110551115511255113551145511555116551175511855119551205512155122551235512455125551265512755128551295513055131551325513355134551355513655137551385513955140551415514255143551445514555146551475514855149551505515155152551535515455155551565515755158551595516055161551625516355164551655516655167551685516955170551715517255173551745517555176551775517855179551805518155182551835518455185551865518755188551895519055191551925519355194551955519655197551985519955200552015520255203552045520555206552075520855209552105521155212552135521455215552165521755218552195522055221552225522355224552255522655227552285522955230552315523255233552345523555236552375523855239552405524155242552435524455245552465524755248552495525055251552525525355254552555525655257552585525955260552615526255263552645526555266552675526855269552705527155272552735527455275552765527755278552795528055281552825528355284552855528655287552885528955290552915529255293552945529555296552975529855299553005530155302553035530455305553065530755308553095531055311553125531355314553155531655317553185531955320553215532255323553245532555326553275532855329553305533155332553335533455335553365533755338553395534055341553425534355344553455534655347553485534955350553515535255353553545535555356553575535855359553605536155362553635536455365553665536755368553695537055371553725537355374553755537655377553785537955380553815538255383553845538555386553875538855389553905539155392553935539455395553965539755398553995540055401554025540355404554055540655407554085540955410554115541255413554145541555416554175541855419554205542155422554235542455425554265542755428554295543055431554325543355434554355543655437554385543955440554415544255443554445544555446554475544855449554505545155452554535545455455554565545755458554595546055461554625546355464554655546655467554685546955470554715547255473554745547555476554775547855479554805548155482554835548455485554865548755488554895549055491554925549355494554955549655497554985549955500555015550255503555045550555506555075550855509555105551155512555135551455515555165551755518555195552055521555225552355524555255552655527555285552955530555315553255533555345553555536555375553855539555405554155542555435554455545555465554755548555495555055551555525555355554555555555655557555585555955560555615556255563555645556555566555675556855569555705557155572555735557455575555765557755578555795558055581555825558355584555855558655587555885558955590555915559255593555945559555596555975559855599556005560155602556035560455605556065560755608556095561055611556125561355614556155561655617556185561955620556215562255623556245562555626556275562855629556305563155632556335563455635556365563755638556395564055641556425564355644556455564655647556485564955650556515565255653556545565555656556575565855659556605566155662556635566455665556665566755668556695567055671556725567355674556755567655677556785567955680556815568255683556845568555686556875568855689556905569155692556935569455695556965569755698556995570055701557025570355704557055570655707557085570955710557115571255713557145571555716557175571855719557205572155722557235572455725557265572755728557295573055731557325573355734557355573655737557385573955740557415574255743557445574555746557475574855749557505575155752557535575455755557565575755758557595576055761557625576355764557655576655767557685576955770557715577255773557745577555776557775577855779557805578155782557835578455785557865578755788557895579055791557925579355794557955579655797557985579955800558015580255803558045580555806558075580855809558105581155812558135581455815558165581755818558195582055821558225582355824558255582655827558285582955830558315583255833558345583555836558375583855839558405584155842558435584455845558465584755848558495585055851558525585355854558555585655857558585585955860558615586255863558645586555866558675586855869558705587155872558735587455875558765587755878558795588055881558825588355884558855588655887558885588955890558915589255893558945589555896558975589855899559005590155902559035590455905559065590755908559095591055911559125591355914559155591655917559185591955920559215592255923559245592555926559275592855929559305593155932559335593455935559365593755938559395594055941559425594355944559455594655947559485594955950559515595255953559545595555956559575595855959559605596155962559635596455965559665596755968559695597055971559725597355974559755597655977559785597955980559815598255983559845598555986559875598855989559905599155992559935599455995559965599755998559995600056001560025600356004560055600656007560085600956010560115601256013560145601556016560175601856019560205602156022560235602456025560265602756028560295603056031560325603356034560355603656037560385603956040560415604256043560445604556046560475604856049560505605156052560535605456055560565605756058560595606056061560625606356064560655606656067560685606956070560715607256073560745607556076560775607856079560805608156082560835608456085560865608756088560895609056091560925609356094560955609656097560985609956100561015610256103561045610556106561075610856109561105611156112561135611456115561165611756118561195612056121561225612356124561255612656127561285612956130561315613256133561345613556136561375613856139561405614156142561435614456145561465614756148561495615056151561525615356154561555615656157561585615956160561615616256163561645616556166561675616856169561705617156172561735617456175561765617756178561795618056181561825618356184561855618656187561885618956190561915619256193561945619556196561975619856199562005620156202562035620456205562065620756208562095621056211562125621356214562155621656217562185621956220562215622256223562245622556226562275622856229562305623156232562335623456235562365623756238562395624056241562425624356244562455624656247562485624956250562515625256253562545625556256562575625856259562605626156262562635626456265562665626756268562695627056271562725627356274562755627656277562785627956280562815628256283562845628556286562875628856289562905629156292562935629456295562965629756298562995630056301563025630356304563055630656307563085630956310563115631256313563145631556316563175631856319563205632156322563235632456325563265632756328563295633056331563325633356334563355633656337563385633956340563415634256343563445634556346563475634856349563505635156352563535635456355563565635756358563595636056361563625636356364563655636656367563685636956370563715637256373563745637556376563775637856379563805638156382563835638456385563865638756388563895639056391563925639356394563955639656397563985639956400564015640256403564045640556406564075640856409564105641156412564135641456415564165641756418564195642056421564225642356424564255642656427564285642956430564315643256433564345643556436564375643856439564405644156442564435644456445564465644756448564495645056451564525645356454564555645656457564585645956460564615646256463564645646556466564675646856469564705647156472564735647456475564765647756478564795648056481564825648356484564855648656487564885648956490564915649256493564945649556496564975649856499565005650156502565035650456505565065650756508565095651056511565125651356514565155651656517565185651956520565215652256523565245652556526565275652856529565305653156532565335653456535565365653756538565395654056541565425654356544565455654656547565485654956550565515655256553565545655556556565575655856559565605656156562565635656456565565665656756568565695657056571565725657356574565755657656577565785657956580565815658256583565845658556586565875658856589565905659156592565935659456595565965659756598565995660056601566025660356604566055660656607566085660956610566115661256613566145661556616566175661856619566205662156622566235662456625566265662756628566295663056631566325663356634566355663656637566385663956640566415664256643566445664556646566475664856649566505665156652566535665456655566565665756658566595666056661566625666356664566655666656667566685666956670566715667256673566745667556676566775667856679566805668156682566835668456685566865668756688566895669056691566925669356694566955669656697566985669956700567015670256703567045670556706567075670856709567105671156712567135671456715567165671756718567195672056721567225672356724567255672656727567285672956730567315673256733567345673556736567375673856739567405674156742567435674456745567465674756748567495675056751567525675356754567555675656757567585675956760567615676256763567645676556766567675676856769567705677156772567735677456775567765677756778567795678056781567825678356784567855678656787567885678956790567915679256793567945679556796567975679856799568005680156802568035680456805568065680756808568095681056811568125681356814568155681656817568185681956820568215682256823568245682556826568275682856829568305683156832568335683456835568365683756838568395684056841568425684356844568455684656847568485684956850568515685256853568545685556856568575685856859568605686156862568635686456865568665686756868568695687056871568725687356874568755687656877568785687956880568815688256883568845688556886568875688856889568905689156892568935689456895568965689756898568995690056901569025690356904569055690656907569085690956910569115691256913569145691556916569175691856919569205692156922569235692456925569265692756928569295693056931569325693356934569355693656937569385693956940569415694256943569445694556946569475694856949569505695156952569535695456955569565695756958569595696056961569625696356964569655696656967569685696956970569715697256973569745697556976569775697856979569805698156982569835698456985569865698756988569895699056991569925699356994569955699656997569985699957000570015700257003570045700557006570075700857009570105701157012570135701457015570165701757018570195702057021570225702357024570255702657027570285702957030570315703257033570345703557036570375703857039570405704157042570435704457045570465704757048570495705057051570525705357054570555705657057570585705957060570615706257063570645706557066570675706857069570705707157072570735707457075570765707757078570795708057081570825708357084570855708657087570885708957090570915709257093570945709557096570975709857099571005710157102571035710457105571065710757108571095711057111571125711357114571155711657117571185711957120571215712257123571245712557126571275712857129571305713157132571335713457135571365713757138571395714057141571425714357144571455714657147571485714957150571515715257153571545715557156571575715857159571605716157162571635716457165571665716757168571695717057171571725717357174571755717657177571785717957180571815718257183571845718557186571875718857189571905719157192571935719457195571965719757198571995720057201572025720357204572055720657207572085720957210572115721257213572145721557216572175721857219572205722157222572235722457225572265722757228572295723057231572325723357234572355723657237572385723957240572415724257243572445724557246572475724857249572505725157252572535725457255572565725757258572595726057261572625726357264572655726657267572685726957270572715727257273572745727557276572775727857279572805728157282572835728457285572865728757288572895729057291572925729357294572955729657297572985729957300573015730257303573045730557306573075730857309573105731157312573135731457315573165731757318573195732057321573225732357324573255732657327573285732957330573315733257333573345733557336573375733857339573405734157342573435734457345573465734757348573495735057351573525735357354573555735657357573585735957360573615736257363573645736557366573675736857369573705737157372573735737457375573765737757378573795738057381573825738357384573855738657387573885738957390573915739257393573945739557396573975739857399574005740157402574035740457405574065740757408574095741057411574125741357414574155741657417574185741957420574215742257423574245742557426574275742857429574305743157432574335743457435574365743757438574395744057441574425744357444574455744657447574485744957450574515745257453574545745557456574575745857459574605746157462574635746457465574665746757468574695747057471574725747357474574755747657477574785747957480574815748257483574845748557486574875748857489574905749157492574935749457495574965749757498574995750057501575025750357504575055750657507575085750957510575115751257513575145751557516575175751857519575205752157522575235752457525575265752757528575295753057531575325753357534575355753657537575385753957540575415754257543575445754557546575475754857549575505755157552575535755457555575565755757558575595756057561575625756357564575655756657567575685756957570575715757257573575745757557576575775757857579575805758157582575835758457585575865758757588575895759057591575925759357594575955759657597575985759957600576015760257603576045760557606576075760857609576105761157612576135761457615576165761757618576195762057621576225762357624576255762657627576285762957630576315763257633576345763557636576375763857639576405764157642576435764457645576465764757648576495765057651576525765357654576555765657657576585765957660576615766257663576645766557666576675766857669576705767157672576735767457675576765767757678576795768057681576825768357684576855768657687576885768957690576915769257693576945769557696576975769857699577005770157702577035770457705577065770757708577095771057711577125771357714577155771657717577185771957720577215772257723577245772557726577275772857729577305773157732577335773457735577365773757738577395774057741577425774357744577455774657747577485774957750577515775257753577545775557756577575775857759577605776157762577635776457765577665776757768577695777057771577725777357774577755777657777577785777957780577815778257783577845778557786577875778857789577905779157792577935779457795577965779757798577995780057801578025780357804578055780657807578085780957810578115781257813578145781557816578175781857819578205782157822578235782457825578265782757828578295783057831578325783357834578355783657837578385783957840578415784257843578445784557846578475784857849578505785157852578535785457855578565785757858578595786057861578625786357864578655786657867578685786957870578715787257873578745787557876578775787857879578805788157882578835788457885578865788757888578895789057891578925789357894578955789657897578985789957900579015790257903579045790557906579075790857909579105791157912579135791457915579165791757918579195792057921579225792357924579255792657927579285792957930579315793257933579345793557936579375793857939579405794157942579435794457945579465794757948579495795057951579525795357954579555795657957579585795957960579615796257963579645796557966579675796857969579705797157972579735797457975579765797757978579795798057981579825798357984579855798657987579885798957990579915799257993579945799557996579975799857999580005800158002580035800458005580065800758008580095801058011580125801358014580155801658017580185801958020580215802258023580245802558026580275802858029580305803158032580335803458035580365803758038580395804058041580425804358044580455804658047580485804958050580515805258053580545805558056580575805858059580605806158062580635806458065580665806758068580695807058071580725807358074580755807658077580785807958080580815808258083580845808558086580875808858089580905809158092580935809458095580965809758098580995810058101581025810358104581055810658107581085810958110581115811258113581145811558116581175811858119581205812158122581235812458125581265812758128581295813058131581325813358134581355813658137581385813958140581415814258143581445814558146581475814858149581505815158152581535815458155581565815758158581595816058161581625816358164581655816658167581685816958170581715817258173581745817558176581775817858179581805818158182581835818458185581865818758188581895819058191581925819358194581955819658197581985819958200582015820258203582045820558206582075820858209582105821158212582135821458215582165821758218582195822058221582225822358224582255822658227582285822958230582315823258233582345823558236582375823858239582405824158242582435824458245582465824758248582495825058251582525825358254582555825658257582585825958260582615826258263582645826558266582675826858269582705827158272582735827458275582765827758278582795828058281582825828358284582855828658287582885828958290582915829258293582945829558296582975829858299583005830158302583035830458305583065830758308583095831058311583125831358314583155831658317583185831958320583215832258323583245832558326583275832858329583305833158332583335833458335583365833758338583395834058341583425834358344583455834658347583485834958350583515835258353583545835558356583575835858359583605836158362583635836458365583665836758368583695837058371583725837358374583755837658377583785837958380583815838258383583845838558386583875838858389583905839158392583935839458395583965839758398583995840058401584025840358404584055840658407584085840958410584115841258413584145841558416584175841858419584205842158422584235842458425584265842758428584295843058431584325843358434584355843658437584385843958440584415844258443584445844558446584475844858449584505845158452584535845458455584565845758458584595846058461584625846358464584655846658467584685846958470584715847258473584745847558476584775847858479584805848158482584835848458485584865848758488584895849058491584925849358494584955849658497584985849958500585015850258503585045850558506585075850858509585105851158512585135851458515585165851758518585195852058521585225852358524585255852658527585285852958530585315853258533585345853558536585375853858539585405854158542585435854458545585465854758548585495855058551585525855358554585555855658557585585855958560585615856258563585645856558566585675856858569585705857158572585735857458575585765857758578585795858058581585825858358584585855858658587585885858958590585915859258593585945859558596585975859858599586005860158602586035860458605586065860758608586095861058611586125861358614586155861658617586185861958620586215862258623586245862558626586275862858629586305863158632586335863458635586365863758638586395864058641586425864358644586455864658647586485864958650586515865258653586545865558656586575865858659586605866158662586635866458665586665866758668586695867058671586725867358674586755867658677586785867958680586815868258683586845868558686586875868858689586905869158692586935869458695586965869758698586995870058701587025870358704587055870658707587085870958710587115871258713587145871558716587175871858719587205872158722587235872458725587265872758728587295873058731587325873358734587355873658737587385873958740587415874258743587445874558746587475874858749587505875158752587535875458755587565875758758587595876058761587625876358764587655876658767587685876958770587715877258773587745877558776587775877858779587805878158782587835878458785587865878758788587895879058791587925879358794587955879658797587985879958800588015880258803588045880558806588075880858809588105881158812588135881458815588165881758818588195882058821588225882358824588255882658827588285882958830588315883258833588345883558836588375883858839588405884158842588435884458845588465884758848588495885058851588525885358854588555885658857588585885958860588615886258863588645886558866588675886858869588705887158872588735887458875588765887758878588795888058881588825888358884588855888658887588885888958890588915889258893588945889558896588975889858899589005890158902589035890458905589065890758908589095891058911589125891358914589155891658917589185891958920589215892258923589245892558926589275892858929589305893158932589335893458935589365893758938589395894058941589425894358944589455894658947589485894958950589515895258953589545895558956589575895858959589605896158962589635896458965589665896758968589695897058971589725897358974589755897658977589785897958980589815898258983589845898558986589875898858989589905899158992589935899458995589965899758998589995900059001590025900359004590055900659007590085900959010590115901259013590145901559016590175901859019590205902159022590235902459025590265902759028590295903059031590325903359034590355903659037590385903959040590415904259043590445904559046590475904859049590505905159052590535905459055590565905759058590595906059061590625906359064590655906659067590685906959070590715907259073590745907559076590775907859079590805908159082590835908459085590865908759088590895909059091590925909359094590955909659097590985909959100591015910259103591045910559106591075910859109591105911159112591135911459115591165911759118591195912059121591225912359124591255912659127591285912959130591315913259133591345913559136591375913859139591405914159142591435914459145591465914759148591495915059151591525915359154591555915659157591585915959160591615916259163591645916559166591675916859169591705917159172591735917459175591765917759178591795918059181591825918359184591855918659187591885918959190591915919259193591945919559196591975919859199592005920159202592035920459205592065920759208592095921059211592125921359214592155921659217592185921959220592215922259223592245922559226592275922859229592305923159232592335923459235592365923759238592395924059241592425924359244592455924659247592485924959250592515925259253592545925559256592575925859259592605926159262592635926459265592665926759268592695927059271592725927359274592755927659277592785927959280592815928259283592845928559286592875928859289592905929159292592935929459295592965929759298592995930059301593025930359304593055930659307593085930959310593115931259313593145931559316593175931859319593205932159322593235932459325593265932759328593295933059331593325933359334593355933659337593385933959340593415934259343593445934559346593475934859349593505935159352593535935459355593565935759358593595936059361593625936359364593655936659367593685936959370593715937259373593745937559376593775937859379593805938159382593835938459385593865938759388593895939059391593925939359394593955939659397593985939959400594015940259403594045940559406594075940859409594105941159412594135941459415594165941759418594195942059421594225942359424594255942659427594285942959430594315943259433594345943559436594375943859439594405944159442594435944459445594465944759448594495945059451594525945359454594555945659457594585945959460594615946259463594645946559466594675946859469594705947159472594735947459475594765947759478594795948059481594825948359484594855948659487594885948959490594915949259493594945949559496594975949859499595005950159502595035950459505595065950759508595095951059511595125951359514595155951659517595185951959520595215952259523595245952559526595275952859529595305953159532595335953459535595365953759538595395954059541595425954359544595455954659547595485954959550595515955259553595545955559556595575955859559595605956159562595635956459565595665956759568595695957059571595725957359574595755957659577595785957959580595815958259583595845958559586595875958859589595905959159592595935959459595595965959759598595995960059601596025960359604596055960659607596085960959610596115961259613596145961559616596175961859619596205962159622596235962459625596265962759628596295963059631596325963359634596355963659637596385963959640596415964259643596445964559646596475964859649596505965159652596535965459655596565965759658596595966059661596625966359664596655966659667596685966959670596715967259673596745967559676596775967859679596805968159682596835968459685596865968759688596895969059691596925969359694596955969659697596985969959700597015970259703597045970559706597075970859709597105971159712597135971459715597165971759718597195972059721597225972359724597255972659727597285972959730597315973259733597345973559736597375973859739597405974159742597435974459745597465974759748597495975059751597525975359754597555975659757597585975959760597615976259763597645976559766597675976859769597705977159772597735977459775597765977759778597795978059781597825978359784597855978659787597885978959790597915979259793597945979559796597975979859799598005980159802598035980459805598065980759808598095981059811598125981359814598155981659817598185981959820598215982259823598245982559826598275982859829598305983159832598335983459835598365983759838598395984059841598425984359844598455984659847598485984959850598515985259853598545985559856598575985859859598605986159862598635986459865598665986759868598695987059871598725987359874598755987659877598785987959880598815988259883598845988559886598875988859889598905989159892598935989459895598965989759898598995990059901599025990359904599055990659907599085990959910599115991259913599145991559916599175991859919599205992159922599235992459925599265992759928599295993059931599325993359934599355993659937599385993959940599415994259943599445994559946599475994859949599505995159952599535995459955599565995759958599595996059961599625996359964599655996659967599685996959970599715997259973599745997559976599775997859979599805998159982599835998459985599865998759988599895999059991599925999359994599955999659997599985999960000600016000260003600046000560006600076000860009600106001160012600136001460015600166001760018600196002060021600226002360024600256002660027600286002960030600316003260033600346003560036600376003860039600406004160042600436004460045600466004760048600496005060051600526005360054600556005660057600586005960060600616006260063600646006560066600676006860069600706007160072600736007460075600766007760078600796008060081600826008360084600856008660087600886008960090600916009260093600946009560096600976009860099601006010160102601036010460105601066010760108601096011060111601126011360114601156011660117601186011960120601216012260123601246012560126601276012860129601306013160132601336013460135601366013760138601396014060141601426014360144601456014660147601486014960150601516015260153601546015560156601576015860159601606016160162601636016460165601666016760168601696017060171601726017360174601756017660177601786017960180601816018260183601846018560186601876018860189601906019160192601936019460195601966019760198601996020060201602026020360204602056020660207602086020960210602116021260213602146021560216602176021860219602206022160222602236022460225602266022760228602296023060231602326023360234602356023660237602386023960240602416024260243602446024560246602476024860249602506025160252602536025460255602566025760258602596026060261602626026360264602656026660267602686026960270602716027260273602746027560276602776027860279602806028160282602836028460285602866028760288602896029060291602926029360294602956029660297602986029960300603016030260303603046030560306603076030860309603106031160312603136031460315603166031760318603196032060321603226032360324603256032660327603286032960330603316033260333603346033560336603376033860339603406034160342603436034460345603466034760348603496035060351603526035360354603556035660357603586035960360603616036260363603646036560366603676036860369603706037160372603736037460375603766037760378603796038060381603826038360384603856038660387603886038960390603916039260393603946039560396603976039860399604006040160402604036040460405604066040760408604096041060411604126041360414604156041660417604186041960420604216042260423604246042560426604276042860429604306043160432604336043460435604366043760438604396044060441604426044360444604456044660447604486044960450604516045260453604546045560456604576045860459604606046160462604636046460465604666046760468604696047060471604726047360474604756047660477604786047960480604816048260483604846048560486604876048860489604906049160492604936049460495604966049760498604996050060501605026050360504605056050660507605086050960510605116051260513605146051560516605176051860519605206052160522605236052460525605266052760528605296053060531605326053360534605356053660537605386053960540605416054260543605446054560546605476054860549605506055160552605536055460555605566055760558605596056060561605626056360564605656056660567605686056960570605716057260573605746057560576605776057860579605806058160582605836058460585605866058760588605896059060591605926059360594605956059660597605986059960600606016060260603606046060560606606076060860609606106061160612606136061460615606166061760618606196062060621606226062360624606256062660627606286062960630606316063260633606346063560636606376063860639606406064160642606436064460645606466064760648606496065060651606526065360654606556065660657606586065960660606616066260663606646066560666606676066860669606706067160672606736067460675606766067760678606796068060681606826068360684606856068660687606886068960690606916069260693606946069560696606976069860699607006070160702607036070460705607066070760708607096071060711607126071360714607156071660717607186071960720607216072260723607246072560726607276072860729607306073160732607336073460735607366073760738607396074060741607426074360744607456074660747607486074960750607516075260753607546075560756607576075860759607606076160762607636076460765607666076760768607696077060771607726077360774607756077660777607786077960780607816078260783607846078560786607876078860789607906079160792607936079460795607966079760798607996080060801608026080360804608056080660807608086080960810608116081260813608146081560816608176081860819608206082160822608236082460825608266082760828608296083060831608326083360834608356083660837608386083960840608416084260843608446084560846608476084860849608506085160852608536085460855608566085760858608596086060861608626086360864608656086660867608686086960870608716087260873608746087560876608776087860879608806088160882608836088460885608866088760888608896089060891608926089360894608956089660897608986089960900609016090260903609046090560906609076090860909609106091160912609136091460915609166091760918609196092060921609226092360924609256092660927609286092960930609316093260933609346093560936609376093860939609406094160942609436094460945609466094760948609496095060951609526095360954609556095660957609586095960960609616096260963609646096560966609676096860969609706097160972609736097460975609766097760978609796098060981609826098360984609856098660987609886098960990609916099260993609946099560996609976099860999610006100161002610036100461005610066100761008610096101061011610126101361014610156101661017610186101961020610216102261023610246102561026610276102861029610306103161032610336103461035610366103761038610396104061041610426104361044610456104661047610486104961050610516105261053610546105561056610576105861059610606106161062610636106461065610666106761068610696107061071610726107361074610756107661077610786107961080610816108261083610846108561086610876108861089610906109161092610936109461095610966109761098610996110061101611026110361104611056110661107611086110961110611116111261113611146111561116611176111861119611206112161122611236112461125611266112761128611296113061131611326113361134611356113661137611386113961140611416114261143611446114561146611476114861149611506115161152611536115461155611566115761158611596116061161611626116361164611656116661167611686116961170611716117261173611746117561176611776117861179611806118161182611836118461185611866118761188611896119061191611926119361194611956119661197611986119961200612016120261203612046120561206612076120861209612106121161212612136121461215612166121761218612196122061221612226122361224612256122661227612286122961230612316123261233612346123561236612376123861239612406124161242612436124461245612466124761248612496125061251612526125361254612556125661257612586125961260612616126261263612646126561266612676126861269612706127161272612736127461275612766127761278612796128061281612826128361284612856128661287612886128961290612916129261293612946129561296612976129861299613006130161302613036130461305613066130761308613096131061311613126131361314613156131661317613186131961320613216132261323613246132561326613276132861329613306133161332613336133461335613366133761338613396134061341613426134361344613456134661347613486134961350613516135261353613546135561356613576135861359613606136161362613636136461365613666136761368613696137061371613726137361374613756137661377613786137961380613816138261383613846138561386613876138861389613906139161392613936139461395613966139761398613996140061401614026140361404614056140661407614086140961410614116141261413614146141561416614176141861419614206142161422614236142461425614266142761428614296143061431614326143361434614356143661437614386143961440614416144261443614446144561446614476144861449614506145161452614536145461455614566145761458614596146061461614626146361464614656146661467614686146961470614716147261473614746147561476614776147861479614806148161482614836148461485614866148761488614896149061491614926149361494614956149661497614986149961500615016150261503615046150561506615076150861509615106151161512615136151461515615166151761518615196152061521615226152361524615256152661527615286152961530615316153261533615346153561536615376153861539615406154161542615436154461545615466154761548615496155061551615526155361554615556155661557615586155961560615616156261563615646156561566615676156861569615706157161572615736157461575615766157761578615796158061581615826158361584615856158661587615886158961590615916159261593615946159561596615976159861599616006160161602616036160461605616066160761608616096161061611616126161361614616156161661617616186161961620616216162261623616246162561626616276162861629616306163161632616336163461635616366163761638616396164061641616426164361644616456164661647616486164961650616516165261653616546165561656616576165861659616606166161662616636166461665616666166761668616696167061671616726167361674616756167661677616786167961680616816168261683616846168561686616876168861689616906169161692616936169461695616966169761698616996170061701617026170361704617056170661707617086170961710617116171261713617146171561716617176171861719617206172161722617236172461725617266172761728617296173061731617326173361734617356173661737617386173961740617416174261743617446174561746617476174861749617506175161752617536175461755617566175761758617596176061761617626176361764617656176661767617686176961770617716177261773617746177561776617776177861779617806178161782617836178461785617866178761788617896179061791617926179361794617956179661797617986179961800618016180261803618046180561806618076180861809618106181161812618136181461815618166181761818618196182061821618226182361824618256182661827618286182961830618316183261833618346183561836618376183861839618406184161842618436184461845618466184761848618496185061851618526185361854618556185661857618586185961860618616186261863618646186561866618676186861869618706187161872618736187461875618766187761878618796188061881618826188361884618856188661887618886188961890618916189261893618946189561896618976189861899619006190161902619036190461905619066190761908619096191061911619126191361914619156191661917619186191961920619216192261923619246192561926619276192861929619306193161932619336193461935619366193761938619396194061941619426194361944619456194661947619486194961950619516195261953619546195561956619576195861959619606196161962619636196461965619666196761968619696197061971619726197361974619756197661977619786197961980619816198261983619846198561986619876198861989619906199161992619936199461995619966199761998619996200062001620026200362004620056200662007620086200962010620116201262013620146201562016620176201862019620206202162022620236202462025620266202762028620296203062031620326203362034620356203662037620386203962040620416204262043620446204562046620476204862049620506205162052620536205462055620566205762058620596206062061620626206362064620656206662067620686206962070620716207262073620746207562076620776207862079620806208162082620836208462085620866208762088620896209062091620926209362094620956209662097620986209962100621016210262103621046210562106621076210862109621106211162112621136211462115621166211762118621196212062121621226212362124621256212662127621286212962130621316213262133621346213562136621376213862139621406214162142621436214462145621466214762148621496215062151621526215362154621556215662157621586215962160621616216262163621646216562166621676216862169621706217162172621736217462175621766217762178621796218062181621826218362184621856218662187621886218962190621916219262193621946219562196621976219862199622006220162202622036220462205622066220762208622096221062211622126221362214622156221662217622186221962220622216222262223622246222562226622276222862229622306223162232622336223462235622366223762238622396224062241622426224362244622456224662247622486224962250622516225262253622546225562256622576225862259622606226162262622636226462265622666226762268622696227062271622726227362274622756227662277622786227962280622816228262283622846228562286622876228862289622906229162292622936229462295622966229762298622996230062301623026230362304623056230662307623086230962310623116231262313623146231562316623176231862319623206232162322623236232462325623266232762328623296233062331623326233362334623356233662337623386233962340623416234262343623446234562346623476234862349623506235162352623536235462355623566235762358623596236062361623626236362364623656236662367623686236962370623716237262373623746237562376623776237862379623806238162382623836238462385623866238762388623896239062391623926239362394623956239662397623986239962400624016240262403624046240562406624076240862409624106241162412624136241462415624166241762418624196242062421624226242362424624256242662427624286242962430624316243262433624346243562436624376243862439624406244162442624436244462445624466244762448624496245062451624526245362454624556245662457624586245962460624616246262463624646246562466624676246862469624706247162472624736247462475624766247762478624796248062481624826248362484624856248662487624886248962490624916249262493624946249562496624976249862499625006250162502625036250462505625066250762508625096251062511625126251362514625156251662517625186251962520625216252262523625246252562526625276252862529625306253162532625336253462535625366253762538625396254062541625426254362544625456254662547625486254962550625516255262553625546255562556625576255862559625606256162562625636256462565625666256762568625696257062571625726257362574625756257662577625786257962580625816258262583625846258562586625876258862589625906259162592625936259462595625966259762598625996260062601626026260362604626056260662607626086260962610626116261262613626146261562616626176261862619626206262162622626236262462625626266262762628626296263062631626326263362634626356263662637626386263962640626416264262643626446264562646626476264862649626506265162652626536265462655626566265762658626596266062661626626266362664626656266662667626686266962670626716267262673626746267562676626776267862679626806268162682626836268462685626866268762688626896269062691626926269362694626956269662697626986269962700627016270262703627046270562706627076270862709627106271162712627136271462715627166271762718627196272062721627226272362724627256272662727627286272962730627316273262733627346273562736627376273862739627406274162742627436274462745627466274762748627496275062751627526275362754627556275662757627586275962760627616276262763627646276562766627676276862769627706277162772627736277462775627766277762778627796278062781627826278362784627856278662787627886278962790627916279262793627946279562796627976279862799628006280162802628036280462805628066280762808628096281062811628126281362814628156281662817628186281962820628216282262823628246282562826628276282862829628306283162832628336283462835628366283762838628396284062841628426284362844628456284662847628486284962850628516285262853628546285562856628576285862859628606286162862628636286462865628666286762868628696287062871628726287362874628756287662877628786287962880628816288262883628846288562886628876288862889628906289162892628936289462895628966289762898628996290062901629026290362904629056290662907629086290962910629116291262913629146291562916629176291862919629206292162922629236292462925629266292762928629296293062931629326293362934629356293662937629386293962940629416294262943629446294562946629476294862949629506295162952629536295462955629566295762958629596296062961629626296362964629656296662967629686296962970629716297262973629746297562976629776297862979629806298162982629836298462985629866298762988629896299062991629926299362994629956299662997629986299963000630016300263003630046300563006630076300863009630106301163012630136301463015630166301763018630196302063021630226302363024630256302663027630286302963030630316303263033630346303563036630376303863039630406304163042630436304463045630466304763048630496305063051630526305363054630556305663057630586305963060630616306263063630646306563066630676306863069630706307163072630736307463075630766307763078630796308063081630826308363084630856308663087630886308963090630916309263093630946309563096630976309863099631006310163102631036310463105631066310763108631096311063111631126311363114631156311663117631186311963120631216312263123631246312563126631276312863129631306313163132631336313463135631366313763138631396314063141631426314363144631456314663147631486314963150631516315263153631546315563156631576315863159631606316163162631636316463165631666316763168631696317063171631726317363174631756317663177631786317963180631816318263183631846318563186631876318863189631906319163192631936319463195631966319763198631996320063201632026320363204632056320663207632086320963210632116321263213632146321563216632176321863219632206322163222632236322463225632266322763228632296323063231632326323363234632356323663237632386323963240632416324263243632446324563246632476324863249632506325163252632536325463255632566325763258632596326063261632626326363264632656326663267632686326963270632716327263273632746327563276632776327863279632806328163282632836328463285632866328763288632896329063291632926329363294632956329663297632986329963300633016330263303633046330563306633076330863309633106331163312633136331463315633166331763318633196332063321633226332363324633256332663327633286332963330633316333263333633346333563336633376333863339633406334163342633436334463345633466334763348633496335063351633526335363354633556335663357633586335963360633616336263363633646336563366633676336863369633706337163372633736337463375633766337763378633796338063381633826338363384633856338663387633886338963390633916339263393633946339563396633976339863399634006340163402634036340463405634066340763408634096341063411634126341363414634156341663417634186341963420634216342263423634246342563426634276342863429634306343163432634336343463435634366343763438634396344063441634426344363444634456344663447634486344963450634516345263453634546345563456634576345863459634606346163462634636346463465634666346763468634696347063471634726347363474634756347663477634786347963480634816348263483634846348563486634876348863489634906349163492634936349463495634966349763498634996350063501635026350363504635056350663507635086350963510635116351263513635146351563516635176351863519635206352163522635236352463525635266352763528635296353063531635326353363534635356353663537635386353963540635416354263543635446354563546635476354863549635506355163552635536355463555635566355763558635596356063561635626356363564635656356663567635686356963570635716357263573635746357563576635776357863579635806358163582635836358463585635866358763588635896359063591635926359363594635956359663597635986359963600636016360263603636046360563606636076360863609636106361163612636136361463615636166361763618636196362063621636226362363624636256362663627636286362963630636316363263633636346363563636636376363863639636406364163642636436364463645636466364763648636496365063651636526365363654636556365663657636586365963660636616366263663636646366563666636676366863669636706367163672636736367463675636766367763678636796368063681636826368363684636856368663687636886368963690636916369263693636946369563696636976369863699637006370163702637036370463705637066370763708637096371063711637126371363714637156371663717637186371963720637216372263723637246372563726637276372863729637306373163732637336373463735637366373763738637396374063741637426374363744637456374663747637486374963750637516375263753637546375563756637576375863759637606376163762637636376463765637666376763768637696377063771637726377363774637756377663777637786377963780637816378263783637846378563786637876378863789637906379163792637936379463795637966379763798637996380063801638026380363804638056380663807638086380963810638116381263813638146381563816638176381863819638206382163822638236382463825638266382763828638296383063831638326383363834638356383663837638386383963840638416384263843638446384563846638476384863849638506385163852638536385463855638566385763858638596386063861638626386363864638656386663867638686386963870638716387263873638746387563876638776387863879638806388163882638836388463885638866388763888638896389063891638926389363894638956389663897638986389963900639016390263903639046390563906639076390863909639106391163912639136391463915639166391763918639196392063921639226392363924639256392663927639286392963930639316393263933639346393563936639376393863939639406394163942639436394463945639466394763948639496395063951639526395363954639556395663957639586395963960639616396263963639646396563966639676396863969639706397163972639736397463975639766397763978639796398063981639826398363984639856398663987639886398963990639916399263993639946399563996639976399863999640006400164002640036400464005640066400764008640096401064011640126401364014640156401664017640186401964020640216402264023640246402564026640276402864029640306403164032640336403464035640366403764038640396404064041640426404364044640456404664047640486404964050640516405264053640546405564056640576405864059640606406164062640636406464065640666406764068640696407064071640726407364074640756407664077640786407964080640816408264083640846408564086640876408864089640906409164092640936409464095640966409764098640996410064101641026410364104641056410664107641086410964110641116411264113641146411564116641176411864119641206412164122641236412464125641266412764128641296413064131641326413364134641356413664137641386413964140641416414264143641446414564146641476414864149641506415164152641536415464155641566415764158641596416064161641626416364164641656416664167641686416964170641716417264173641746417564176641776417864179641806418164182641836418464185641866418764188641896419064191641926419364194641956419664197641986419964200642016420264203642046420564206642076420864209642106421164212642136421464215642166421764218642196422064221642226422364224642256422664227642286422964230642316423264233642346423564236642376423864239642406424164242642436424464245642466424764248642496425064251642526425364254642556425664257642586425964260642616426264263642646426564266642676426864269642706427164272642736427464275642766427764278642796428064281642826428364284642856428664287642886428964290642916429264293642946429564296642976429864299643006430164302643036430464305643066430764308643096431064311643126431364314643156431664317643186431964320643216432264323643246432564326643276432864329643306433164332643336433464335643366433764338643396434064341643426434364344643456434664347643486434964350643516435264353643546435564356643576435864359643606436164362643636436464365643666436764368643696437064371643726437364374643756437664377643786437964380643816438264383643846438564386643876438864389643906439164392643936439464395643966439764398643996440064401644026440364404644056440664407644086440964410644116441264413644146441564416644176441864419644206442164422644236442464425644266442764428644296443064431644326443364434644356443664437644386443964440644416444264443644446444564446644476444864449644506445164452644536445464455644566445764458644596446064461644626446364464644656446664467644686446964470644716447264473644746447564476644776447864479644806448164482644836448464485644866448764488644896449064491644926449364494644956449664497644986449964500645016450264503645046450564506645076450864509645106451164512645136451464515645166451764518645196452064521645226452364524645256452664527645286452964530645316453264533645346453564536645376453864539645406454164542645436454464545645466454764548645496455064551645526455364554645556455664557645586455964560645616456264563645646456564566645676456864569645706457164572645736457464575645766457764578645796458064581645826458364584645856458664587645886458964590645916459264593645946459564596645976459864599646006460164602646036460464605646066460764608646096461064611646126461364614646156461664617646186461964620646216462264623646246462564626646276462864629646306463164632646336463464635646366463764638646396464064641646426464364644646456464664647646486464964650646516465264653646546465564656646576465864659646606466164662646636466464665646666466764668646696467064671646726467364674646756467664677646786467964680646816468264683646846468564686646876468864689646906469164692646936469464695646966469764698646996470064701647026470364704647056470664707647086470964710647116471264713647146471564716647176471864719647206472164722647236472464725647266472764728647296473064731647326473364734647356473664737647386473964740647416474264743647446474564746647476474864749647506475164752647536475464755647566475764758647596476064761647626476364764647656476664767647686476964770647716477264773647746477564776647776477864779647806478164782647836478464785647866478764788647896479064791647926479364794647956479664797647986479964800648016480264803648046480564806648076480864809648106481164812648136481464815648166481764818648196482064821648226482364824648256482664827648286482964830648316483264833648346483564836648376483864839648406484164842648436484464845648466484764848648496485064851648526485364854648556485664857648586485964860648616486264863648646486564866648676486864869648706487164872648736487464875648766487764878648796488064881648826488364884648856488664887648886488964890648916489264893648946489564896648976489864899649006490164902649036490464905649066490764908649096491064911649126491364914649156491664917649186491964920649216492264923649246492564926649276492864929649306493164932649336493464935649366493764938649396494064941649426494364944649456494664947649486494964950649516495264953649546495564956649576495864959649606496164962649636496464965649666496764968649696497064971649726497364974649756497664977649786497964980649816498264983649846498564986649876498864989649906499164992649936499464995649966499764998649996500065001650026500365004650056500665007650086500965010650116501265013650146501565016650176501865019650206502165022650236502465025650266502765028650296503065031650326503365034650356503665037650386503965040650416504265043650446504565046650476504865049650506505165052650536505465055650566505765058650596506065061650626506365064650656506665067650686506965070650716507265073650746507565076650776507865079650806508165082650836508465085650866508765088650896509065091650926509365094650956509665097650986509965100651016510265103651046510565106651076510865109651106511165112651136511465115651166511765118651196512065121651226512365124651256512665127651286512965130651316513265133651346513565136651376513865139651406514165142651436514465145651466514765148651496515065151651526515365154651556515665157651586515965160651616516265163651646516565166651676516865169651706517165172651736517465175651766517765178651796518065181651826518365184651856518665187651886518965190651916519265193651946519565196651976519865199652006520165202652036520465205652066520765208652096521065211652126521365214652156521665217652186521965220652216522265223652246522565226652276522865229652306523165232652336523465235652366523765238652396524065241652426524365244652456524665247652486524965250652516525265253652546525565256652576525865259652606526165262652636526465265652666526765268652696527065271652726527365274652756527665277652786527965280652816528265283652846528565286652876528865289652906529165292652936529465295652966529765298652996530065301653026530365304653056530665307653086530965310653116531265313653146531565316653176531865319653206532165322653236532465325653266532765328653296533065331653326533365334653356533665337653386533965340653416534265343653446534565346653476534865349653506535165352653536535465355653566535765358653596536065361653626536365364653656536665367653686536965370653716537265373653746537565376653776537865379653806538165382653836538465385653866538765388653896539065391653926539365394653956539665397653986539965400654016540265403654046540565406654076540865409654106541165412654136541465415654166541765418654196542065421654226542365424654256542665427654286542965430654316543265433654346543565436654376543865439654406544165442654436544465445654466544765448654496545065451654526545365454654556545665457654586545965460654616546265463654646546565466654676546865469654706547165472654736547465475654766547765478654796548065481654826548365484654856548665487654886548965490654916549265493654946549565496654976549865499655006550165502655036550465505655066550765508655096551065511655126551365514655156551665517655186551965520655216552265523655246552565526655276552865529655306553165532655336553465535655366553765538655396554065541655426554365544655456554665547655486554965550655516555265553655546555565556655576555865559655606556165562655636556465565655666556765568655696557065571655726557365574655756557665577655786557965580655816558265583655846558565586655876558865589655906559165592655936559465595655966559765598655996560065601656026560365604656056560665607656086560965610656116561265613656146561565616656176561865619656206562165622656236562465625656266562765628656296563065631656326563365634656356563665637656386563965640656416564265643656446564565646656476564865649656506565165652656536565465655656566565765658656596566065661656626566365664656656566665667656686566965670656716567265673656746567565676656776567865679656806568165682656836568465685656866568765688656896569065691656926569365694656956569665697656986569965700657016570265703657046570565706657076570865709657106571165712657136571465715657166571765718657196572065721657226572365724657256572665727657286572965730657316573265733657346573565736657376573865739657406574165742657436574465745657466574765748657496575065751657526575365754657556575665757657586575965760657616576265763657646576565766657676576865769657706577165772657736577465775657766577765778657796578065781657826578365784657856578665787657886578965790657916579265793657946579565796657976579865799658006580165802658036580465805658066580765808658096581065811658126581365814658156581665817658186581965820658216582265823658246582565826658276582865829658306583165832658336583465835658366583765838658396584065841658426584365844658456584665847658486584965850658516585265853658546585565856658576585865859658606586165862658636586465865658666586765868658696587065871658726587365874658756587665877658786587965880658816588265883658846588565886658876588865889658906589165892658936589465895658966589765898658996590065901659026590365904659056590665907659086590965910659116591265913659146591565916659176591865919659206592165922659236592465925659266592765928659296593065931659326593365934659356593665937659386593965940659416594265943659446594565946659476594865949659506595165952659536595465955659566595765958659596596065961659626596365964659656596665967659686596965970659716597265973659746597565976659776597865979659806598165982659836598465985659866598765988659896599065991659926599365994659956599665997659986599966000660016600266003660046600566006660076600866009660106601166012660136601466015660166601766018660196602066021660226602366024660256602666027660286602966030660316603266033660346603566036660376603866039660406604166042660436604466045660466604766048660496605066051660526605366054660556605666057660586605966060660616606266063660646606566066660676606866069660706607166072660736607466075660766607766078660796608066081660826608366084660856608666087660886608966090660916609266093660946609566096660976609866099661006610166102661036610466105661066610766108661096611066111661126611366114661156611666117661186611966120661216612266123661246612566126661276612866129661306613166132661336613466135661366613766138661396614066141661426614366144661456614666147661486614966150661516615266153661546615566156661576615866159661606616166162661636616466165661666616766168661696617066171661726617366174661756617666177661786617966180661816618266183661846618566186661876618866189661906619166192661936619466195661966619766198661996620066201662026620366204662056620666207662086620966210662116621266213662146621566216662176621866219662206622166222662236622466225662266622766228662296623066231662326623366234662356623666237662386623966240662416624266243662446624566246662476624866249662506625166252662536625466255662566625766258662596626066261662626626366264662656626666267662686626966270662716627266273662746627566276662776627866279662806628166282662836628466285662866628766288662896629066291662926629366294662956629666297662986629966300663016630266303663046630566306663076630866309663106631166312663136631466315663166631766318663196632066321663226632366324663256632666327663286632966330663316633266333663346633566336663376633866339663406634166342663436634466345663466634766348663496635066351663526635366354663556635666357663586635966360663616636266363663646636566366663676636866369663706637166372663736637466375663766637766378663796638066381663826638366384663856638666387663886638966390663916639266393663946639566396663976639866399664006640166402664036640466405664066640766408664096641066411664126641366414664156641666417664186641966420664216642266423664246642566426664276642866429664306643166432664336643466435664366643766438664396644066441664426644366444664456644666447664486644966450664516645266453664546645566456664576645866459664606646166462664636646466465664666646766468664696647066471664726647366474664756647666477664786647966480664816648266483664846648566486664876648866489664906649166492664936649466495664966649766498664996650066501665026650366504665056650666507665086650966510665116651266513665146651566516665176651866519665206652166522665236652466525665266652766528665296653066531665326653366534665356653666537665386653966540665416654266543665446654566546665476654866549665506655166552665536655466555665566655766558665596656066561665626656366564665656656666567665686656966570665716657266573665746657566576665776657866579665806658166582665836658466585665866658766588665896659066591665926659366594665956659666597665986659966600666016660266603666046660566606666076660866609666106661166612666136661466615666166661766618666196662066621666226662366624666256662666627666286662966630666316663266633666346663566636666376663866639666406664166642666436664466645666466664766648666496665066651666526665366654666556665666657666586665966660666616666266663666646666566666666676666866669666706667166672666736667466675666766667766678666796668066681666826668366684666856668666687666886668966690666916669266693666946669566696666976669866699667006670166702667036670466705667066670766708667096671066711667126671366714667156671666717667186671966720667216672266723667246672566726667276672866729667306673166732667336673466735667366673766738667396674066741667426674366744667456674666747667486674966750667516675266753667546675566756667576675866759667606676166762667636676466765667666676766768667696677066771667726677366774667756677666777667786677966780667816678266783667846678566786667876678866789667906679166792667936679466795667966679766798667996680066801668026680366804668056680666807668086680966810668116681266813668146681566816668176681866819668206682166822668236682466825668266682766828668296683066831668326683366834668356683666837668386683966840668416684266843668446684566846668476684866849668506685166852668536685466855668566685766858668596686066861668626686366864668656686666867668686686966870668716687266873668746687566876668776687866879668806688166882668836688466885668866688766888668896689066891668926689366894668956689666897668986689966900669016690266903669046690566906669076690866909669106691166912669136691466915669166691766918669196692066921669226692366924669256692666927669286692966930669316693266933669346693566936669376693866939669406694166942669436694466945669466694766948669496695066951669526695366954669556695666957669586695966960669616696266963669646696566966669676696866969669706697166972669736697466975669766697766978669796698066981669826698366984669856698666987669886698966990669916699266993669946699566996669976699866999670006700167002670036700467005670066700767008670096701067011670126701367014670156701667017670186701967020670216702267023670246702567026670276702867029670306703167032670336703467035670366703767038670396704067041670426704367044670456704667047670486704967050670516705267053670546705567056670576705867059670606706167062670636706467065670666706767068670696707067071670726707367074670756707667077670786707967080670816708267083670846708567086670876708867089670906709167092670936709467095670966709767098670996710067101671026710367104671056710667107671086710967110671116711267113671146711567116671176711867119671206712167122671236712467125671266712767128671296713067131671326713367134671356713667137671386713967140671416714267143671446714567146671476714867149671506715167152671536715467155671566715767158671596716067161671626716367164671656716667167671686716967170671716717267173671746717567176671776717867179671806718167182671836718467185671866718767188671896719067191671926719367194671956719667197671986719967200672016720267203672046720567206672076720867209672106721167212672136721467215672166721767218672196722067221672226722367224672256722667227672286722967230672316723267233672346723567236672376723867239672406724167242672436724467245672466724767248672496725067251672526725367254672556725667257672586725967260672616726267263672646726567266672676726867269672706727167272672736727467275672766727767278672796728067281672826728367284672856728667287672886728967290672916729267293672946729567296672976729867299673006730167302673036730467305673066730767308673096731067311673126731367314673156731667317673186731967320673216732267323673246732567326673276732867329673306733167332673336733467335673366733767338673396734067341673426734367344673456734667347673486734967350673516735267353673546735567356673576735867359673606736167362673636736467365673666736767368673696737067371673726737367374673756737667377673786737967380673816738267383673846738567386673876738867389673906739167392673936739467395673966739767398673996740067401674026740367404674056740667407674086740967410674116741267413674146741567416674176741867419674206742167422674236742467425674266742767428674296743067431674326743367434674356743667437674386743967440674416744267443674446744567446674476744867449674506745167452674536745467455674566745767458674596746067461674626746367464674656746667467674686746967470674716747267473674746747567476674776747867479674806748167482674836748467485674866748767488674896749067491674926749367494674956749667497674986749967500675016750267503675046750567506675076750867509675106751167512675136751467515675166751767518675196752067521675226752367524675256752667527675286752967530675316753267533675346753567536675376753867539675406754167542675436754467545675466754767548675496755067551675526755367554675556755667557675586755967560675616756267563675646756567566675676756867569675706757167572675736757467575675766757767578675796758067581675826758367584675856758667587675886758967590675916759267593675946759567596675976759867599676006760167602676036760467605676066760767608676096761067611676126761367614676156761667617676186761967620676216762267623676246762567626676276762867629676306763167632676336763467635676366763767638676396764067641676426764367644676456764667647676486764967650676516765267653676546765567656676576765867659676606766167662676636766467665676666766767668676696767067671676726767367674676756767667677676786767967680676816768267683676846768567686676876768867689676906769167692676936769467695676966769767698676996770067701677026770367704677056770667707677086770967710677116771267713677146771567716677176771867719677206772167722677236772467725677266772767728677296773067731677326773367734677356773667737677386773967740677416774267743677446774567746677476774867749677506775167752677536775467755677566775767758677596776067761677626776367764677656776667767677686776967770677716777267773677746777567776677776777867779677806778167782677836778467785677866778767788677896779067791677926779367794677956779667797677986779967800678016780267803678046780567806678076780867809678106781167812678136781467815678166781767818678196782067821678226782367824678256782667827678286782967830678316783267833678346783567836678376783867839678406784167842678436784467845678466784767848678496785067851678526785367854678556785667857678586785967860678616786267863678646786567866678676786867869678706787167872678736787467875678766787767878678796788067881678826788367884678856788667887678886788967890678916789267893678946789567896678976789867899679006790167902679036790467905679066790767908679096791067911679126791367914679156791667917679186791967920679216792267923679246792567926679276792867929679306793167932679336793467935679366793767938679396794067941679426794367944679456794667947679486794967950679516795267953679546795567956679576795867959679606796167962679636796467965679666796767968679696797067971679726797367974679756797667977679786797967980679816798267983679846798567986679876798867989679906799167992679936799467995679966799767998679996800068001680026800368004680056800668007680086800968010680116801268013680146801568016680176801868019680206802168022680236802468025680266802768028680296803068031680326803368034680356803668037680386803968040680416804268043680446804568046680476804868049680506805168052680536805468055680566805768058680596806068061680626806368064680656806668067680686806968070680716807268073680746807568076680776807868079680806808168082680836808468085680866808768088680896809068091680926809368094680956809668097680986809968100681016810268103681046810568106681076810868109681106811168112681136811468115681166811768118681196812068121681226812368124681256812668127681286812968130681316813268133681346813568136681376813868139681406814168142681436814468145681466814768148681496815068151681526815368154681556815668157681586815968160681616816268163681646816568166681676816868169681706817168172681736817468175681766817768178681796818068181681826818368184681856818668187681886818968190681916819268193681946819568196681976819868199682006820168202682036820468205682066820768208682096821068211682126821368214682156821668217682186821968220682216822268223682246822568226682276822868229682306823168232682336823468235682366823768238682396824068241682426824368244682456824668247682486824968250682516825268253682546825568256682576825868259682606826168262682636826468265682666826768268682696827068271682726827368274682756827668277682786827968280682816828268283682846828568286682876828868289682906829168292682936829468295682966829768298682996830068301683026830368304683056830668307683086830968310683116831268313683146831568316683176831868319683206832168322683236832468325683266832768328683296833068331683326833368334683356833668337683386833968340683416834268343683446834568346683476834868349683506835168352683536835468355683566835768358683596836068361683626836368364683656836668367683686836968370683716837268373683746837568376683776837868379683806838168382683836838468385683866838768388683896839068391683926839368394683956839668397683986839968400684016840268403684046840568406684076840868409684106841168412684136841468415684166841768418684196842068421684226842368424684256842668427684286842968430684316843268433684346843568436684376843868439684406844168442684436844468445684466844768448684496845068451684526845368454684556845668457684586845968460684616846268463684646846568466684676846868469684706847168472684736847468475684766847768478684796848068481684826848368484684856848668487684886848968490684916849268493684946849568496684976849868499685006850168502685036850468505685066850768508685096851068511685126851368514685156851668517685186851968520685216852268523685246852568526685276852868529685306853168532685336853468535685366853768538685396854068541685426854368544685456854668547685486854968550685516855268553685546855568556685576855868559685606856168562685636856468565685666856768568685696857068571685726857368574685756857668577685786857968580685816858268583685846858568586685876858868589685906859168592685936859468595685966859768598685996860068601686026860368604686056860668607686086860968610686116861268613686146861568616686176861868619686206862168622686236862468625686266862768628686296863068631686326863368634686356863668637686386863968640686416864268643686446864568646686476864868649686506865168652686536865468655686566865768658686596866068661686626866368664686656866668667686686866968670686716867268673686746867568676686776867868679686806868168682686836868468685686866868768688686896869068691686926869368694686956869668697686986869968700687016870268703687046870568706687076870868709687106871168712687136871468715687166871768718687196872068721687226872368724687256872668727687286872968730687316873268733687346873568736687376873868739687406874168742687436874468745687466874768748687496875068751687526875368754687556875668757687586875968760687616876268763687646876568766687676876868769687706877168772687736877468775687766877768778687796878068781687826878368784687856878668787687886878968790687916879268793687946879568796687976879868799688006880168802688036880468805688066880768808688096881068811688126881368814688156881668817688186881968820688216882268823688246882568826688276882868829688306883168832688336883468835688366883768838688396884068841688426884368844688456884668847688486884968850688516885268853688546885568856688576885868859688606886168862688636886468865688666886768868688696887068871688726887368874688756887668877688786887968880688816888268883688846888568886688876888868889688906889168892688936889468895688966889768898688996890068901689026890368904689056890668907689086890968910689116891268913689146891568916689176891868919689206892168922689236892468925689266892768928689296893068931689326893368934689356893668937689386893968940689416894268943689446894568946689476894868949689506895168952689536895468955689566895768958689596896068961689626896368964689656896668967689686896968970689716897268973689746897568976689776897868979689806898168982689836898468985689866898768988689896899068991689926899368994689956899668997689986899969000690016900269003690046900569006690076900869009690106901169012690136901469015690166901769018690196902069021690226902369024690256902669027690286902969030690316903269033690346903569036690376903869039690406904169042690436904469045690466904769048690496905069051690526905369054690556905669057690586905969060690616906269063690646906569066690676906869069690706907169072690736907469075690766907769078690796908069081690826908369084690856908669087690886908969090690916909269093690946909569096690976909869099691006910169102691036910469105691066910769108691096911069111691126911369114691156911669117691186911969120691216912269123691246912569126691276912869129691306913169132691336913469135691366913769138691396914069141691426914369144691456914669147691486914969150691516915269153691546915569156691576915869159691606916169162691636916469165691666916769168691696917069171691726917369174691756917669177691786917969180691816918269183691846918569186691876918869189691906919169192691936919469195691966919769198691996920069201692026920369204692056920669207692086920969210692116921269213692146921569216692176921869219692206922169222692236922469225692266922769228692296923069231692326923369234692356923669237692386923969240692416924269243692446924569246692476924869249692506925169252692536925469255692566925769258692596926069261692626926369264692656926669267692686926969270692716927269273692746927569276692776927869279692806928169282692836928469285692866928769288692896929069291692926929369294692956929669297692986929969300693016930269303693046930569306693076930869309693106931169312693136931469315693166931769318693196932069321693226932369324693256932669327693286932969330693316933269333693346933569336693376933869339693406934169342693436934469345693466934769348693496935069351693526935369354693556935669357693586935969360693616936269363693646936569366693676936869369693706937169372693736937469375693766937769378693796938069381693826938369384693856938669387693886938969390693916939269393693946939569396693976939869399694006940169402694036940469405694066940769408694096941069411694126941369414694156941669417694186941969420694216942269423694246942569426694276942869429694306943169432694336943469435694366943769438694396944069441694426944369444694456944669447694486944969450694516945269453694546945569456694576945869459694606946169462694636946469465694666946769468694696947069471694726947369474694756947669477694786947969480694816948269483694846948569486694876948869489694906949169492694936949469495694966949769498694996950069501695026950369504695056950669507695086950969510695116951269513695146951569516695176951869519695206952169522695236952469525695266952769528695296953069531695326953369534695356953669537695386953969540695416954269543695446954569546695476954869549695506955169552695536955469555695566955769558695596956069561695626956369564695656956669567695686956969570695716957269573695746957569576695776957869579695806958169582695836958469585695866958769588695896959069591695926959369594695956959669597695986959969600696016960269603696046960569606696076960869609696106961169612696136961469615696166961769618696196962069621696226962369624696256962669627696286962969630696316963269633696346963569636696376963869639696406964169642696436964469645696466964769648696496965069651696526965369654696556965669657696586965969660696616966269663696646966569666696676966869669696706967169672696736967469675696766967769678696796968069681696826968369684696856968669687696886968969690696916969269693696946969569696696976969869699697006970169702697036970469705697066970769708697096971069711697126971369714697156971669717697186971969720697216972269723697246972569726697276972869729697306973169732697336973469735697366973769738697396974069741697426974369744697456974669747697486974969750697516975269753697546975569756697576975869759697606976169762697636976469765697666976769768697696977069771697726977369774697756977669777697786977969780697816978269783697846978569786697876978869789697906979169792697936979469795697966979769798697996980069801698026980369804698056980669807698086980969810698116981269813698146981569816698176981869819698206982169822698236982469825698266982769828698296983069831698326983369834698356983669837698386983969840698416984269843698446984569846698476984869849698506985169852698536985469855698566985769858698596986069861698626986369864698656986669867698686986969870698716987269873698746987569876698776987869879698806988169882698836988469885698866988769888698896989069891698926989369894698956989669897698986989969900699016990269903699046990569906699076990869909699106991169912699136991469915699166991769918699196992069921699226992369924699256992669927699286992969930699316993269933699346993569936699376993869939699406994169942699436994469945699466994769948699496995069951699526995369954699556995669957699586995969960699616996269963699646996569966699676996869969699706997169972699736997469975699766997769978699796998069981699826998369984699856998669987699886998969990699916999269993699946999569996699976999869999700007000170002700037000470005700067000770008700097001070011700127001370014700157001670017700187001970020700217002270023700247002570026700277002870029700307003170032700337003470035700367003770038700397004070041700427004370044700457004670047700487004970050700517005270053700547005570056700577005870059700607006170062700637006470065700667006770068700697007070071700727007370074700757007670077700787007970080700817008270083700847008570086700877008870089700907009170092700937009470095700967009770098700997010070101701027010370104701057010670107701087010970110701117011270113701147011570116701177011870119701207012170122701237012470125701267012770128701297013070131701327013370134701357013670137701387013970140701417014270143701447014570146701477014870149701507015170152701537015470155701567015770158701597016070161701627016370164701657016670167701687016970170701717017270173701747017570176701777017870179701807018170182701837018470185701867018770188701897019070191701927019370194701957019670197701987019970200702017020270203702047020570206702077020870209702107021170212702137021470215702167021770218702197022070221702227022370224702257022670227702287022970230702317023270233702347023570236702377023870239702407024170242702437024470245702467024770248702497025070251702527025370254702557025670257702587025970260702617026270263702647026570266702677026870269702707027170272702737027470275702767027770278702797028070281702827028370284702857028670287702887028970290702917029270293702947029570296702977029870299703007030170302703037030470305703067030770308703097031070311703127031370314703157031670317703187031970320703217032270323703247032570326703277032870329703307033170332703337033470335703367033770338703397034070341703427034370344703457034670347703487034970350703517035270353703547035570356703577035870359703607036170362703637036470365703667036770368703697037070371703727037370374703757037670377703787037970380703817038270383703847038570386703877038870389703907039170392703937039470395703967039770398703997040070401704027040370404704057040670407704087040970410704117041270413704147041570416704177041870419704207042170422704237042470425704267042770428704297043070431704327043370434704357043670437704387043970440704417044270443704447044570446704477044870449704507045170452704537045470455704567045770458704597046070461704627046370464704657046670467704687046970470704717047270473704747047570476704777047870479704807048170482704837048470485704867048770488704897049070491704927049370494704957049670497704987049970500705017050270503705047050570506705077050870509705107051170512705137051470515705167051770518705197052070521705227052370524705257052670527705287052970530705317053270533705347053570536705377053870539705407054170542705437054470545705467054770548705497055070551705527055370554705557055670557705587055970560705617056270563705647056570566705677056870569705707057170572705737057470575705767057770578705797058070581705827058370584705857058670587705887058970590705917059270593705947059570596705977059870599706007060170602706037060470605706067060770608706097061070611706127061370614706157061670617706187061970620706217062270623706247062570626706277062870629706307063170632706337063470635706367063770638706397064070641706427064370644706457064670647706487064970650706517065270653706547065570656706577065870659706607066170662706637066470665706667066770668706697067070671706727067370674706757067670677706787067970680706817068270683706847068570686706877068870689706907069170692706937069470695706967069770698706997070070701707027070370704707057070670707707087070970710707117071270713707147071570716707177071870719707207072170722707237072470725707267072770728707297073070731707327073370734707357073670737707387073970740707417074270743707447074570746707477074870749707507075170752707537075470755707567075770758707597076070761707627076370764707657076670767707687076970770707717077270773707747077570776707777077870779707807078170782707837078470785707867078770788707897079070791707927079370794707957079670797707987079970800708017080270803708047080570806708077080870809708107081170812708137081470815708167081770818708197082070821708227082370824708257082670827708287082970830708317083270833708347083570836708377083870839708407084170842708437084470845708467084770848708497085070851708527085370854708557085670857708587085970860708617086270863708647086570866708677086870869708707087170872708737087470875708767087770878708797088070881708827088370884708857088670887708887088970890708917089270893708947089570896708977089870899709007090170902709037090470905709067090770908709097091070911709127091370914709157091670917709187091970920709217092270923709247092570926709277092870929709307093170932709337093470935709367093770938709397094070941709427094370944709457094670947709487094970950709517095270953709547095570956709577095870959709607096170962709637096470965709667096770968709697097070971709727097370974709757097670977709787097970980709817098270983709847098570986709877098870989709907099170992709937099470995709967099770998709997100071001710027100371004710057100671007710087100971010710117101271013710147101571016710177101871019710207102171022710237102471025710267102771028710297103071031710327103371034710357103671037710387103971040710417104271043710447104571046710477104871049710507105171052710537105471055710567105771058710597106071061710627106371064710657106671067710687106971070710717107271073710747107571076710777107871079710807108171082710837108471085710867108771088710897109071091710927109371094710957109671097710987109971100711017110271103711047110571106711077110871109711107111171112711137111471115711167111771118711197112071121711227112371124711257112671127711287112971130711317113271133711347113571136711377113871139711407114171142711437114471145711467114771148711497115071151711527115371154711557115671157711587115971160711617116271163711647116571166711677116871169711707117171172711737117471175711767117771178711797118071181711827118371184711857118671187711887118971190711917119271193711947119571196711977119871199712007120171202712037120471205712067120771208712097121071211712127121371214712157121671217712187121971220712217122271223712247122571226712277122871229712307123171232712337123471235712367123771238712397124071241712427124371244712457124671247712487124971250712517125271253712547125571256712577125871259712607126171262712637126471265712667126771268712697127071271712727127371274712757127671277712787127971280712817128271283712847128571286712877128871289712907129171292712937129471295712967129771298712997130071301713027130371304713057130671307713087130971310713117131271313713147131571316713177131871319713207132171322713237132471325713267132771328713297133071331713327133371334713357133671337713387133971340713417134271343713447134571346713477134871349713507135171352713537135471355713567135771358713597136071361713627136371364713657136671367713687136971370713717137271373713747137571376713777137871379713807138171382713837138471385713867138771388713897139071391713927139371394713957139671397713987139971400714017140271403714047140571406714077140871409714107141171412714137141471415714167141771418714197142071421714227142371424714257142671427714287142971430714317143271433714347143571436714377143871439714407144171442714437144471445714467144771448714497145071451714527145371454714557145671457714587145971460714617146271463714647146571466714677146871469714707147171472714737147471475714767147771478714797148071481714827148371484714857148671487714887148971490714917149271493714947149571496714977149871499715007150171502715037150471505715067150771508715097151071511715127151371514715157151671517715187151971520715217152271523715247152571526715277152871529715307153171532715337153471535715367153771538715397154071541715427154371544715457154671547715487154971550715517155271553715547155571556715577155871559715607156171562715637156471565715667156771568715697157071571715727157371574715757157671577715787157971580715817158271583715847158571586715877158871589715907159171592715937159471595715967159771598715997160071601716027160371604716057160671607716087160971610716117161271613716147161571616716177161871619716207162171622716237162471625716267162771628716297163071631716327163371634716357163671637716387163971640716417164271643716447164571646716477164871649716507165171652716537165471655716567165771658716597166071661716627166371664716657166671667716687166971670716717167271673716747167571676716777167871679716807168171682716837168471685716867168771688716897169071691716927169371694716957169671697716987169971700717017170271703717047170571706717077170871709717107171171712717137171471715717167171771718717197172071721717227172371724717257172671727717287172971730717317173271733717347173571736717377173871739717407174171742717437174471745717467174771748717497175071751717527175371754717557175671757717587175971760717617176271763717647176571766717677176871769717707177171772717737177471775717767177771778717797178071781717827178371784717857178671787717887178971790717917179271793717947179571796717977179871799718007180171802718037180471805718067180771808718097181071811718127181371814718157181671817718187181971820718217182271823718247182571826718277182871829718307183171832718337183471835718367183771838718397184071841718427184371844718457184671847718487184971850718517185271853718547185571856718577185871859718607186171862718637186471865718667186771868718697187071871718727187371874718757187671877718787187971880718817188271883718847188571886718877188871889718907189171892718937189471895718967189771898718997190071901719027190371904719057190671907719087190971910719117191271913719147191571916719177191871919719207192171922719237192471925719267192771928719297193071931719327193371934719357193671937719387193971940719417194271943719447194571946719477194871949719507195171952719537195471955719567195771958719597196071961719627196371964719657196671967719687196971970719717197271973719747197571976719777197871979719807198171982719837198471985719867198771988719897199071991719927199371994719957199671997719987199972000720017200272003720047200572006720077200872009720107201172012720137201472015720167201772018720197202072021720227202372024720257202672027720287202972030720317203272033720347203572036720377203872039720407204172042720437204472045720467204772048720497205072051720527205372054720557205672057720587205972060720617206272063720647206572066720677206872069720707207172072720737207472075720767207772078720797208072081720827208372084720857208672087720887208972090720917209272093720947209572096720977209872099721007210172102721037210472105721067210772108721097211072111721127211372114721157211672117721187211972120721217212272123721247212572126721277212872129721307213172132721337213472135721367213772138721397214072141721427214372144721457214672147721487214972150721517215272153721547215572156721577215872159721607216172162721637216472165721667216772168721697217072171721727217372174721757217672177721787217972180721817218272183721847218572186721877218872189721907219172192721937219472195721967219772198721997220072201722027220372204722057220672207722087220972210722117221272213722147221572216722177221872219722207222172222722237222472225722267222772228722297223072231722327223372234722357223672237722387223972240722417224272243722447224572246722477224872249722507225172252722537225472255722567225772258722597226072261722627226372264722657226672267722687226972270722717227272273722747227572276722777227872279722807228172282722837228472285722867228772288722897229072291722927229372294722957229672297722987229972300723017230272303723047230572306723077230872309723107231172312723137231472315723167231772318723197232072321723227232372324723257232672327723287232972330723317233272333723347233572336723377233872339723407234172342723437234472345723467234772348723497235072351723527235372354723557235672357723587235972360723617236272363723647236572366723677236872369723707237172372723737237472375723767237772378723797238072381723827238372384723857238672387723887238972390723917239272393723947239572396723977239872399724007240172402724037240472405724067240772408724097241072411724127241372414724157241672417724187241972420724217242272423724247242572426724277242872429724307243172432724337243472435724367243772438724397244072441724427244372444724457244672447724487244972450724517245272453724547245572456724577245872459724607246172462724637246472465724667246772468724697247072471724727247372474724757247672477724787247972480724817248272483724847248572486724877248872489724907249172492724937249472495724967249772498724997250072501725027250372504725057250672507725087250972510725117251272513725147251572516725177251872519725207252172522725237252472525725267252772528725297253072531725327253372534725357253672537725387253972540725417254272543725447254572546725477254872549725507255172552725537255472555725567255772558725597256072561725627256372564725657256672567725687256972570725717257272573725747257572576725777257872579725807258172582725837258472585725867258772588725897259072591725927259372594725957259672597725987259972600726017260272603726047260572606726077260872609726107261172612726137261472615726167261772618726197262072621726227262372624726257262672627726287262972630726317263272633726347263572636726377263872639726407264172642726437264472645726467264772648726497265072651726527265372654726557265672657726587265972660726617266272663726647266572666726677266872669726707267172672726737267472675726767267772678726797268072681726827268372684726857268672687726887268972690726917269272693726947269572696726977269872699727007270172702727037270472705727067270772708727097271072711727127271372714727157271672717727187271972720727217272272723727247272572726727277272872729727307273172732727337273472735727367273772738727397274072741727427274372744727457274672747727487274972750727517275272753727547275572756727577275872759727607276172762727637276472765727667276772768727697277072771727727277372774727757277672777727787277972780727817278272783727847278572786727877278872789727907279172792727937279472795727967279772798727997280072801728027280372804728057280672807728087280972810728117281272813728147281572816728177281872819728207282172822728237282472825728267282772828728297283072831728327283372834728357283672837728387283972840728417284272843728447284572846728477284872849728507285172852728537285472855728567285772858728597286072861728627286372864728657286672867728687286972870728717287272873728747287572876728777287872879728807288172882728837288472885728867288772888728897289072891728927289372894728957289672897728987289972900729017290272903729047290572906729077290872909729107291172912729137291472915729167291772918729197292072921729227292372924729257292672927729287292972930729317293272933729347293572936729377293872939729407294172942729437294472945729467294772948729497295072951729527295372954729557295672957729587295972960729617296272963729647296572966729677296872969729707297172972729737297472975729767297772978729797298072981729827298372984729857298672987729887298972990729917299272993729947299572996729977299872999730007300173002730037300473005730067300773008730097301073011730127301373014730157301673017730187301973020730217302273023730247302573026730277302873029730307303173032730337303473035730367303773038730397304073041730427304373044730457304673047730487304973050730517305273053730547305573056730577305873059730607306173062730637306473065730667306773068730697307073071730727307373074730757307673077730787307973080730817308273083730847308573086730877308873089730907309173092730937309473095730967309773098730997310073101731027310373104731057310673107731087310973110731117311273113731147311573116731177311873119731207312173122731237312473125731267312773128731297313073131731327313373134731357313673137731387313973140731417314273143731447314573146731477314873149731507315173152731537315473155731567315773158731597316073161731627316373164731657316673167731687316973170731717317273173731747317573176731777317873179731807318173182731837318473185731867318773188731897319073191731927319373194731957319673197731987319973200732017320273203732047320573206732077320873209732107321173212732137321473215732167321773218732197322073221732227322373224732257322673227732287322973230732317323273233732347323573236732377323873239732407324173242732437324473245732467324773248732497325073251732527325373254732557325673257732587325973260732617326273263732647326573266732677326873269732707327173272732737327473275732767327773278732797328073281732827328373284732857328673287732887328973290732917329273293732947329573296732977329873299733007330173302733037330473305733067330773308733097331073311733127331373314733157331673317733187331973320733217332273323733247332573326733277332873329733307333173332733337333473335733367333773338733397334073341733427334373344733457334673347733487334973350733517335273353733547335573356733577335873359733607336173362733637336473365733667336773368733697337073371733727337373374733757337673377733787337973380733817338273383733847338573386733877338873389733907339173392733937339473395733967339773398733997340073401734027340373404734057340673407734087340973410734117341273413734147341573416734177341873419734207342173422734237342473425734267342773428734297343073431734327343373434734357343673437734387343973440734417344273443734447344573446734477344873449734507345173452734537345473455734567345773458734597346073461734627346373464734657346673467734687346973470734717347273473734747347573476734777347873479734807348173482734837348473485734867348773488734897349073491734927349373494734957349673497734987349973500735017350273503735047350573506735077350873509735107351173512735137351473515735167351773518735197352073521735227352373524735257352673527735287352973530735317353273533735347353573536735377353873539735407354173542735437354473545735467354773548735497355073551735527355373554735557355673557735587355973560735617356273563735647356573566735677356873569735707357173572735737357473575735767357773578735797358073581735827358373584735857358673587735887358973590735917359273593735947359573596735977359873599736007360173602736037360473605736067360773608736097361073611736127361373614736157361673617736187361973620736217362273623736247362573626736277362873629736307363173632736337363473635736367363773638736397364073641736427364373644736457364673647736487364973650736517365273653736547365573656736577365873659736607366173662736637366473665736667366773668736697367073671736727367373674736757367673677736787367973680736817368273683736847368573686736877368873689736907369173692736937369473695736967369773698736997370073701737027370373704737057370673707737087370973710737117371273713737147371573716737177371873719737207372173722737237372473725737267372773728737297373073731737327373373734737357373673737737387373973740737417374273743737447374573746737477374873749737507375173752737537375473755737567375773758737597376073761737627376373764737657376673767737687376973770737717377273773737747377573776737777377873779737807378173782737837378473785737867378773788737897379073791737927379373794737957379673797737987379973800738017380273803738047380573806738077380873809738107381173812738137381473815738167381773818738197382073821738227382373824738257382673827738287382973830738317383273833738347383573836738377383873839738407384173842738437384473845738467384773848738497385073851738527385373854738557385673857738587385973860738617386273863738647386573866738677386873869738707387173872738737387473875738767387773878738797388073881738827388373884738857388673887738887388973890738917389273893738947389573896738977389873899739007390173902739037390473905739067390773908739097391073911739127391373914739157391673917739187391973920739217392273923739247392573926739277392873929739307393173932739337393473935739367393773938739397394073941739427394373944739457394673947739487394973950739517395273953739547395573956739577395873959739607396173962739637396473965739667396773968739697397073971739727397373974739757397673977739787397973980739817398273983739847398573986739877398873989739907399173992739937399473995739967399773998739997400074001740027400374004740057400674007740087400974010740117401274013740147401574016740177401874019740207402174022740237402474025740267402774028740297403074031740327403374034740357403674037740387403974040740417404274043740447404574046740477404874049740507405174052740537405474055740567405774058740597406074061740627406374064740657406674067740687406974070740717407274073740747407574076740777407874079740807408174082740837408474085740867408774088740897409074091740927409374094740957409674097740987409974100741017410274103741047410574106741077410874109741107411174112741137411474115741167411774118741197412074121741227412374124741257412674127741287412974130741317413274133741347413574136741377413874139741407414174142741437414474145741467414774148741497415074151741527415374154741557415674157741587415974160741617416274163741647416574166741677416874169741707417174172741737417474175741767417774178741797418074181741827418374184741857418674187741887418974190741917419274193741947419574196741977419874199742007420174202742037420474205742067420774208742097421074211742127421374214742157421674217742187421974220742217422274223742247422574226742277422874229742307423174232742337423474235742367423774238742397424074241742427424374244742457424674247742487424974250742517425274253742547425574256742577425874259742607426174262742637426474265742667426774268742697427074271742727427374274742757427674277742787427974280742817428274283742847428574286742877428874289742907429174292742937429474295742967429774298742997430074301743027430374304743057430674307743087430974310743117431274313743147431574316743177431874319743207432174322743237432474325743267432774328743297433074331743327433374334743357433674337743387433974340743417434274343743447434574346743477434874349743507435174352743537435474355743567435774358743597436074361743627436374364743657436674367743687436974370743717437274373743747437574376743777437874379743807438174382743837438474385743867438774388743897439074391743927439374394743957439674397743987439974400744017440274403744047440574406744077440874409744107441174412744137441474415744167441774418744197442074421744227442374424744257442674427744287442974430744317443274433744347443574436744377443874439744407444174442744437444474445744467444774448744497445074451744527445374454744557445674457744587445974460744617446274463744647446574466744677446874469744707447174472744737447474475744767447774478744797448074481744827448374484744857448674487744887448974490744917449274493744947449574496744977449874499745007450174502745037450474505745067450774508745097451074511745127451374514745157451674517745187451974520745217452274523745247452574526745277452874529745307453174532745337453474535745367453774538745397454074541745427454374544745457454674547745487454974550745517455274553745547455574556745577455874559745607456174562745637456474565745667456774568745697457074571745727457374574745757457674577745787457974580745817458274583745847458574586745877458874589745907459174592745937459474595745967459774598745997460074601746027460374604746057460674607746087460974610746117461274613746147461574616746177461874619746207462174622746237462474625746267462774628746297463074631746327463374634746357463674637746387463974640746417464274643746447464574646746477464874649746507465174652746537465474655746567465774658746597466074661746627466374664746657466674667746687466974670746717467274673746747467574676746777467874679746807468174682746837468474685746867468774688746897469074691746927469374694746957469674697746987469974700747017470274703747047470574706747077470874709747107471174712747137471474715747167471774718747197472074721747227472374724747257472674727747287472974730747317473274733747347473574736747377473874739747407474174742747437474474745747467474774748747497475074751747527475374754747557475674757747587475974760747617476274763747647476574766747677476874769747707477174772747737477474775747767477774778747797478074781747827478374784747857478674787747887478974790747917479274793747947479574796747977479874799748007480174802748037480474805748067480774808748097481074811748127481374814748157481674817748187481974820748217482274823748247482574826748277482874829748307483174832748337483474835748367483774838748397484074841748427484374844748457484674847748487484974850748517485274853748547485574856748577485874859748607486174862748637486474865748667486774868748697487074871748727487374874748757487674877748787487974880748817488274883748847488574886748877488874889748907489174892748937489474895748967489774898748997490074901749027490374904749057490674907749087490974910749117491274913749147491574916749177491874919749207492174922749237492474925749267492774928749297493074931749327493374934749357493674937749387493974940749417494274943749447494574946749477494874949749507495174952749537495474955749567495774958749597496074961749627496374964749657496674967749687496974970749717497274973749747497574976749777497874979749807498174982749837498474985749867498774988749897499074991749927499374994749957499674997749987499975000750017500275003750047500575006750077500875009750107501175012750137501475015750167501775018750197502075021750227502375024750257502675027750287502975030750317503275033750347503575036750377503875039750407504175042750437504475045750467504775048750497505075051750527505375054750557505675057750587505975060750617506275063750647506575066750677506875069750707507175072750737507475075750767507775078750797508075081750827508375084750857508675087750887508975090750917509275093750947509575096750977509875099751007510175102751037510475105751067510775108751097511075111751127511375114751157511675117751187511975120751217512275123751247512575126751277512875129751307513175132751337513475135751367513775138751397514075141751427514375144751457514675147751487514975150751517515275153751547515575156751577515875159751607516175162751637516475165751667516775168751697517075171751727517375174751757517675177751787517975180751817518275183751847518575186751877518875189751907519175192751937519475195751967519775198751997520075201752027520375204752057520675207752087520975210752117521275213752147521575216752177521875219752207522175222752237522475225752267522775228752297523075231752327523375234752357523675237752387523975240752417524275243752447524575246752477524875249752507525175252752537525475255752567525775258752597526075261752627526375264752657526675267752687526975270752717527275273752747527575276752777527875279752807528175282752837528475285752867528775288752897529075291752927529375294752957529675297752987529975300753017530275303753047530575306753077530875309753107531175312753137531475315753167531775318753197532075321753227532375324753257532675327753287532975330753317533275333753347533575336753377533875339753407534175342753437534475345753467534775348753497535075351753527535375354753557535675357753587535975360753617536275363753647536575366753677536875369753707537175372753737537475375753767537775378753797538075381753827538375384753857538675387753887538975390753917539275393753947539575396753977539875399754007540175402754037540475405754067540775408754097541075411754127541375414754157541675417754187541975420754217542275423754247542575426754277542875429754307543175432754337543475435754367543775438754397544075441754427544375444754457544675447754487544975450754517545275453754547545575456754577545875459754607546175462754637546475465754667546775468754697547075471754727547375474754757547675477754787547975480754817548275483754847548575486754877548875489754907549175492754937549475495754967549775498754997550075501755027550375504755057550675507755087550975510755117551275513755147551575516755177551875519755207552175522755237552475525755267552775528755297553075531755327553375534755357553675537755387553975540755417554275543755447554575546755477554875549755507555175552755537555475555755567555775558755597556075561755627556375564755657556675567755687556975570755717557275573755747557575576755777557875579755807558175582755837558475585755867558775588755897559075591755927559375594755957559675597755987559975600756017560275603756047560575606756077560875609756107561175612756137561475615756167561775618756197562075621756227562375624756257562675627756287562975630756317563275633756347563575636756377563875639756407564175642756437564475645756467564775648756497565075651756527565375654756557565675657756587565975660756617566275663756647566575666756677566875669756707567175672756737567475675756767567775678756797568075681756827568375684756857568675687756887568975690756917569275693756947569575696756977569875699757007570175702757037570475705757067570775708757097571075711757127571375714757157571675717757187571975720757217572275723757247572575726757277572875729757307573175732757337573475735757367573775738757397574075741757427574375744757457574675747757487574975750757517575275753757547575575756757577575875759757607576175762757637576475765757667576775768757697577075771757727577375774757757577675777757787577975780757817578275783757847578575786757877578875789757907579175792757937579475795757967579775798757997580075801758027580375804758057580675807758087580975810758117581275813758147581575816758177581875819758207582175822758237582475825758267582775828758297583075831758327583375834758357583675837758387583975840758417584275843758447584575846758477584875849758507585175852758537585475855758567585775858758597586075861758627586375864758657586675867758687586975870758717587275873758747587575876758777587875879758807588175882758837588475885758867588775888758897589075891758927589375894758957589675897758987589975900759017590275903759047590575906759077590875909759107591175912759137591475915759167591775918759197592075921759227592375924759257592675927759287592975930759317593275933759347593575936759377593875939759407594175942759437594475945759467594775948759497595075951759527595375954759557595675957759587595975960759617596275963759647596575966759677596875969759707597175972759737597475975759767597775978759797598075981759827598375984759857598675987759887598975990759917599275993759947599575996759977599875999760007600176002760037600476005760067600776008760097601076011760127601376014760157601676017760187601976020760217602276023760247602576026760277602876029760307603176032760337603476035760367603776038760397604076041760427604376044760457604676047760487604976050760517605276053760547605576056760577605876059760607606176062760637606476065760667606776068760697607076071760727607376074760757607676077760787607976080760817608276083760847608576086760877608876089760907609176092760937609476095760967609776098760997610076101761027610376104761057610676107761087610976110761117611276113761147611576116761177611876119761207612176122761237612476125761267612776128761297613076131761327613376134761357613676137761387613976140761417614276143761447614576146761477614876149761507615176152761537615476155761567615776158761597616076161761627616376164761657616676167761687616976170761717617276173761747617576176761777617876179761807618176182761837618476185761867618776188761897619076191761927619376194761957619676197761987619976200762017620276203762047620576206762077620876209762107621176212762137621476215762167621776218762197622076221762227622376224762257622676227762287622976230762317623276233762347623576236762377623876239762407624176242762437624476245762467624776248762497625076251762527625376254762557625676257762587625976260762617626276263762647626576266762677626876269762707627176272762737627476275762767627776278762797628076281762827628376284762857628676287762887628976290762917629276293762947629576296762977629876299763007630176302763037630476305763067630776308763097631076311763127631376314763157631676317763187631976320763217632276323763247632576326763277632876329763307633176332763337633476335763367633776338763397634076341763427634376344763457634676347763487634976350763517635276353763547635576356763577635876359763607636176362763637636476365763667636776368763697637076371763727637376374763757637676377763787637976380763817638276383763847638576386763877638876389763907639176392763937639476395763967639776398763997640076401764027640376404764057640676407764087640976410764117641276413764147641576416764177641876419764207642176422764237642476425764267642776428764297643076431764327643376434764357643676437764387643976440764417644276443764447644576446764477644876449764507645176452764537645476455764567645776458764597646076461764627646376464764657646676467764687646976470764717647276473764747647576476764777647876479764807648176482764837648476485764867648776488764897649076491764927649376494764957649676497764987649976500765017650276503765047650576506765077650876509765107651176512765137651476515765167651776518765197652076521765227652376524765257652676527765287652976530765317653276533765347653576536765377653876539765407654176542765437654476545765467654776548765497655076551765527655376554765557655676557765587655976560765617656276563765647656576566765677656876569765707657176572765737657476575765767657776578765797658076581765827658376584765857658676587765887658976590765917659276593765947659576596765977659876599766007660176602766037660476605766067660776608766097661076611766127661376614766157661676617766187661976620766217662276623766247662576626766277662876629766307663176632766337663476635766367663776638766397664076641766427664376644766457664676647766487664976650766517665276653766547665576656766577665876659766607666176662766637666476665766667666776668766697667076671766727667376674766757667676677766787667976680766817668276683766847668576686766877668876689766907669176692766937669476695766967669776698766997670076701767027670376704767057670676707767087670976710767117671276713767147671576716767177671876719767207672176722767237672476725767267672776728767297673076731767327673376734767357673676737767387673976740767417674276743767447674576746767477674876749767507675176752767537675476755767567675776758767597676076761767627676376764767657676676767767687676976770767717677276773767747677576776767777677876779767807678176782767837678476785767867678776788767897679076791767927679376794767957679676797767987679976800768017680276803768047680576806768077680876809768107681176812768137681476815768167681776818768197682076821768227682376824768257682676827768287682976830768317683276833768347683576836768377683876839768407684176842768437684476845768467684776848768497685076851768527685376854768557685676857768587685976860768617686276863768647686576866768677686876869768707687176872768737687476875768767687776878768797688076881768827688376884768857688676887768887688976890768917689276893768947689576896768977689876899769007690176902769037690476905769067690776908769097691076911769127691376914769157691676917769187691976920769217692276923769247692576926769277692876929769307693176932769337693476935769367693776938769397694076941769427694376944769457694676947769487694976950769517695276953769547695576956769577695876959769607696176962769637696476965769667696776968769697697076971769727697376974769757697676977769787697976980769817698276983769847698576986769877698876989769907699176992769937699476995769967699776998769997700077001770027700377004770057700677007770087700977010770117701277013770147701577016770177701877019770207702177022770237702477025770267702777028770297703077031770327703377034770357703677037770387703977040770417704277043770447704577046770477704877049770507705177052770537705477055770567705777058770597706077061770627706377064770657706677067770687706977070770717707277073770747707577076770777707877079770807708177082770837708477085770867708777088770897709077091770927709377094770957709677097770987709977100771017710277103771047710577106771077710877109771107711177112771137711477115771167711777118771197712077121771227712377124771257712677127771287712977130771317713277133771347713577136771377713877139771407714177142771437714477145771467714777148771497715077151771527715377154771557715677157771587715977160771617716277163771647716577166771677716877169771707717177172771737717477175771767717777178771797718077181771827718377184771857718677187771887718977190771917719277193771947719577196771977719877199772007720177202772037720477205772067720777208772097721077211772127721377214772157721677217772187721977220772217722277223772247722577226772277722877229772307723177232772337723477235772367723777238772397724077241772427724377244772457724677247772487724977250772517725277253772547725577256772577725877259772607726177262772637726477265772667726777268772697727077271772727727377274772757727677277772787727977280772817728277283772847728577286772877728877289772907729177292772937729477295772967729777298772997730077301773027730377304773057730677307773087730977310773117731277313773147731577316773177731877319773207732177322773237732477325773267732777328773297733077331773327733377334773357733677337773387733977340773417734277343773447734577346773477734877349773507735177352773537735477355773567735777358773597736077361773627736377364773657736677367773687736977370773717737277373773747737577376773777737877379773807738177382773837738477385773867738777388773897739077391773927739377394773957739677397773987739977400774017740277403774047740577406774077740877409774107741177412774137741477415774167741777418774197742077421774227742377424774257742677427774287742977430774317743277433774347743577436774377743877439774407744177442774437744477445774467744777448774497745077451774527745377454774557745677457774587745977460774617746277463774647746577466774677746877469774707747177472774737747477475774767747777478774797748077481774827748377484774857748677487774887748977490774917749277493774947749577496774977749877499775007750177502775037750477505775067750777508775097751077511775127751377514775157751677517775187751977520775217752277523775247752577526775277752877529775307753177532775337753477535775367753777538775397754077541775427754377544775457754677547775487754977550775517755277553775547755577556775577755877559775607756177562775637756477565775667756777568775697757077571775727757377574775757757677577775787757977580775817758277583775847758577586775877758877589775907759177592775937759477595775967759777598775997760077601776027760377604776057760677607776087760977610776117761277613776147761577616776177761877619776207762177622776237762477625776267762777628776297763077631776327763377634776357763677637776387763977640776417764277643776447764577646776477764877649776507765177652776537765477655776567765777658776597766077661776627766377664776657766677667776687766977670776717767277673776747767577676776777767877679776807768177682776837768477685776867768777688776897769077691776927769377694776957769677697776987769977700777017770277703777047770577706777077770877709777107771177712777137771477715777167771777718777197772077721777227772377724777257772677727777287772977730777317773277733777347773577736777377773877739777407774177742777437774477745777467774777748777497775077751777527775377754777557775677757777587775977760777617776277763777647776577766777677776877769777707777177772777737777477775777767777777778777797778077781777827778377784777857778677787777887778977790777917779277793777947779577796777977779877799778007780177802778037780477805778067780777808778097781077811778127781377814778157781677817778187781977820778217782277823778247782577826778277782877829778307783177832778337783477835778367783777838778397784077841778427784377844778457784677847778487784977850778517785277853778547785577856778577785877859778607786177862778637786477865778667786777868778697787077871778727787377874778757787677877778787787977880778817788277883778847788577886778877788877889778907789177892778937789477895778967789777898778997790077901779027790377904779057790677907779087790977910779117791277913779147791577916779177791877919779207792177922779237792477925779267792777928779297793077931779327793377934779357793677937779387793977940779417794277943779447794577946779477794877949779507795177952779537795477955779567795777958779597796077961779627796377964779657796677967779687796977970779717797277973779747797577976779777797877979779807798177982779837798477985779867798777988779897799077991779927799377994779957799677997779987799978000780017800278003780047800578006780077800878009780107801178012780137801478015780167801778018780197802078021780227802378024780257802678027780287802978030780317803278033780347803578036780377803878039780407804178042780437804478045780467804778048780497805078051780527805378054780557805678057780587805978060780617806278063780647806578066780677806878069780707807178072780737807478075780767807778078780797808078081780827808378084780857808678087780887808978090780917809278093780947809578096780977809878099781007810178102781037810478105781067810778108781097811078111781127811378114781157811678117781187811978120781217812278123781247812578126781277812878129781307813178132781337813478135781367813778138781397814078141781427814378144781457814678147781487814978150781517815278153781547815578156781577815878159781607816178162781637816478165781667816778168781697817078171781727817378174781757817678177781787817978180781817818278183781847818578186781877818878189781907819178192781937819478195781967819778198781997820078201782027820378204782057820678207782087820978210782117821278213782147821578216782177821878219782207822178222782237822478225782267822778228782297823078231782327823378234782357823678237782387823978240782417824278243782447824578246782477824878249782507825178252782537825478255782567825778258782597826078261782627826378264782657826678267782687826978270782717827278273782747827578276782777827878279782807828178282782837828478285782867828778288782897829078291782927829378294782957829678297782987829978300783017830278303783047830578306783077830878309783107831178312783137831478315783167831778318783197832078321783227832378324783257832678327783287832978330783317833278333783347833578336783377833878339783407834178342783437834478345783467834778348783497835078351783527835378354783557835678357783587835978360783617836278363783647836578366783677836878369783707837178372783737837478375783767837778378783797838078381783827838378384783857838678387783887838978390783917839278393783947839578396783977839878399784007840178402784037840478405784067840778408784097841078411784127841378414784157841678417784187841978420784217842278423784247842578426784277842878429784307843178432784337843478435784367843778438784397844078441784427844378444784457844678447784487844978450784517845278453784547845578456784577845878459784607846178462784637846478465784667846778468784697847078471784727847378474784757847678477784787847978480784817848278483784847848578486784877848878489784907849178492784937849478495784967849778498784997850078501785027850378504785057850678507785087850978510785117851278513785147851578516785177851878519785207852178522785237852478525785267852778528785297853078531785327853378534785357853678537785387853978540785417854278543785447854578546785477854878549785507855178552785537855478555785567855778558785597856078561785627856378564785657856678567785687856978570785717857278573785747857578576785777857878579785807858178582785837858478585785867858778588785897859078591785927859378594785957859678597785987859978600786017860278603786047860578606786077860878609786107861178612786137861478615786167861778618786197862078621786227862378624786257862678627786287862978630786317863278633786347863578636786377863878639786407864178642786437864478645786467864778648786497865078651786527865378654786557865678657786587865978660786617866278663786647866578666786677866878669786707867178672786737867478675786767867778678786797868078681786827868378684786857868678687786887868978690786917869278693786947869578696786977869878699787007870178702787037870478705787067870778708787097871078711787127871378714787157871678717787187871978720787217872278723787247872578726787277872878729787307873178732787337873478735787367873778738787397874078741787427874378744787457874678747787487874978750787517875278753787547875578756787577875878759787607876178762787637876478765787667876778768787697877078771787727877378774787757877678777787787877978780787817878278783787847878578786787877878878789787907879178792787937879478795787967879778798787997880078801788027880378804788057880678807788087880978810788117881278813788147881578816788177881878819788207882178822788237882478825788267882778828788297883078831788327883378834788357883678837788387883978840788417884278843788447884578846788477884878849788507885178852788537885478855788567885778858788597886078861788627886378864788657886678867788687886978870788717887278873788747887578876788777887878879788807888178882788837888478885788867888778888788897889078891788927889378894788957889678897788987889978900789017890278903789047890578906789077890878909789107891178912789137891478915789167891778918789197892078921789227892378924789257892678927789287892978930789317893278933789347893578936789377893878939789407894178942789437894478945789467894778948789497895078951789527895378954789557895678957789587895978960789617896278963789647896578966789677896878969789707897178972789737897478975789767897778978789797898078981789827898378984789857898678987789887898978990789917899278993789947899578996789977899878999790007900179002790037900479005790067900779008790097901079011790127901379014790157901679017790187901979020790217902279023790247902579026790277902879029790307903179032790337903479035790367903779038790397904079041790427904379044790457904679047790487904979050790517905279053790547905579056790577905879059790607906179062790637906479065790667906779068790697907079071790727907379074790757907679077790787907979080790817908279083790847908579086790877908879089790907909179092790937909479095790967909779098790997910079101791027910379104791057910679107791087910979110791117911279113791147911579116791177911879119791207912179122791237912479125791267912779128791297913079131791327913379134791357913679137791387913979140791417914279143791447914579146791477914879149791507915179152791537915479155791567915779158791597916079161791627916379164791657916679167791687916979170791717917279173791747917579176791777917879179791807918179182791837918479185791867918779188791897919079191791927919379194791957919679197791987919979200792017920279203792047920579206792077920879209792107921179212792137921479215792167921779218792197922079221792227922379224792257922679227792287922979230792317923279233792347923579236792377923879239792407924179242792437924479245792467924779248792497925079251792527925379254792557925679257792587925979260792617926279263792647926579266792677926879269792707927179272792737927479275792767927779278792797928079281792827928379284792857928679287792887928979290792917929279293792947929579296792977929879299793007930179302793037930479305793067930779308793097931079311793127931379314793157931679317793187931979320793217932279323793247932579326793277932879329793307933179332793337933479335793367933779338793397934079341793427934379344793457934679347793487934979350793517935279353793547935579356793577935879359793607936179362793637936479365793667936779368793697937079371793727937379374793757937679377793787937979380793817938279383793847938579386793877938879389793907939179392793937939479395793967939779398793997940079401794027940379404794057940679407794087940979410794117941279413794147941579416794177941879419794207942179422794237942479425794267942779428794297943079431794327943379434794357943679437794387943979440794417944279443794447944579446794477944879449794507945179452794537945479455794567945779458794597946079461794627946379464794657946679467794687946979470794717947279473794747947579476794777947879479794807948179482794837948479485794867948779488794897949079491794927949379494794957949679497794987949979500795017950279503795047950579506795077950879509795107951179512795137951479515795167951779518795197952079521795227952379524795257952679527795287952979530795317953279533795347953579536795377953879539795407954179542795437954479545795467954779548795497955079551795527955379554795557955679557795587955979560795617956279563795647956579566795677956879569795707957179572795737957479575795767957779578795797958079581795827958379584795857958679587795887958979590795917959279593795947959579596795977959879599796007960179602796037960479605796067960779608796097961079611796127961379614796157961679617796187961979620796217962279623796247962579626796277962879629796307963179632796337963479635796367963779638796397964079641796427964379644796457964679647796487964979650796517965279653796547965579656796577965879659796607966179662796637966479665796667966779668796697967079671796727967379674796757967679677796787967979680796817968279683796847968579686796877968879689796907969179692796937969479695796967969779698796997970079701797027970379704797057970679707797087970979710797117971279713797147971579716797177971879719797207972179722797237972479725797267972779728797297973079731797327973379734797357973679737797387973979740797417974279743797447974579746797477974879749797507975179752797537975479755797567975779758797597976079761797627976379764797657976679767797687976979770797717977279773797747977579776797777977879779797807978179782797837978479785797867978779788797897979079791797927979379794797957979679797797987979979800798017980279803798047980579806798077980879809798107981179812798137981479815798167981779818798197982079821798227982379824798257982679827798287982979830798317983279833798347983579836798377983879839798407984179842798437984479845798467984779848798497985079851798527985379854798557985679857798587985979860798617986279863798647986579866798677986879869798707987179872798737987479875798767987779878798797988079881798827988379884798857988679887798887988979890798917989279893798947989579896798977989879899799007990179902799037990479905799067990779908799097991079911799127991379914799157991679917799187991979920799217992279923799247992579926799277992879929799307993179932799337993479935799367993779938799397994079941799427994379944799457994679947799487994979950799517995279953799547995579956799577995879959799607996179962799637996479965799667996779968799697997079971799727997379974799757997679977799787997979980799817998279983799847998579986799877998879989799907999179992799937999479995799967999779998799998000080001800028000380004800058000680007800088000980010800118001280013800148001580016800178001880019800208002180022800238002480025800268002780028800298003080031800328003380034800358003680037800388003980040800418004280043800448004580046800478004880049800508005180052800538005480055800568005780058800598006080061800628006380064800658006680067800688006980070800718007280073800748007580076800778007880079800808008180082800838008480085800868008780088800898009080091800928009380094800958009680097800988009980100801018010280103801048010580106801078010880109801108011180112801138011480115801168011780118801198012080121801228012380124801258012680127801288012980130801318013280133801348013580136801378013880139801408014180142801438014480145801468014780148801498015080151801528015380154801558015680157801588015980160801618016280163801648016580166801678016880169801708017180172801738017480175801768017780178801798018080181801828018380184801858018680187801888018980190801918019280193801948019580196801978019880199802008020180202802038020480205802068020780208802098021080211802128021380214802158021680217802188021980220802218022280223802248022580226802278022880229802308023180232802338023480235802368023780238802398024080241802428024380244802458024680247802488024980250802518025280253802548025580256802578025880259802608026180262802638026480265802668026780268802698027080271802728027380274802758027680277802788027980280802818028280283802848028580286802878028880289802908029180292802938029480295802968029780298802998030080301803028030380304803058030680307803088030980310803118031280313803148031580316803178031880319803208032180322803238032480325803268032780328803298033080331803328033380334803358033680337803388033980340803418034280343803448034580346803478034880349803508035180352803538035480355803568035780358803598036080361803628036380364803658036680367803688036980370803718037280373803748037580376803778037880379803808038180382803838038480385803868038780388803898039080391803928039380394803958039680397803988039980400804018040280403804048040580406804078040880409804108041180412804138041480415804168041780418804198042080421804228042380424804258042680427804288042980430804318043280433804348043580436804378043880439804408044180442804438044480445804468044780448804498045080451804528045380454804558045680457804588045980460804618046280463804648046580466804678046880469804708047180472804738047480475804768047780478804798048080481804828048380484804858048680487804888048980490804918049280493804948049580496804978049880499805008050180502805038050480505805068050780508805098051080511805128051380514805158051680517805188051980520805218052280523805248052580526805278052880529805308053180532805338053480535805368053780538805398054080541805428054380544805458054680547805488054980550805518055280553805548055580556805578055880559805608056180562805638056480565805668056780568805698057080571805728057380574805758057680577805788057980580805818058280583805848058580586805878058880589805908059180592805938059480595805968059780598805998060080601806028060380604806058060680607806088060980610806118061280613806148061580616806178061880619806208062180622806238062480625806268062780628806298063080631806328063380634806358063680637806388063980640806418064280643806448064580646806478064880649806508065180652806538065480655806568065780658806598066080661806628066380664806658066680667806688066980670806718067280673806748067580676806778067880679806808068180682806838068480685806868068780688806898069080691806928069380694806958069680697806988069980700807018070280703807048070580706807078070880709807108071180712807138071480715807168071780718807198072080721807228072380724807258072680727807288072980730807318073280733807348073580736807378073880739807408074180742807438074480745807468074780748807498075080751807528075380754807558075680757807588075980760807618076280763807648076580766807678076880769807708077180772807738077480775807768077780778807798078080781807828078380784807858078680787807888078980790807918079280793807948079580796807978079880799808008080180802808038080480805808068080780808808098081080811808128081380814808158081680817808188081980820808218082280823808248082580826808278082880829808308083180832808338083480835808368083780838808398084080841808428084380844808458084680847808488084980850808518085280853808548085580856808578085880859808608086180862808638086480865808668086780868808698087080871808728087380874808758087680877808788087980880808818088280883808848088580886808878088880889808908089180892808938089480895808968089780898808998090080901809028090380904809058090680907809088090980910809118091280913809148091580916809178091880919809208092180922809238092480925809268092780928809298093080931809328093380934809358093680937809388093980940809418094280943809448094580946809478094880949809508095180952809538095480955809568095780958809598096080961809628096380964809658096680967809688096980970809718097280973809748097580976809778097880979809808098180982809838098480985809868098780988809898099080991809928099380994809958099680997809988099981000810018100281003810048100581006810078100881009810108101181012810138101481015810168101781018810198102081021810228102381024810258102681027810288102981030810318103281033810348103581036810378103881039810408104181042810438104481045810468104781048810498105081051810528105381054810558105681057810588105981060810618106281063810648106581066810678106881069810708107181072810738107481075810768107781078810798108081081810828108381084810858108681087810888108981090810918109281093810948109581096810978109881099811008110181102811038110481105811068110781108811098111081111811128111381114811158111681117811188111981120811218112281123811248112581126811278112881129811308113181132811338113481135811368113781138811398114081141811428114381144811458114681147811488114981150811518115281153811548115581156811578115881159811608116181162811638116481165811668116781168811698117081171811728117381174811758117681177811788117981180811818118281183811848118581186811878118881189811908119181192811938119481195811968119781198811998120081201812028120381204812058120681207812088120981210812118121281213812148121581216812178121881219812208122181222812238122481225812268122781228812298123081231812328123381234812358123681237812388123981240812418124281243812448124581246812478124881249812508125181252812538125481255812568125781258812598126081261812628126381264812658126681267812688126981270812718127281273812748127581276812778127881279812808128181282812838128481285812868128781288812898129081291812928129381294812958129681297812988129981300813018130281303813048130581306813078130881309813108131181312813138131481315813168131781318813198132081321813228132381324813258132681327813288132981330813318133281333813348133581336813378133881339813408134181342813438134481345813468134781348813498135081351813528135381354813558135681357813588135981360813618136281363813648136581366813678136881369813708137181372813738137481375813768137781378813798138081381813828138381384813858138681387813888138981390813918139281393813948139581396813978139881399814008140181402814038140481405814068140781408814098141081411814128141381414814158141681417814188141981420814218142281423814248142581426814278142881429814308143181432814338143481435814368143781438814398144081441814428144381444814458144681447814488144981450814518145281453814548145581456814578145881459814608146181462814638146481465814668146781468814698147081471814728147381474814758147681477814788147981480814818148281483814848148581486814878148881489814908149181492814938149481495814968149781498814998150081501815028150381504815058150681507815088150981510815118151281513815148151581516815178151881519815208152181522815238152481525815268152781528815298153081531815328153381534815358153681537815388153981540815418154281543815448154581546815478154881549815508155181552815538155481555815568155781558815598156081561815628156381564815658156681567815688156981570815718157281573815748157581576815778157881579815808158181582815838158481585815868158781588815898159081591815928159381594815958159681597815988159981600816018160281603816048160581606816078160881609816108161181612816138161481615816168161781618816198162081621816228162381624816258162681627816288162981630816318163281633816348163581636816378163881639816408164181642816438164481645816468164781648816498165081651816528165381654816558165681657816588165981660816618166281663816648166581666816678166881669816708167181672816738167481675816768167781678816798168081681816828168381684816858168681687816888168981690816918169281693816948169581696816978169881699817008170181702817038170481705817068170781708817098171081711817128171381714817158171681717817188171981720817218172281723817248172581726817278172881729817308173181732817338173481735817368173781738817398174081741817428174381744817458174681747817488174981750817518175281753817548175581756817578175881759817608176181762817638176481765817668176781768817698177081771817728177381774817758177681777817788177981780817818178281783817848178581786817878178881789817908179181792817938179481795817968179781798817998180081801818028180381804818058180681807818088180981810818118181281813818148181581816818178181881819818208182181822818238182481825818268182781828818298183081831818328183381834818358183681837818388183981840818418184281843818448184581846818478184881849818508185181852818538185481855818568185781858818598186081861818628186381864818658186681867818688186981870818718187281873818748187581876818778187881879818808188181882818838188481885818868188781888818898189081891818928189381894818958189681897818988189981900819018190281903819048190581906819078190881909819108191181912819138191481915819168191781918819198192081921819228192381924819258192681927819288192981930819318193281933819348193581936819378193881939819408194181942819438194481945819468194781948819498195081951819528195381954819558195681957819588195981960819618196281963819648196581966819678196881969819708197181972819738197481975819768197781978819798198081981819828198381984819858198681987819888198981990819918199281993819948199581996819978199881999820008200182002820038200482005820068200782008820098201082011820128201382014820158201682017820188201982020820218202282023820248202582026820278202882029820308203182032820338203482035820368203782038820398204082041820428204382044820458204682047820488204982050820518205282053820548205582056820578205882059820608206182062820638206482065820668206782068820698207082071820728207382074820758207682077820788207982080820818208282083820848208582086820878208882089820908209182092820938209482095820968209782098820998210082101821028210382104821058210682107821088210982110821118211282113821148211582116821178211882119821208212182122821238212482125821268212782128821298213082131821328213382134821358213682137821388213982140821418214282143821448214582146821478214882149821508215182152821538215482155821568215782158821598216082161821628216382164821658216682167821688216982170821718217282173821748217582176821778217882179821808218182182821838218482185821868218782188821898219082191821928219382194821958219682197821988219982200822018220282203822048220582206822078220882209822108221182212822138221482215822168221782218822198222082221822228222382224822258222682227822288222982230822318223282233822348223582236822378223882239822408224182242822438224482245822468224782248822498225082251822528225382254822558225682257822588225982260822618226282263822648226582266822678226882269822708227182272822738227482275822768227782278822798228082281822828228382284822858228682287822888228982290822918229282293822948229582296822978229882299823008230182302823038230482305823068230782308823098231082311823128231382314823158231682317823188231982320823218232282323823248232582326823278232882329823308233182332823338233482335823368233782338823398234082341823428234382344823458234682347823488234982350823518235282353823548235582356823578235882359823608236182362823638236482365823668236782368823698237082371823728237382374823758237682377823788237982380823818238282383823848238582386823878238882389823908239182392823938239482395823968239782398823998240082401824028240382404824058240682407824088240982410824118241282413824148241582416824178241882419824208242182422824238242482425824268242782428824298243082431824328243382434824358243682437824388243982440824418244282443824448244582446824478244882449824508245182452824538245482455824568245782458824598246082461824628246382464824658246682467824688246982470824718247282473824748247582476824778247882479824808248182482824838248482485824868248782488824898249082491824928249382494824958249682497824988249982500825018250282503825048250582506825078250882509825108251182512825138251482515825168251782518825198252082521825228252382524825258252682527825288252982530825318253282533825348253582536825378253882539825408254182542825438254482545825468254782548825498255082551825528255382554825558255682557825588255982560825618256282563825648256582566825678256882569825708257182572825738257482575825768257782578825798258082581825828258382584825858258682587825888258982590825918259282593825948259582596825978259882599826008260182602826038260482605826068260782608826098261082611826128261382614826158261682617826188261982620826218262282623826248262582626826278262882629826308263182632826338263482635826368263782638826398264082641826428264382644826458264682647826488264982650826518265282653826548265582656826578265882659826608266182662826638266482665826668266782668826698267082671826728267382674826758267682677826788267982680826818268282683826848268582686826878268882689826908269182692826938269482695826968269782698826998270082701827028270382704827058270682707827088270982710827118271282713827148271582716827178271882719827208272182722827238272482725827268272782728827298273082731827328273382734827358273682737827388273982740827418274282743827448274582746827478274882749827508275182752827538275482755827568275782758827598276082761827628276382764827658276682767827688276982770827718277282773827748277582776827778277882779827808278182782827838278482785827868278782788827898279082791827928279382794827958279682797827988279982800828018280282803828048280582806828078280882809828108281182812828138281482815828168281782818828198282082821828228282382824828258282682827828288282982830828318283282833828348283582836828378283882839828408284182842828438284482845828468284782848828498285082851828528285382854828558285682857828588285982860828618286282863828648286582866828678286882869828708287182872828738287482875828768287782878828798288082881828828288382884828858288682887828888288982890828918289282893828948289582896828978289882899829008290182902829038290482905829068290782908829098291082911829128291382914829158291682917829188291982920829218292282923829248292582926829278292882929829308293182932829338293482935829368293782938829398294082941829428294382944829458294682947829488294982950829518295282953829548295582956829578295882959829608296182962829638296482965829668296782968829698297082971829728297382974829758297682977829788297982980829818298282983829848298582986829878298882989829908299182992829938299482995829968299782998829998300083001830028300383004830058300683007830088300983010830118301283013830148301583016830178301883019830208302183022830238302483025830268302783028830298303083031830328303383034830358303683037830388303983040830418304283043830448304583046830478304883049830508305183052830538305483055830568305783058830598306083061830628306383064830658306683067830688306983070830718307283073830748307583076830778307883079830808308183082830838308483085830868308783088830898309083091830928309383094830958309683097830988309983100831018310283103831048310583106831078310883109831108311183112831138311483115831168311783118831198312083121831228312383124831258312683127831288312983130831318313283133831348313583136831378313883139831408314183142831438314483145831468314783148831498315083151831528315383154831558315683157831588315983160831618316283163831648316583166831678316883169831708317183172831738317483175831768317783178831798318083181831828318383184831858318683187831888318983190831918319283193831948319583196831978319883199832008320183202832038320483205832068320783208832098321083211832128321383214832158321683217832188321983220832218322283223832248322583226832278322883229832308323183232832338323483235832368323783238832398324083241832428324383244832458324683247832488324983250832518325283253832548325583256832578325883259832608326183262832638326483265832668326783268832698327083271832728327383274832758327683277832788327983280832818328283283832848328583286832878328883289832908329183292832938329483295832968329783298832998330083301833028330383304833058330683307833088330983310833118331283313833148331583316833178331883319833208332183322833238332483325833268332783328833298333083331833328333383334833358333683337833388333983340833418334283343833448334583346833478334883349833508335183352833538335483355833568335783358833598336083361833628336383364833658336683367833688336983370833718337283373833748337583376833778337883379833808338183382833838338483385833868338783388833898339083391833928339383394833958339683397833988339983400834018340283403834048340583406834078340883409834108341183412834138341483415834168341783418834198342083421834228342383424834258342683427834288342983430834318343283433834348343583436834378343883439834408344183442834438344483445834468344783448834498345083451834528345383454834558345683457834588345983460834618346283463834648346583466834678346883469834708347183472834738347483475834768347783478834798348083481834828348383484834858348683487834888348983490834918349283493834948349583496834978349883499835008350183502835038350483505835068350783508835098351083511835128351383514835158351683517835188351983520835218352283523835248352583526835278352883529835308353183532835338353483535835368353783538835398354083541835428354383544835458354683547835488354983550835518355283553835548355583556835578355883559835608356183562835638356483565835668356783568835698357083571835728357383574835758357683577835788357983580835818358283583835848358583586835878358883589835908359183592835938359483595835968359783598835998360083601836028360383604836058360683607836088360983610836118361283613836148361583616836178361883619836208362183622836238362483625836268362783628836298363083631836328363383634836358363683637836388363983640836418364283643836448364583646836478364883649836508365183652836538365483655836568365783658836598366083661836628366383664836658366683667836688366983670836718367283673836748367583676836778367883679836808368183682836838368483685836868368783688836898369083691836928369383694836958369683697836988369983700837018370283703837048370583706837078370883709837108371183712837138371483715837168371783718837198372083721837228372383724837258372683727837288372983730837318373283733837348373583736837378373883739837408374183742837438374483745837468374783748837498375083751837528375383754837558375683757837588375983760837618376283763837648376583766837678376883769837708377183772837738377483775837768377783778837798378083781837828378383784837858378683787837888378983790837918379283793837948379583796837978379883799838008380183802838038380483805838068380783808838098381083811838128381383814838158381683817838188381983820838218382283823838248382583826838278382883829838308383183832838338383483835838368383783838838398384083841838428384383844838458384683847838488384983850838518385283853838548385583856838578385883859838608386183862838638386483865838668386783868838698387083871838728387383874838758387683877838788387983880838818388283883838848388583886838878388883889838908389183892838938389483895838968389783898838998390083901839028390383904839058390683907839088390983910839118391283913839148391583916839178391883919839208392183922839238392483925839268392783928839298393083931839328393383934839358393683937839388393983940839418394283943839448394583946839478394883949839508395183952839538395483955839568395783958839598396083961839628396383964839658396683967839688396983970839718397283973839748397583976839778397883979839808398183982839838398483985839868398783988839898399083991839928399383994839958399683997839988399984000840018400284003840048400584006840078400884009840108401184012840138401484015840168401784018840198402084021840228402384024840258402684027840288402984030840318403284033840348403584036840378403884039840408404184042840438404484045840468404784048840498405084051840528405384054840558405684057840588405984060840618406284063840648406584066840678406884069840708407184072840738407484075840768407784078840798408084081840828408384084840858408684087840888408984090840918409284093840948409584096840978409884099841008410184102841038410484105841068410784108841098411084111841128411384114841158411684117841188411984120841218412284123841248412584126841278412884129841308413184132841338413484135841368413784138841398414084141841428414384144841458414684147841488414984150841518415284153841548415584156841578415884159841608416184162841638416484165841668416784168841698417084171841728417384174841758417684177841788417984180841818418284183841848418584186841878418884189841908419184192841938419484195841968419784198841998420084201842028420384204842058420684207842088420984210842118421284213842148421584216842178421884219842208422184222842238422484225842268422784228842298423084231842328423384234842358423684237842388423984240842418424284243842448424584246842478424884249842508425184252842538425484255842568425784258842598426084261842628426384264842658426684267842688426984270842718427284273842748427584276842778427884279842808428184282842838428484285842868428784288842898429084291842928429384294842958429684297842988429984300843018430284303843048430584306843078430884309843108431184312843138431484315843168431784318843198432084321843228432384324843258432684327843288432984330843318433284333843348433584336843378433884339843408434184342843438434484345843468434784348843498435084351843528435384354843558435684357843588435984360843618436284363843648436584366843678436884369843708437184372843738437484375843768437784378843798438084381843828438384384843858438684387843888438984390843918439284393843948439584396843978439884399844008440184402844038440484405844068440784408844098441084411844128441384414844158441684417844188441984420844218442284423844248442584426844278442884429844308443184432844338443484435844368443784438844398444084441844428444384444844458444684447844488444984450844518445284453844548445584456844578445884459844608446184462844638446484465844668446784468844698447084471844728447384474844758447684477844788447984480844818448284483844848448584486844878448884489844908449184492844938449484495844968449784498844998450084501845028450384504845058450684507845088450984510845118451284513845148451584516845178451884519845208452184522845238452484525845268452784528845298453084531845328453384534845358453684537845388453984540845418454284543845448454584546845478454884549845508455184552845538455484555845568455784558845598456084561845628456384564845658456684567845688456984570845718457284573845748457584576845778457884579845808458184582845838458484585845868458784588845898459084591845928459384594845958459684597845988459984600846018460284603846048460584606846078460884609846108461184612846138461484615846168461784618846198462084621846228462384624846258462684627846288462984630846318463284633846348463584636846378463884639846408464184642846438464484645846468464784648846498465084651846528465384654846558465684657846588465984660846618466284663846648466584666846678466884669846708467184672846738467484675846768467784678846798468084681846828468384684846858468684687846888468984690846918469284693846948469584696846978469884699847008470184702847038470484705847068470784708847098471084711847128471384714847158471684717847188471984720847218472284723847248472584726847278472884729847308473184732847338473484735847368473784738847398474084741847428474384744847458474684747847488474984750847518475284753847548475584756847578475884759847608476184762847638476484765847668476784768847698477084771847728477384774847758477684777847788477984780847818478284783847848478584786847878478884789847908479184792847938479484795847968479784798847998480084801848028480384804848058480684807848088480984810848118481284813848148481584816848178481884819848208482184822848238482484825848268482784828848298483084831848328483384834848358483684837848388483984840848418484284843848448484584846848478484884849848508485184852848538485484855848568485784858848598486084861848628486384864848658486684867848688486984870848718487284873848748487584876848778487884879848808488184882848838488484885848868488784888848898489084891848928489384894848958489684897848988489984900849018490284903849048490584906849078490884909849108491184912849138491484915849168491784918849198492084921849228492384924849258492684927849288492984930849318493284933849348493584936849378493884939849408494184942849438494484945849468494784948849498495084951849528495384954849558495684957849588495984960849618496284963849648496584966849678496884969849708497184972849738497484975849768497784978849798498084981849828498384984849858498684987849888498984990849918499284993849948499584996849978499884999850008500185002850038500485005850068500785008850098501085011850128501385014850158501685017850188501985020850218502285023850248502585026850278502885029850308503185032850338503485035850368503785038850398504085041850428504385044850458504685047850488504985050850518505285053850548505585056850578505885059850608506185062850638506485065850668506785068850698507085071850728507385074850758507685077850788507985080850818508285083850848508585086850878508885089850908509185092850938509485095850968509785098850998510085101851028510385104851058510685107851088510985110851118511285113851148511585116851178511885119851208512185122851238512485125851268512785128851298513085131851328513385134851358513685137851388513985140851418514285143851448514585146851478514885149851508515185152851538515485155851568515785158851598516085161851628516385164851658516685167851688516985170851718517285173851748517585176851778517885179851808518185182851838518485185851868518785188851898519085191851928519385194851958519685197851988519985200852018520285203852048520585206852078520885209852108521185212852138521485215852168521785218852198522085221852228522385224852258522685227852288522985230852318523285233852348523585236852378523885239852408524185242852438524485245852468524785248852498525085251852528525385254852558525685257852588525985260852618526285263852648526585266852678526885269852708527185272852738527485275852768527785278852798528085281852828528385284852858528685287852888528985290852918529285293852948529585296852978529885299853008530185302853038530485305853068530785308853098531085311853128531385314853158531685317853188531985320853218532285323853248532585326853278532885329853308533185332853338533485335853368533785338853398534085341853428534385344853458534685347853488534985350853518535285353853548535585356853578535885359853608536185362853638536485365853668536785368853698537085371853728537385374853758537685377853788537985380853818538285383853848538585386853878538885389853908539185392853938539485395853968539785398853998540085401854028540385404854058540685407854088540985410854118541285413854148541585416854178541885419854208542185422854238542485425854268542785428854298543085431854328543385434854358543685437854388543985440854418544285443854448544585446854478544885449854508545185452854538545485455854568545785458854598546085461854628546385464854658546685467854688546985470854718547285473854748547585476854778547885479854808548185482854838548485485854868548785488854898549085491854928549385494854958549685497854988549985500855018550285503855048550585506855078550885509855108551185512855138551485515855168551785518855198552085521855228552385524855258552685527855288552985530855318553285533855348553585536855378553885539855408554185542855438554485545855468554785548855498555085551855528555385554855558555685557855588555985560855618556285563855648556585566855678556885569855708557185572855738557485575855768557785578855798558085581855828558385584855858558685587855888558985590855918559285593855948559585596855978559885599856008560185602856038560485605856068560785608856098561085611856128561385614856158561685617856188561985620856218562285623856248562585626856278562885629856308563185632856338563485635856368563785638856398564085641856428564385644856458564685647856488564985650856518565285653856548565585656856578565885659856608566185662856638566485665856668566785668856698567085671856728567385674856758567685677856788567985680856818568285683856848568585686856878568885689856908569185692856938569485695856968569785698856998570085701857028570385704857058570685707857088570985710857118571285713857148571585716857178571885719857208572185722857238572485725857268572785728857298573085731857328573385734857358573685737857388573985740857418574285743857448574585746857478574885749857508575185752857538575485755857568575785758857598576085761857628576385764857658576685767857688576985770857718577285773857748577585776857778577885779857808578185782857838578485785857868578785788857898579085791857928579385794857958579685797857988579985800858018580285803858048580585806858078580885809858108581185812858138581485815858168581785818858198582085821858228582385824858258582685827858288582985830858318583285833858348583585836858378583885839858408584185842858438584485845858468584785848858498585085851858528585385854858558585685857858588585985860858618586285863858648586585866858678586885869858708587185872858738587485875858768587785878858798588085881858828588385884858858588685887858888588985890858918589285893858948589585896858978589885899859008590185902859038590485905859068590785908859098591085911859128591385914859158591685917859188591985920859218592285923859248592585926859278592885929859308593185932859338593485935859368593785938859398594085941859428594385944859458594685947859488594985950859518595285953859548595585956859578595885959859608596185962859638596485965859668596785968859698597085971859728597385974859758597685977859788597985980859818598285983859848598585986859878598885989859908599185992859938599485995859968599785998859998600086001860028600386004860058600686007860088600986010860118601286013860148601586016860178601886019860208602186022860238602486025860268602786028860298603086031860328603386034860358603686037860388603986040860418604286043860448604586046860478604886049860508605186052860538605486055860568605786058860598606086061860628606386064860658606686067860688606986070860718607286073860748607586076860778607886079860808608186082860838608486085860868608786088860898609086091860928609386094860958609686097860988609986100861018610286103861048610586106861078610886109861108611186112861138611486115861168611786118861198612086121861228612386124861258612686127861288612986130861318613286133861348613586136861378613886139861408614186142861438614486145861468614786148861498615086151861528615386154861558615686157861588615986160861618616286163861648616586166861678616886169861708617186172861738617486175861768617786178861798618086181861828618386184861858618686187861888618986190861918619286193861948619586196861978619886199862008620186202862038620486205862068620786208862098621086211862128621386214862158621686217862188621986220862218622286223862248622586226862278622886229862308623186232862338623486235862368623786238862398624086241862428624386244862458624686247862488624986250862518625286253862548625586256862578625886259862608626186262862638626486265862668626786268862698627086271862728627386274862758627686277862788627986280862818628286283862848628586286862878628886289862908629186292862938629486295862968629786298862998630086301863028630386304863058630686307863088630986310863118631286313863148631586316863178631886319863208632186322863238632486325863268632786328863298633086331863328633386334863358633686337863388633986340863418634286343863448634586346863478634886349863508635186352863538635486355863568635786358863598636086361863628636386364863658636686367863688636986370863718637286373863748637586376863778637886379863808638186382863838638486385863868638786388863898639086391863928639386394863958639686397863988639986400864018640286403864048640586406864078640886409864108641186412864138641486415864168641786418864198642086421864228642386424864258642686427864288642986430864318643286433864348643586436864378643886439864408644186442864438644486445864468644786448864498645086451864528645386454864558645686457864588645986460864618646286463864648646586466864678646886469864708647186472864738647486475864768647786478864798648086481864828648386484864858648686487864888648986490864918649286493864948649586496864978649886499865008650186502865038650486505865068650786508865098651086511865128651386514865158651686517865188651986520865218652286523865248652586526865278652886529865308653186532865338653486535865368653786538865398654086541865428654386544865458654686547865488654986550865518655286553865548655586556865578655886559865608656186562865638656486565865668656786568865698657086571865728657386574865758657686577865788657986580865818658286583865848658586586865878658886589865908659186592865938659486595865968659786598865998660086601866028660386604866058660686607866088660986610866118661286613866148661586616866178661886619866208662186622866238662486625866268662786628866298663086631866328663386634866358663686637866388663986640866418664286643866448664586646866478664886649866508665186652866538665486655866568665786658866598666086661866628666386664866658666686667866688666986670866718667286673866748667586676866778667886679866808668186682866838668486685866868668786688866898669086691866928669386694866958669686697866988669986700867018670286703867048670586706867078670886709867108671186712867138671486715867168671786718867198672086721867228672386724867258672686727867288672986730867318673286733867348673586736867378673886739867408674186742867438674486745867468674786748867498675086751867528675386754867558675686757867588675986760867618676286763867648676586766867678676886769867708677186772867738677486775867768677786778867798678086781867828678386784867858678686787867888678986790867918679286793867948679586796867978679886799868008680186802868038680486805868068680786808868098681086811868128681386814868158681686817868188681986820868218682286823868248682586826868278682886829868308683186832868338683486835868368683786838868398684086841868428684386844868458684686847868488684986850868518685286853868548685586856868578685886859868608686186862868638686486865868668686786868868698687086871868728687386874868758687686877868788687986880868818688286883868848688586886868878688886889868908689186892868938689486895868968689786898868998690086901869028690386904869058690686907869088690986910869118691286913869148691586916869178691886919869208692186922869238692486925869268692786928869298693086931869328693386934869358693686937869388693986940869418694286943869448694586946869478694886949869508695186952869538695486955869568695786958869598696086961869628696386964869658696686967869688696986970869718697286973869748697586976869778697886979869808698186982869838698486985869868698786988869898699086991869928699386994869958699686997869988699987000870018700287003870048700587006870078700887009870108701187012870138701487015870168701787018870198702087021870228702387024870258702687027870288702987030870318703287033870348703587036870378703887039870408704187042870438704487045870468704787048870498705087051870528705387054870558705687057870588705987060870618706287063870648706587066870678706887069870708707187072870738707487075870768707787078870798708087081870828708387084870858708687087870888708987090870918709287093870948709587096870978709887099871008710187102871038710487105871068710787108871098711087111871128711387114871158711687117871188711987120871218712287123871248712587126871278712887129871308713187132871338713487135871368713787138871398714087141871428714387144871458714687147871488714987150871518715287153871548715587156871578715887159871608716187162871638716487165871668716787168871698717087171871728717387174871758717687177871788717987180871818718287183871848718587186871878718887189871908719187192871938719487195871968719787198871998720087201872028720387204872058720687207872088720987210872118721287213872148721587216872178721887219872208722187222872238722487225872268722787228872298723087231872328723387234872358723687237872388723987240872418724287243872448724587246872478724887249872508725187252872538725487255872568725787258872598726087261872628726387264872658726687267872688726987270872718727287273872748727587276872778727887279872808728187282872838728487285872868728787288872898729087291872928729387294872958729687297872988729987300873018730287303873048730587306873078730887309873108731187312873138731487315873168731787318873198732087321873228732387324873258732687327873288732987330873318733287333873348733587336873378733887339873408734187342873438734487345873468734787348873498735087351873528735387354873558735687357873588735987360873618736287363873648736587366873678736887369873708737187372873738737487375873768737787378873798738087381873828738387384873858738687387873888738987390873918739287393873948739587396873978739887399874008740187402874038740487405874068740787408874098741087411874128741387414874158741687417874188741987420874218742287423874248742587426874278742887429874308743187432874338743487435874368743787438874398744087441874428744387444874458744687447874488744987450874518745287453874548745587456874578745887459874608746187462874638746487465874668746787468874698747087471874728747387474874758747687477874788747987480874818748287483874848748587486874878748887489874908749187492874938749487495874968749787498874998750087501875028750387504875058750687507875088750987510875118751287513875148751587516875178751887519875208752187522875238752487525875268752787528875298753087531875328753387534875358753687537875388753987540875418754287543875448754587546875478754887549875508755187552875538755487555875568755787558875598756087561875628756387564875658756687567875688756987570875718757287573875748757587576875778757887579875808758187582875838758487585875868758787588875898759087591875928759387594875958759687597875988759987600876018760287603876048760587606876078760887609876108761187612876138761487615876168761787618876198762087621876228762387624876258762687627876288762987630876318763287633876348763587636876378763887639876408764187642876438764487645876468764787648876498765087651876528765387654876558765687657876588765987660876618766287663876648766587666876678766887669876708767187672876738767487675876768767787678876798768087681876828768387684876858768687687876888768987690876918769287693876948769587696876978769887699877008770187702877038770487705877068770787708877098771087711877128771387714877158771687717877188771987720877218772287723877248772587726877278772887729877308773187732877338773487735877368773787738877398774087741877428774387744877458774687747877488774987750877518775287753877548775587756877578775887759877608776187762877638776487765877668776787768877698777087771877728777387774877758777687777877788777987780877818778287783877848778587786877878778887789877908779187792877938779487795877968779787798877998780087801878028780387804878058780687807878088780987810878118781287813878148781587816878178781887819878208782187822878238782487825878268782787828878298783087831878328783387834878358783687837878388783987840878418784287843878448784587846878478784887849878508785187852878538785487855878568785787858878598786087861878628786387864878658786687867878688786987870878718787287873878748787587876878778787887879878808788187882878838788487885878868788787888878898789087891878928789387894878958789687897878988789987900879018790287903879048790587906879078790887909879108791187912879138791487915879168791787918879198792087921879228792387924879258792687927879288792987930879318793287933879348793587936879378793887939879408794187942879438794487945879468794787948879498795087951879528795387954879558795687957879588795987960879618796287963879648796587966879678796887969879708797187972879738797487975879768797787978879798798087981879828798387984879858798687987879888798987990879918799287993879948799587996879978799887999880008800188002880038800488005880068800788008880098801088011880128801388014880158801688017880188801988020880218802288023880248802588026880278802888029880308803188032880338803488035880368803788038880398804088041880428804388044880458804688047880488804988050880518805288053880548805588056880578805888059880608806188062880638806488065880668806788068880698807088071880728807388074880758807688077880788807988080880818808288083880848808588086880878808888089880908809188092880938809488095880968809788098880998810088101881028810388104881058810688107881088810988110881118811288113881148811588116881178811888119881208812188122881238812488125881268812788128881298813088131881328813388134881358813688137881388813988140881418814288143881448814588146881478814888149881508815188152881538815488155881568815788158881598816088161881628816388164881658816688167881688816988170881718817288173881748817588176881778817888179881808818188182881838818488185881868818788188881898819088191881928819388194881958819688197881988819988200882018820288203882048820588206882078820888209882108821188212882138821488215882168821788218882198822088221882228822388224882258822688227882288822988230882318823288233882348823588236882378823888239882408824188242882438824488245882468824788248882498825088251882528825388254882558825688257882588825988260882618826288263882648826588266882678826888269882708827188272882738827488275882768827788278882798828088281882828828388284882858828688287882888828988290882918829288293882948829588296882978829888299883008830188302883038830488305883068830788308883098831088311883128831388314883158831688317883188831988320883218832288323883248832588326883278832888329883308833188332883338833488335883368833788338883398834088341883428834388344883458834688347883488834988350883518835288353883548835588356883578835888359883608836188362883638836488365883668836788368883698837088371883728837388374883758837688377883788837988380883818838288383883848838588386883878838888389883908839188392883938839488395883968839788398883998840088401884028840388404884058840688407884088840988410884118841288413884148841588416884178841888419884208842188422884238842488425884268842788428884298843088431884328843388434884358843688437884388843988440884418844288443884448844588446884478844888449884508845188452884538845488455884568845788458884598846088461884628846388464884658846688467884688846988470884718847288473884748847588476884778847888479884808848188482884838848488485884868848788488884898849088491884928849388494884958849688497884988849988500885018850288503885048850588506885078850888509885108851188512885138851488515885168851788518885198852088521885228852388524885258852688527885288852988530885318853288533885348853588536885378853888539885408854188542885438854488545885468854788548885498855088551885528855388554885558855688557885588855988560885618856288563885648856588566885678856888569885708857188572885738857488575885768857788578885798858088581885828858388584885858858688587885888858988590885918859288593885948859588596885978859888599886008860188602886038860488605886068860788608886098861088611886128861388614886158861688617886188861988620886218862288623886248862588626886278862888629886308863188632886338863488635886368863788638886398864088641886428864388644886458864688647886488864988650886518865288653886548865588656886578865888659886608866188662886638866488665886668866788668886698867088671886728867388674886758867688677886788867988680886818868288683886848868588686886878868888689886908869188692886938869488695886968869788698886998870088701887028870388704887058870688707887088870988710887118871288713887148871588716887178871888719887208872188722887238872488725887268872788728887298873088731887328873388734887358873688737887388873988740887418874288743887448874588746887478874888749887508875188752887538875488755887568875788758887598876088761887628876388764887658876688767887688876988770887718877288773887748877588776887778877888779887808878188782887838878488785887868878788788887898879088791887928879388794887958879688797887988879988800888018880288803888048880588806888078880888809888108881188812888138881488815888168881788818888198882088821888228882388824888258882688827888288882988830888318883288833888348883588836888378883888839888408884188842888438884488845888468884788848888498885088851888528885388854888558885688857888588885988860888618886288863888648886588866888678886888869888708887188872888738887488875888768887788878888798888088881888828888388884888858888688887888888888988890888918889288893888948889588896888978889888899889008890188902889038890488905889068890788908889098891088911889128891388914889158891688917889188891988920889218892288923889248892588926889278892888929889308893188932889338893488935889368893788938889398894088941889428894388944889458894688947889488894988950889518895288953889548895588956889578895888959889608896188962889638896488965889668896788968889698897088971889728897388974889758897688977889788897988980889818898288983889848898588986889878898888989889908899188992889938899488995889968899788998889998900089001890028900389004890058900689007890088900989010890118901289013890148901589016890178901889019890208902189022890238902489025890268902789028890298903089031890328903389034890358903689037890388903989040890418904289043890448904589046890478904889049890508905189052890538905489055890568905789058890598906089061890628906389064890658906689067890688906989070890718907289073890748907589076890778907889079890808908189082890838908489085890868908789088890898909089091890928909389094890958909689097890988909989100891018910289103891048910589106891078910889109891108911189112891138911489115891168911789118891198912089121891228912389124891258912689127891288912989130891318913289133891348913589136891378913889139891408914189142891438914489145891468914789148891498915089151891528915389154891558915689157891588915989160891618916289163891648916589166891678916889169891708917189172891738917489175891768917789178891798918089181891828918389184891858918689187891888918989190891918919289193891948919589196891978919889199892008920189202892038920489205892068920789208892098921089211892128921389214892158921689217892188921989220892218922289223892248922589226892278922889229892308923189232892338923489235892368923789238892398924089241892428924389244892458924689247892488924989250892518925289253892548925589256892578925889259892608926189262892638926489265892668926789268892698927089271892728927389274892758927689277892788927989280892818928289283892848928589286892878928889289892908929189292892938929489295892968929789298892998930089301893028930389304893058930689307893088930989310893118931289313893148931589316893178931889319893208932189322893238932489325893268932789328893298933089331893328933389334893358933689337893388933989340893418934289343893448934589346893478934889349893508935189352893538935489355893568935789358893598936089361893628936389364893658936689367893688936989370893718937289373893748937589376893778937889379893808938189382893838938489385893868938789388893898939089391893928939389394893958939689397893988939989400894018940289403894048940589406894078940889409894108941189412894138941489415894168941789418894198942089421894228942389424894258942689427894288942989430894318943289433894348943589436894378943889439894408944189442894438944489445894468944789448894498945089451894528945389454894558945689457894588945989460894618946289463894648946589466894678946889469894708947189472894738947489475894768947789478894798948089481894828948389484894858948689487894888948989490894918949289493894948949589496894978949889499895008950189502895038950489505895068950789508895098951089511895128951389514895158951689517895188951989520895218952289523895248952589526895278952889529895308953189532895338953489535895368953789538895398954089541895428954389544895458954689547895488954989550895518955289553895548955589556895578955889559895608956189562895638956489565895668956789568895698957089571895728957389574895758957689577895788957989580895818958289583895848958589586895878958889589895908959189592895938959489595895968959789598895998960089601896028960389604896058960689607896088960989610896118961289613896148961589616896178961889619896208962189622896238962489625896268962789628896298963089631896328963389634896358963689637896388963989640896418964289643896448964589646896478964889649896508965189652896538965489655896568965789658896598966089661896628966389664896658966689667896688966989670896718967289673896748967589676896778967889679896808968189682896838968489685896868968789688896898969089691896928969389694896958969689697896988969989700897018970289703897048970589706897078970889709897108971189712897138971489715897168971789718897198972089721897228972389724897258972689727897288972989730897318973289733897348973589736897378973889739897408974189742897438974489745897468974789748897498975089751897528975389754897558975689757897588975989760897618976289763897648976589766897678976889769897708977189772897738977489775897768977789778897798978089781897828978389784897858978689787897888978989790897918979289793897948979589796897978979889799898008980189802898038980489805898068980789808898098981089811898128981389814898158981689817898188981989820898218982289823898248982589826898278982889829898308983189832898338983489835898368983789838898398984089841898428984389844898458984689847898488984989850898518985289853898548985589856898578985889859898608986189862898638986489865898668986789868898698987089871898728987389874898758987689877898788987989880898818988289883898848988589886898878988889889898908989189892898938989489895898968989789898898998990089901899028990389904899058990689907899088990989910899118991289913899148991589916899178991889919899208992189922899238992489925899268992789928899298993089931899328993389934899358993689937899388993989940899418994289943899448994589946899478994889949899508995189952899538995489955899568995789958899598996089961899628996389964899658996689967899688996989970899718997289973899748997589976899778997889979899808998189982899838998489985899868998789988899898999089991899928999389994899958999689997899988999990000900019000290003900049000590006900079000890009900109001190012900139001490015900169001790018900199002090021900229002390024900259002690027900289002990030900319003290033900349003590036900379003890039900409004190042900439004490045900469004790048900499005090051900529005390054900559005690057900589005990060900619006290063900649006590066900679006890069900709007190072900739007490075900769007790078900799008090081900829008390084900859008690087900889008990090900919009290093900949009590096900979009890099901009010190102901039010490105901069010790108901099011090111901129011390114901159011690117901189011990120901219012290123901249012590126901279012890129901309013190132901339013490135901369013790138901399014090141901429014390144901459014690147901489014990150901519015290153901549015590156901579015890159901609016190162901639016490165901669016790168901699017090171901729017390174901759017690177901789017990180901819018290183901849018590186901879018890189901909019190192901939019490195901969019790198901999020090201902029020390204902059020690207902089020990210902119021290213902149021590216902179021890219902209022190222902239022490225902269022790228902299023090231902329023390234902359023690237902389023990240902419024290243902449024590246902479024890249902509025190252902539025490255902569025790258902599026090261902629026390264902659026690267902689026990270902719027290273902749027590276902779027890279902809028190282902839028490285902869028790288902899029090291902929029390294902959029690297902989029990300903019030290303903049030590306903079030890309903109031190312903139031490315903169031790318903199032090321903229032390324903259032690327903289032990330903319033290333903349033590336903379033890339903409034190342903439034490345903469034790348903499035090351903529035390354903559035690357903589035990360903619036290363903649036590366903679036890369903709037190372903739037490375903769037790378903799038090381903829038390384903859038690387903889038990390903919039290393903949039590396903979039890399904009040190402904039040490405904069040790408904099041090411904129041390414904159041690417904189041990420904219042290423904249042590426904279042890429904309043190432904339043490435904369043790438904399044090441904429044390444904459044690447904489044990450904519045290453904549045590456904579045890459904609046190462904639046490465904669046790468904699047090471904729047390474904759047690477904789047990480904819048290483904849048590486904879048890489904909049190492904939049490495904969049790498904999050090501905029050390504905059050690507905089050990510905119051290513905149051590516905179051890519905209052190522905239052490525905269052790528905299053090531905329053390534905359053690537905389053990540905419054290543905449054590546905479054890549905509055190552905539055490555905569055790558905599056090561905629056390564905659056690567905689056990570905719057290573905749057590576905779057890579905809058190582905839058490585905869058790588905899059090591905929059390594905959059690597905989059990600906019060290603906049060590606906079060890609906109061190612906139061490615906169061790618906199062090621906229062390624906259062690627906289062990630906319063290633906349063590636906379063890639906409064190642906439064490645906469064790648906499065090651906529065390654906559065690657906589065990660906619066290663906649066590666906679066890669906709067190672906739067490675906769067790678906799068090681906829068390684906859068690687906889068990690906919069290693906949069590696906979069890699907009070190702907039070490705907069070790708907099071090711907129071390714907159071690717907189071990720907219072290723907249072590726907279072890729907309073190732907339073490735907369073790738907399074090741907429074390744907459074690747907489074990750907519075290753907549075590756907579075890759907609076190762907639076490765907669076790768907699077090771907729077390774907759077690777907789077990780907819078290783907849078590786907879078890789907909079190792907939079490795907969079790798907999080090801908029080390804908059080690807908089080990810908119081290813908149081590816908179081890819908209082190822908239082490825908269082790828908299083090831908329083390834908359083690837908389083990840908419084290843908449084590846908479084890849908509085190852908539085490855908569085790858908599086090861908629086390864908659086690867908689086990870908719087290873908749087590876908779087890879908809088190882908839088490885908869088790888908899089090891908929089390894908959089690897908989089990900909019090290903909049090590906909079090890909909109091190912909139091490915909169091790918909199092090921909229092390924909259092690927909289092990930909319093290933909349093590936909379093890939909409094190942909439094490945909469094790948909499095090951909529095390954909559095690957909589095990960909619096290963909649096590966909679096890969909709097190972909739097490975909769097790978909799098090981909829098390984909859098690987909889098990990909919099290993909949099590996909979099890999910009100191002910039100491005910069100791008910099101091011910129101391014910159101691017910189101991020910219102291023910249102591026910279102891029910309103191032910339103491035910369103791038910399104091041910429104391044910459104691047910489104991050910519105291053910549105591056910579105891059910609106191062910639106491065910669106791068910699107091071910729107391074910759107691077910789107991080910819108291083910849108591086910879108891089910909109191092910939109491095910969109791098910999110091101911029110391104911059110691107911089110991110911119111291113911149111591116911179111891119911209112191122911239112491125911269112791128911299113091131911329113391134911359113691137911389113991140911419114291143911449114591146911479114891149911509115191152911539115491155911569115791158911599116091161911629116391164911659116691167911689116991170911719117291173911749117591176911779117891179911809118191182911839118491185911869118791188911899119091191911929119391194911959119691197911989119991200912019120291203912049120591206912079120891209912109121191212912139121491215912169121791218912199122091221912229122391224912259122691227912289122991230912319123291233912349123591236912379123891239912409124191242912439124491245912469124791248912499125091251912529125391254912559125691257912589125991260912619126291263912649126591266912679126891269912709127191272912739127491275912769127791278912799128091281912829128391284912859128691287912889128991290912919129291293912949129591296912979129891299913009130191302913039130491305913069130791308913099131091311913129131391314913159131691317913189131991320913219132291323913249132591326913279132891329913309133191332913339133491335913369133791338913399134091341913429134391344913459134691347913489134991350913519135291353913549135591356913579135891359913609136191362913639136491365913669136791368913699137091371913729137391374913759137691377913789137991380913819138291383913849138591386913879138891389913909139191392913939139491395913969139791398913999140091401914029140391404914059140691407914089140991410914119141291413914149141591416914179141891419914209142191422914239142491425914269142791428914299143091431914329143391434914359143691437914389143991440914419144291443914449144591446914479144891449914509145191452914539145491455914569145791458914599146091461914629146391464914659146691467914689146991470914719147291473914749147591476914779147891479914809148191482914839148491485914869148791488914899149091491914929149391494914959149691497914989149991500915019150291503915049150591506915079150891509915109151191512915139151491515915169151791518915199152091521915229152391524915259152691527915289152991530915319153291533915349153591536915379153891539915409154191542915439154491545915469154791548915499155091551915529155391554915559155691557915589155991560915619156291563915649156591566915679156891569915709157191572915739157491575915769157791578915799158091581915829158391584915859158691587915889158991590915919159291593915949159591596915979159891599916009160191602916039160491605916069160791608916099161091611916129161391614916159161691617916189161991620916219162291623916249162591626916279162891629916309163191632916339163491635916369163791638916399164091641916429164391644916459164691647916489164991650916519165291653916549165591656916579165891659916609166191662916639166491665916669166791668916699167091671916729167391674916759167691677916789167991680916819168291683916849168591686916879168891689916909169191692916939169491695916969169791698916999170091701917029170391704917059170691707917089170991710917119171291713917149171591716917179171891719917209172191722917239172491725917269172791728917299173091731917329173391734917359173691737917389173991740917419174291743917449174591746917479174891749917509175191752917539175491755917569175791758917599176091761917629176391764917659176691767917689176991770917719177291773917749177591776917779177891779917809178191782917839178491785917869178791788917899179091791917929179391794917959179691797917989179991800918019180291803918049180591806918079180891809918109181191812918139181491815918169181791818918199182091821918229182391824918259182691827918289182991830918319183291833918349183591836918379183891839918409184191842918439184491845918469184791848918499185091851918529185391854918559185691857918589185991860918619186291863918649186591866918679186891869918709187191872918739187491875918769187791878918799188091881918829188391884918859188691887918889188991890918919189291893918949189591896918979189891899919009190191902919039190491905919069190791908919099191091911919129191391914919159191691917919189191991920919219192291923919249192591926919279192891929919309193191932919339193491935919369193791938919399194091941919429194391944919459194691947919489194991950919519195291953919549195591956919579195891959919609196191962919639196491965919669196791968919699197091971919729197391974919759197691977919789197991980919819198291983919849198591986919879198891989919909199191992919939199491995919969199791998919999200092001920029200392004920059200692007920089200992010920119201292013920149201592016920179201892019920209202192022920239202492025920269202792028920299203092031920329203392034920359203692037920389203992040920419204292043920449204592046920479204892049920509205192052920539205492055920569205792058920599206092061920629206392064920659206692067920689206992070920719207292073920749207592076920779207892079920809208192082920839208492085920869208792088920899209092091920929209392094920959209692097920989209992100921019210292103921049210592106921079210892109921109211192112921139211492115921169211792118921199212092121921229212392124921259212692127921289212992130921319213292133921349213592136921379213892139921409214192142921439214492145921469214792148921499215092151921529215392154921559215692157921589215992160921619216292163921649216592166921679216892169921709217192172921739217492175921769217792178921799218092181921829218392184921859218692187921889218992190921919219292193921949219592196921979219892199922009220192202922039220492205922069220792208922099221092211922129221392214922159221692217922189221992220922219222292223922249222592226922279222892229922309223192232922339223492235922369223792238922399224092241922429224392244922459224692247922489224992250922519225292253922549225592256922579225892259922609226192262922639226492265922669226792268922699227092271922729227392274922759227692277922789227992280922819228292283922849228592286922879228892289922909229192292922939229492295922969229792298922999230092301923029230392304923059230692307923089230992310923119231292313923149231592316923179231892319923209232192322923239232492325923269232792328923299233092331923329233392334923359233692337923389233992340923419234292343923449234592346923479234892349923509235192352923539235492355923569235792358923599236092361923629236392364923659236692367923689236992370923719237292373923749237592376923779237892379923809238192382923839238492385923869238792388923899239092391923929239392394923959239692397923989239992400924019240292403924049240592406924079240892409924109241192412924139241492415924169241792418924199242092421924229242392424924259242692427924289242992430924319243292433924349243592436924379243892439924409244192442924439244492445924469244792448924499245092451924529245392454924559245692457924589245992460924619246292463924649246592466924679246892469924709247192472924739247492475924769247792478924799248092481924829248392484924859248692487924889248992490924919249292493924949249592496924979249892499925009250192502925039250492505925069250792508925099251092511925129251392514925159251692517925189251992520925219252292523925249252592526925279252892529925309253192532925339253492535925369253792538925399254092541925429254392544925459254692547925489254992550925519255292553925549255592556925579255892559925609256192562925639256492565925669256792568925699257092571925729257392574925759257692577925789257992580925819258292583925849258592586925879258892589925909259192592925939259492595925969259792598925999260092601926029260392604926059260692607926089260992610926119261292613926149261592616926179261892619926209262192622926239262492625926269262792628926299263092631926329263392634926359263692637926389263992640926419264292643926449264592646926479264892649926509265192652926539265492655926569265792658926599266092661926629266392664926659266692667926689266992670926719267292673926749267592676926779267892679926809268192682926839268492685926869268792688926899269092691926929269392694926959269692697926989269992700927019270292703927049270592706927079270892709927109271192712927139271492715927169271792718927199272092721927229272392724927259272692727927289272992730927319273292733927349273592736927379273892739927409274192742927439274492745927469274792748927499275092751927529275392754927559275692757927589275992760927619276292763927649276592766927679276892769927709277192772927739277492775927769277792778927799278092781927829278392784927859278692787927889278992790927919279292793927949279592796927979279892799928009280192802928039280492805928069280792808928099281092811928129281392814928159281692817928189281992820928219282292823928249282592826928279282892829928309283192832928339283492835928369283792838928399284092841928429284392844928459284692847928489284992850928519285292853928549285592856928579285892859928609286192862928639286492865928669286792868928699287092871928729287392874928759287692877928789287992880928819288292883928849288592886928879288892889928909289192892928939289492895928969289792898928999290092901929029290392904929059290692907929089290992910929119291292913929149291592916929179291892919929209292192922929239292492925929269292792928929299293092931929329293392934929359293692937929389293992940929419294292943929449294592946929479294892949929509295192952929539295492955929569295792958929599296092961929629296392964929659296692967929689296992970929719297292973929749297592976929779297892979929809298192982929839298492985929869298792988929899299092991929929299392994929959299692997929989299993000930019300293003930049300593006930079300893009930109301193012930139301493015930169301793018930199302093021930229302393024930259302693027930289302993030930319303293033930349303593036930379303893039930409304193042930439304493045930469304793048930499305093051930529305393054930559305693057930589305993060930619306293063930649306593066930679306893069930709307193072930739307493075930769307793078930799308093081930829308393084930859308693087930889308993090930919309293093930949309593096930979309893099931009310193102931039310493105931069310793108931099311093111931129311393114931159311693117931189311993120931219312293123931249312593126931279312893129931309313193132931339313493135931369313793138931399314093141931429314393144931459314693147931489314993150931519315293153931549315593156931579315893159931609316193162931639316493165931669316793168931699317093171931729317393174931759317693177931789317993180931819318293183931849318593186931879318893189931909319193192931939319493195931969319793198931999320093201932029320393204932059320693207932089320993210932119321293213932149321593216932179321893219932209322193222932239322493225932269322793228932299323093231932329323393234932359323693237932389323993240932419324293243932449324593246932479324893249932509325193252932539325493255932569325793258932599326093261932629326393264932659326693267932689326993270932719327293273932749327593276932779327893279932809328193282932839328493285932869328793288932899329093291932929329393294932959329693297932989329993300933019330293303933049330593306933079330893309933109331193312933139331493315933169331793318933199332093321933229332393324933259332693327933289332993330933319333293333933349333593336933379333893339933409334193342933439334493345933469334793348933499335093351933529335393354933559335693357933589335993360933619336293363933649336593366933679336893369933709337193372933739337493375933769337793378933799338093381933829338393384933859338693387933889338993390933919339293393933949339593396933979339893399934009340193402934039340493405934069340793408934099341093411934129341393414934159341693417934189341993420934219342293423934249342593426934279342893429934309343193432934339343493435934369343793438934399344093441934429344393444934459344693447934489344993450934519345293453934549345593456934579345893459934609346193462934639346493465934669346793468934699347093471934729347393474934759347693477934789347993480934819348293483934849348593486934879348893489934909349193492934939349493495934969349793498934999350093501935029350393504935059350693507935089350993510935119351293513935149351593516935179351893519935209352193522935239352493525935269352793528935299353093531935329353393534935359353693537935389353993540935419354293543935449354593546935479354893549935509355193552935539355493555935569355793558935599356093561935629356393564935659356693567935689356993570935719357293573935749357593576935779357893579935809358193582935839358493585935869358793588935899359093591935929359393594935959359693597935989359993600936019360293603936049360593606936079360893609936109361193612936139361493615936169361793618936199362093621936229362393624936259362693627936289362993630936319363293633936349363593636936379363893639936409364193642936439364493645936469364793648936499365093651936529365393654936559365693657936589365993660936619366293663936649366593666936679366893669936709367193672936739367493675936769367793678936799368093681936829368393684936859368693687936889368993690936919369293693936949369593696936979369893699937009370193702937039370493705937069370793708937099371093711937129371393714937159371693717937189371993720937219372293723937249372593726937279372893729937309373193732937339373493735937369373793738937399374093741937429374393744937459374693747937489374993750937519375293753937549375593756937579375893759937609376193762937639376493765937669376793768937699377093771937729377393774937759377693777937789377993780937819378293783937849378593786937879378893789937909379193792937939379493795937969379793798937999380093801938029380393804938059380693807938089380993810938119381293813938149381593816938179381893819938209382193822938239382493825938269382793828938299383093831938329383393834938359383693837938389383993840938419384293843938449384593846938479384893849938509385193852938539385493855938569385793858938599386093861938629386393864938659386693867938689386993870938719387293873938749387593876938779387893879938809388193882938839388493885938869388793888938899389093891938929389393894938959389693897938989389993900939019390293903939049390593906939079390893909939109391193912939139391493915939169391793918939199392093921939229392393924939259392693927939289392993930939319393293933939349393593936939379393893939939409394193942939439394493945939469394793948939499395093951939529395393954939559395693957939589395993960939619396293963939649396593966939679396893969939709397193972939739397493975939769397793978939799398093981939829398393984939859398693987939889398993990939919399293993939949399593996939979399893999940009400194002940039400494005940069400794008940099401094011940129401394014940159401694017940189401994020940219402294023940249402594026940279402894029940309403194032940339403494035940369403794038940399404094041940429404394044940459404694047940489404994050940519405294053940549405594056940579405894059940609406194062940639406494065940669406794068940699407094071940729407394074940759407694077940789407994080940819408294083940849408594086940879408894089940909409194092940939409494095940969409794098940999410094101941029410394104941059410694107941089410994110941119411294113941149411594116941179411894119941209412194122941239412494125941269412794128941299413094131941329413394134941359413694137941389413994140941419414294143941449414594146941479414894149941509415194152941539415494155941569415794158941599416094161941629416394164941659416694167941689416994170941719417294173941749417594176941779417894179941809418194182941839418494185941869418794188941899419094191941929419394194941959419694197941989419994200942019420294203942049420594206942079420894209942109421194212942139421494215942169421794218942199422094221942229422394224942259422694227942289422994230942319423294233942349423594236942379423894239942409424194242942439424494245942469424794248942499425094251942529425394254942559425694257942589425994260942619426294263942649426594266942679426894269942709427194272942739427494275942769427794278942799428094281942829428394284942859428694287942889428994290942919429294293942949429594296942979429894299943009430194302943039430494305943069430794308943099431094311943129431394314943159431694317943189431994320943219432294323943249432594326943279432894329943309433194332943339433494335943369433794338943399434094341943429434394344943459434694347943489434994350943519435294353943549435594356943579435894359943609436194362943639436494365943669436794368943699437094371943729437394374943759437694377943789437994380943819438294383943849438594386943879438894389943909439194392943939439494395943969439794398943999440094401944029440394404944059440694407944089440994410944119441294413944149441594416944179441894419944209442194422944239442494425944269442794428944299443094431944329443394434944359443694437944389443994440944419444294443944449444594446944479444894449944509445194452944539445494455944569445794458944599446094461944629446394464944659446694467944689446994470944719447294473944749447594476944779447894479944809448194482944839448494485944869448794488944899449094491944929449394494944959449694497944989449994500945019450294503945049450594506945079450894509945109451194512945139451494515945169451794518945199452094521945229452394524945259452694527945289452994530945319453294533945349453594536945379453894539945409454194542945439454494545945469454794548945499455094551945529455394554945559455694557945589455994560945619456294563945649456594566945679456894569945709457194572945739457494575945769457794578945799458094581945829458394584945859458694587945889458994590945919459294593945949459594596945979459894599946009460194602946039460494605946069460794608946099461094611946129461394614946159461694617946189461994620946219462294623946249462594626946279462894629946309463194632946339463494635946369463794638946399464094641946429464394644946459464694647946489464994650946519465294653946549465594656946579465894659946609466194662946639466494665946669466794668946699467094671946729467394674946759467694677946789467994680946819468294683946849468594686946879468894689946909469194692946939469494695946969469794698946999470094701947029470394704947059470694707947089470994710947119471294713947149471594716947179471894719947209472194722947239472494725947269472794728947299473094731947329473394734947359473694737947389473994740947419474294743947449474594746947479474894749947509475194752947539475494755947569475794758947599476094761947629476394764947659476694767947689476994770947719477294773947749477594776947779477894779947809478194782947839478494785947869478794788947899479094791947929479394794947959479694797947989479994800948019480294803948049480594806948079480894809948109481194812948139481494815948169481794818948199482094821948229482394824948259482694827948289482994830948319483294833948349483594836948379483894839948409484194842948439484494845948469484794848948499485094851948529485394854948559485694857948589485994860948619486294863948649486594866948679486894869948709487194872948739487494875948769487794878948799488094881948829488394884948859488694887948889488994890948919489294893948949489594896948979489894899949009490194902949039490494905949069490794908949099491094911949129491394914949159491694917949189491994920949219492294923949249492594926949279492894929949309493194932949339493494935949369493794938949399494094941949429494394944949459494694947949489494994950949519495294953949549495594956949579495894959949609496194962949639496494965949669496794968949699497094971949729497394974949759497694977949789497994980949819498294983949849498594986949879498894989949909499194992949939499494995949969499794998949999500095001950029500395004950059500695007950089500995010950119501295013950149501595016950179501895019950209502195022950239502495025950269502795028950299503095031950329503395034950359503695037950389503995040950419504295043950449504595046950479504895049950509505195052950539505495055950569505795058950599506095061950629506395064950659506695067950689506995070950719507295073950749507595076950779507895079950809508195082950839508495085950869508795088950899509095091950929509395094950959509695097950989509995100951019510295103951049510595106951079510895109951109511195112951139511495115951169511795118951199512095121951229512395124951259512695127951289512995130951319513295133951349513595136951379513895139951409514195142951439514495145951469514795148951499515095151951529515395154951559515695157951589515995160951619516295163951649516595166951679516895169951709517195172951739517495175951769517795178951799518095181951829518395184951859518695187951889518995190951919519295193951949519595196951979519895199952009520195202952039520495205952069520795208952099521095211952129521395214952159521695217952189521995220952219522295223952249522595226952279522895229952309523195232952339523495235952369523795238952399524095241952429524395244952459524695247952489524995250952519525295253952549525595256952579525895259952609526195262952639526495265952669526795268952699527095271952729527395274952759527695277952789527995280952819528295283952849528595286952879528895289952909529195292952939529495295952969529795298952999530095301953029530395304953059530695307953089530995310953119531295313953149531595316953179531895319953209532195322953239532495325953269532795328953299533095331953329533395334953359533695337953389533995340953419534295343953449534595346953479534895349953509535195352953539535495355953569535795358953599536095361953629536395364953659536695367953689536995370953719537295373953749537595376953779537895379953809538195382953839538495385953869538795388953899539095391953929539395394953959539695397953989539995400954019540295403954049540595406954079540895409954109541195412954139541495415954169541795418954199542095421954229542395424954259542695427954289542995430954319543295433954349543595436954379543895439954409544195442954439544495445954469544795448954499545095451954529545395454954559545695457954589545995460954619546295463954649546595466954679546895469954709547195472954739547495475954769547795478954799548095481954829548395484954859548695487954889548995490954919549295493954949549595496954979549895499955009550195502955039550495505955069550795508955099551095511955129551395514955159551695517955189551995520955219552295523955249552595526955279552895529955309553195532955339553495535955369553795538955399554095541955429554395544955459554695547955489554995550955519555295553955549555595556955579555895559955609556195562955639556495565955669556795568955699557095571955729557395574955759557695577955789557995580955819558295583955849558595586955879558895589955909559195592955939559495595955969559795598955999560095601956029560395604956059560695607956089560995610956119561295613956149561595616956179561895619956209562195622956239562495625956269562795628956299563095631956329563395634956359563695637956389563995640956419564295643956449564595646956479564895649956509565195652956539565495655956569565795658956599566095661956629566395664956659566695667956689566995670956719567295673956749567595676956779567895679956809568195682956839568495685956869568795688956899569095691956929569395694956959569695697956989569995700957019570295703957049570595706957079570895709957109571195712957139571495715957169571795718957199572095721957229572395724957259572695727957289572995730957319573295733957349573595736957379573895739957409574195742957439574495745957469574795748957499575095751957529575395754957559575695757957589575995760957619576295763957649576595766957679576895769957709577195772957739577495775957769577795778957799578095781957829578395784957859578695787957889578995790957919579295793957949579595796957979579895799958009580195802958039580495805958069580795808958099581095811958129581395814958159581695817958189581995820958219582295823958249582595826958279582895829958309583195832958339583495835958369583795838958399584095841958429584395844958459584695847958489584995850958519585295853958549585595856958579585895859958609586195862958639586495865958669586795868958699587095871958729587395874958759587695877958789587995880958819588295883958849588595886958879588895889958909589195892958939589495895958969589795898958999590095901959029590395904959059590695907959089590995910959119591295913959149591595916959179591895919959209592195922959239592495925959269592795928959299593095931959329593395934959359593695937959389593995940959419594295943959449594595946959479594895949959509595195952959539595495955959569595795958959599596095961959629596395964959659596695967959689596995970959719597295973959749597595976959779597895979959809598195982959839598495985959869598795988959899599095991959929599395994959959599695997959989599996000960019600296003960049600596006960079600896009960109601196012960139601496015960169601796018960199602096021960229602396024960259602696027960289602996030960319603296033960349603596036960379603896039960409604196042960439604496045960469604796048960499605096051960529605396054960559605696057960589605996060960619606296063960649606596066960679606896069960709607196072960739607496075960769607796078960799608096081960829608396084960859608696087960889608996090960919609296093960949609596096960979609896099961009610196102961039610496105961069610796108961099611096111961129611396114961159611696117961189611996120961219612296123961249612596126961279612896129961309613196132961339613496135961369613796138961399614096141961429614396144961459614696147961489614996150961519615296153961549615596156961579615896159961609616196162961639616496165961669616796168961699617096171961729617396174961759617696177961789617996180961819618296183961849618596186961879618896189961909619196192961939619496195961969619796198961999620096201962029620396204962059620696207962089620996210962119621296213962149621596216962179621896219962209622196222962239622496225962269622796228962299623096231962329623396234962359623696237962389623996240962419624296243962449624596246962479624896249962509625196252962539625496255962569625796258962599626096261962629626396264962659626696267962689626996270962719627296273962749627596276962779627896279962809628196282962839628496285962869628796288962899629096291962929629396294962959629696297962989629996300963019630296303963049630596306963079630896309963109631196312963139631496315963169631796318963199632096321963229632396324963259632696327963289632996330963319633296333963349633596336963379633896339963409634196342963439634496345963469634796348963499635096351963529635396354963559635696357963589635996360963619636296363963649636596366963679636896369963709637196372963739637496375963769637796378963799638096381963829638396384963859638696387963889638996390963919639296393963949639596396963979639896399964009640196402964039640496405964069640796408964099641096411964129641396414964159641696417964189641996420964219642296423964249642596426964279642896429964309643196432964339643496435964369643796438964399644096441964429644396444964459644696447964489644996450964519645296453964549645596456964579645896459964609646196462964639646496465964669646796468964699647096471964729647396474964759647696477964789647996480964819648296483964849648596486964879648896489964909649196492964939649496495964969649796498964999650096501965029650396504965059650696507965089650996510965119651296513965149651596516965179651896519965209652196522965239652496525965269652796528965299653096531965329653396534965359653696537965389653996540965419654296543965449654596546965479654896549965509655196552965539655496555965569655796558965599656096561965629656396564965659656696567965689656996570965719657296573965749657596576965779657896579965809658196582965839658496585965869658796588965899659096591965929659396594965959659696597965989659996600966019660296603966049660596606966079660896609966109661196612966139661496615966169661796618966199662096621966229662396624966259662696627966289662996630966319663296633966349663596636966379663896639966409664196642966439664496645966469664796648966499665096651966529665396654966559665696657966589665996660966619666296663966649666596666966679666896669966709667196672966739667496675966769667796678966799668096681966829668396684966859668696687966889668996690966919669296693966949669596696966979669896699967009670196702967039670496705967069670796708967099671096711967129671396714967159671696717967189671996720967219672296723967249672596726967279672896729967309673196732967339673496735967369673796738967399674096741967429674396744967459674696747967489674996750967519675296753967549675596756967579675896759967609676196762967639676496765967669676796768967699677096771967729677396774967759677696777967789677996780967819678296783967849678596786967879678896789967909679196792967939679496795967969679796798967999680096801968029680396804968059680696807968089680996810968119681296813968149681596816968179681896819968209682196822968239682496825968269682796828968299683096831968329683396834968359683696837968389683996840968419684296843968449684596846968479684896849968509685196852968539685496855968569685796858968599686096861968629686396864968659686696867968689686996870968719687296873968749687596876968779687896879968809688196882968839688496885968869688796888968899689096891968929689396894968959689696897968989689996900969019690296903969049690596906969079690896909969109691196912969139691496915969169691796918969199692096921969229692396924969259692696927969289692996930969319693296933969349693596936969379693896939969409694196942969439694496945969469694796948969499695096951969529695396954969559695696957969589695996960969619696296963969649696596966969679696896969969709697196972969739697496975969769697796978969799698096981969829698396984969859698696987969889698996990969919699296993969949699596996969979699896999970009700197002970039700497005970069700797008970099701097011970129701397014970159701697017970189701997020970219702297023970249702597026970279702897029970309703197032970339703497035970369703797038970399704097041970429704397044970459704697047970489704997050970519705297053970549705597056970579705897059970609706197062970639706497065970669706797068970699707097071970729707397074970759707697077970789707997080970819708297083970849708597086970879708897089970909709197092970939709497095970969709797098970999710097101971029710397104971059710697107971089710997110971119711297113971149711597116971179711897119971209712197122971239712497125971269712797128971299713097131971329713397134971359713697137971389713997140971419714297143971449714597146971479714897149971509715197152971539715497155971569715797158971599716097161971629716397164971659716697167971689716997170971719717297173971749717597176971779717897179971809718197182971839718497185971869718797188971899719097191971929719397194971959719697197971989719997200972019720297203972049720597206972079720897209972109721197212972139721497215972169721797218972199722097221972229722397224972259722697227972289722997230972319723297233972349723597236972379723897239972409724197242972439724497245972469724797248972499725097251972529725397254972559725697257972589725997260972619726297263972649726597266972679726897269972709727197272972739727497275972769727797278972799728097281972829728397284972859728697287972889728997290972919729297293972949729597296972979729897299973009730197302973039730497305973069730797308973099731097311973129731397314973159731697317973189731997320973219732297323973249732597326973279732897329973309733197332973339733497335973369733797338973399734097341973429734397344973459734697347973489734997350973519735297353973549735597356973579735897359973609736197362973639736497365973669736797368973699737097371973729737397374973759737697377973789737997380973819738297383973849738597386973879738897389973909739197392973939739497395973969739797398973999740097401974029740397404974059740697407974089740997410974119741297413974149741597416974179741897419974209742197422974239742497425974269742797428974299743097431974329743397434974359743697437974389743997440974419744297443974449744597446974479744897449974509745197452974539745497455974569745797458974599746097461974629746397464974659746697467974689746997470974719747297473974749747597476974779747897479974809748197482974839748497485974869748797488974899749097491974929749397494974959749697497974989749997500975019750297503975049750597506975079750897509975109751197512975139751497515975169751797518975199752097521975229752397524975259752697527975289752997530975319753297533975349753597536975379753897539975409754197542975439754497545975469754797548975499755097551975529755397554975559755697557975589755997560975619756297563975649756597566975679756897569975709757197572975739757497575975769757797578975799758097581975829758397584975859758697587975889758997590975919759297593975949759597596975979759897599976009760197602976039760497605976069760797608976099761097611976129761397614976159761697617976189761997620976219762297623976249762597626976279762897629976309763197632976339763497635976369763797638976399764097641976429764397644976459764697647976489764997650976519765297653976549765597656976579765897659976609766197662976639766497665976669766797668976699767097671976729767397674976759767697677976789767997680976819768297683976849768597686976879768897689976909769197692976939769497695976969769797698976999770097701977029770397704977059770697707977089770997710977119771297713977149771597716977179771897719977209772197722977239772497725977269772797728977299773097731977329773397734977359773697737977389773997740977419774297743977449774597746977479774897749977509775197752977539775497755977569775797758977599776097761977629776397764977659776697767977689776997770977719777297773977749777597776977779777897779977809778197782977839778497785977869778797788977899779097791977929779397794977959779697797977989779997800978019780297803978049780597806978079780897809978109781197812978139781497815978169781797818978199782097821978229782397824978259782697827978289782997830978319783297833978349783597836978379783897839978409784197842978439784497845978469784797848978499785097851978529785397854978559785697857978589785997860978619786297863978649786597866978679786897869978709787197872978739787497875978769787797878978799788097881978829788397884978859788697887978889788997890978919789297893978949789597896978979789897899979009790197902979039790497905979069790797908979099791097911979129791397914979159791697917979189791997920979219792297923979249792597926979279792897929979309793197932979339793497935979369793797938979399794097941979429794397944979459794697947979489794997950979519795297953979549795597956979579795897959979609796197962979639796497965979669796797968979699797097971979729797397974979759797697977979789797997980979819798297983979849798597986979879798897989979909799197992979939799497995979969799797998979999800098001980029800398004980059800698007980089800998010980119801298013980149801598016980179801898019980209802198022980239802498025980269802798028980299803098031980329803398034980359803698037980389803998040980419804298043980449804598046980479804898049980509805198052980539805498055980569805798058980599806098061980629806398064980659806698067980689806998070980719807298073980749807598076980779807898079980809808198082980839808498085980869808798088980899809098091980929809398094980959809698097980989809998100981019810298103981049810598106981079810898109981109811198112981139811498115981169811798118981199812098121981229812398124981259812698127981289812998130981319813298133981349813598136981379813898139981409814198142981439814498145981469814798148981499815098151981529815398154981559815698157981589815998160981619816298163981649816598166981679816898169981709817198172981739817498175981769817798178981799818098181981829818398184981859818698187981889818998190981919819298193981949819598196981979819898199982009820198202982039820498205982069820798208982099821098211982129821398214982159821698217982189821998220982219822298223982249822598226982279822898229982309823198232982339823498235982369823798238982399824098241982429824398244982459824698247982489824998250982519825298253982549825598256982579825898259982609826198262982639826498265982669826798268982699827098271982729827398274982759827698277982789827998280982819828298283982849828598286982879828898289982909829198292982939829498295982969829798298982999830098301983029830398304983059830698307983089830998310983119831298313983149831598316983179831898319983209832198322983239832498325983269832798328983299833098331983329833398334983359833698337983389833998340983419834298343983449834598346983479834898349983509835198352983539835498355983569835798358983599836098361983629836398364983659836698367983689836998370983719837298373983749837598376983779837898379983809838198382983839838498385983869838798388983899839098391983929839398394983959839698397983989839998400984019840298403984049840598406984079840898409984109841198412984139841498415984169841798418984199842098421984229842398424984259842698427984289842998430984319843298433984349843598436984379843898439984409844198442984439844498445984469844798448984499845098451984529845398454984559845698457984589845998460984619846298463984649846598466984679846898469984709847198472984739847498475984769847798478984799848098481984829848398484984859848698487984889848998490984919849298493984949849598496984979849898499985009850198502985039850498505985069850798508985099851098511985129851398514985159851698517985189851998520985219852298523985249852598526985279852898529985309853198532985339853498535985369853798538985399854098541985429854398544985459854698547985489854998550985519855298553985549855598556985579855898559985609856198562985639856498565985669856798568985699857098571985729857398574985759857698577985789857998580985819858298583985849858598586985879858898589985909859198592985939859498595985969859798598985999860098601986029860398604986059860698607986089860998610986119861298613986149861598616986179861898619986209862198622986239862498625986269862798628986299863098631986329863398634986359863698637986389863998640986419864298643986449864598646986479864898649986509865198652986539865498655986569865798658986599866098661986629866398664986659866698667986689866998670986719867298673986749867598676986779867898679986809868198682986839868498685986869868798688986899869098691986929869398694986959869698697986989869998700987019870298703987049870598706987079870898709987109871198712987139871498715987169871798718987199872098721987229872398724987259872698727987289872998730987319873298733987349873598736987379873898739987409874198742987439874498745987469874798748987499875098751987529875398754987559875698757987589875998760987619876298763987649876598766987679876898769987709877198772987739877498775987769877798778987799878098781987829878398784987859878698787987889878998790987919879298793987949879598796987979879898799988009880198802988039880498805988069880798808988099881098811988129881398814988159881698817988189881998820988219882298823988249882598826988279882898829988309883198832988339883498835988369883798838988399884098841988429884398844988459884698847988489884998850988519885298853988549885598856988579885898859988609886198862988639886498865988669886798868988699887098871988729887398874988759887698877988789887998880988819888298883988849888598886988879888898889988909889198892988939889498895988969889798898988999890098901989029890398904989059890698907989089890998910989119891298913989149891598916989179891898919989209892198922989239892498925989269892798928989299893098931989329893398934989359893698937989389893998940989419894298943989449894598946989479894898949989509895198952989539895498955989569895798958989599896098961989629896398964989659896698967989689896998970989719897298973989749897598976989779897898979989809898198982989839898498985989869898798988989899899098991989929899398994989959899698997989989899999000990019900299003990049900599006990079900899009990109901199012990139901499015990169901799018990199902099021990229902399024990259902699027990289902999030990319903299033990349903599036990379903899039990409904199042990439904499045990469904799048990499905099051990529905399054990559905699057990589905999060990619906299063990649906599066990679906899069990709907199072990739907499075990769907799078990799908099081990829908399084990859908699087990889908999090990919909299093990949909599096990979909899099991009910199102991039910499105991069910799108991099911099111991129911399114991159911699117991189911999120991219912299123991249912599126991279912899129991309913199132991339913499135991369913799138991399914099141991429914399144991459914699147991489914999150991519915299153991549915599156991579915899159991609916199162991639916499165991669916799168991699917099171991729917399174991759917699177991789917999180991819918299183991849918599186991879918899189991909919199192991939919499195991969919799198991999920099201992029920399204992059920699207992089920999210992119921299213992149921599216992179921899219992209922199222992239922499225992269922799228992299923099231992329923399234992359923699237992389923999240992419924299243992449924599246992479924899249992509925199252992539925499255992569925799258992599926099261992629926399264992659926699267992689926999270992719927299273992749927599276992779927899279992809928199282992839928499285992869928799288992899929099291992929929399294992959929699297992989929999300993019930299303993049930599306993079930899309993109931199312993139931499315993169931799318993199932099321993229932399324993259932699327993289932999330993319933299333993349933599336993379933899339993409934199342993439934499345993469934799348993499935099351993529935399354993559935699357993589935999360993619936299363993649936599366993679936899369993709937199372993739937499375993769937799378993799938099381993829938399384993859938699387993889938999390993919939299393993949939599396993979939899399994009940199402994039940499405994069940799408994099941099411994129941399414994159941699417994189941999420994219942299423994249942599426994279942899429994309943199432994339943499435994369943799438994399944099441994429944399444994459944699447994489944999450994519945299453994549945599456994579945899459994609946199462994639946499465994669946799468994699947099471994729947399474994759947699477994789947999480994819948299483994849948599486994879948899489994909949199492994939949499495994969949799498994999950099501995029950399504995059950699507995089950999510995119951299513995149951599516995179951899519995209952199522995239952499525995269952799528995299953099531995329953399534995359953699537995389953999540995419954299543995449954599546995479954899549995509955199552995539955499555995569955799558995599956099561995629956399564995659956699567995689956999570995719957299573995749957599576995779957899579995809958199582995839958499585995869958799588995899959099591995929959399594995959959699597995989959999600996019960299603996049960599606996079960899609996109961199612996139961499615996169961799618996199962099621996229962399624996259962699627996289962999630996319963299633996349963599636996379963899639996409964199642996439964499645996469964799648996499965099651996529965399654996559965699657996589965999660996619966299663996649966599666996679966899669996709967199672996739967499675996769967799678996799968099681996829968399684996859968699687996889968999690996919969299693996949969599696996979969899699997009970199702997039970499705997069970799708997099971099711997129971399714997159971699717997189971999720997219972299723997249972599726997279972899729997309973199732997339973499735997369973799738997399974099741997429974399744997459974699747997489974999750997519975299753997549975599756997579975899759997609976199762997639976499765997669976799768997699977099771997729977399774997759977699777997789977999780997819978299783997849978599786997879978899789997909979199792997939979499795997969979799798997999980099801998029980399804998059980699807998089980999810998119981299813998149981599816998179981899819998209982199822998239982499825998269982799828998299983099831998329983399834998359983699837998389983999840998419984299843998449984599846998479984899849998509985199852998539985499855998569985799858998599986099861998629986399864998659986699867998689986999870998719987299873998749987599876998779987899879998809988199882998839988499885998869988799888998899989099891998929989399894998959989699897998989989999900999019990299903999049990599906999079990899909999109991199912999139991499915999169991799918999199992099921999229992399924999259992699927999289992999930999319993299933999349993599936999379993899939999409994199942999439994499945999469994799948999499995099951999529995399954999559995699957999589995999960999619996299963999649996599966999679996899969999709997199972999739997499975999769997799978999799998099981999829998399984999859998699987999889998999990999919999299993999949999599996999979999899999100000100001100002100003100004100005100006100007100008100009100010100011100012100013100014100015100016100017100018100019100020100021100022100023100024100025100026100027100028100029100030100031100032100033100034100035100036100037100038100039100040100041100042100043100044100045100046100047100048100049100050100051100052100053100054100055100056100057100058100059100060100061100062100063100064100065100066100067100068100069100070100071100072100073100074100075100076100077100078100079100080100081100082100083100084100085100086100087100088100089100090100091100092100093100094100095100096100097100098100099100100100101100102100103100104100105100106100107100108100109100110100111100112100113100114100115100116100117100118100119100120100121100122100123100124100125100126100127100128100129100130100131100132100133100134100135100136100137100138100139100140100141100142100143100144100145100146100147100148100149100150100151100152100153100154100155100156100157100158100159100160100161100162100163100164100165100166100167100168100169100170100171100172100173100174100175100176100177100178100179100180100181100182100183100184100185100186100187100188100189100190100191100192100193100194100195100196100197100198100199100200100201100202100203100204100205100206100207100208100209100210100211100212100213100214100215100216100217100218100219100220100221100222100223100224100225100226100227100228100229100230100231100232100233100234100235100236100237100238100239100240100241100242100243100244100245100246100247100248100249100250100251100252100253100254100255100256100257100258100259100260100261100262100263100264100265100266100267100268100269100270100271100272100273100274100275100276100277100278100279100280100281100282100283100284100285100286100287100288100289100290100291100292100293100294100295100296100297100298100299100300100301100302100303100304100305100306100307100308100309100310100311100312100313100314100315100316100317100318100319100320100321100322100323100324100325100326100327100328100329100330100331100332100333100334100335100336100337100338100339100340100341100342100343100344100345100346100347100348100349100350100351100352100353100354100355100356100357100358100359100360100361100362100363100364100365100366100367100368100369100370100371100372100373100374100375100376100377100378100379100380100381100382100383100384100385100386100387100388100389100390100391100392100393100394100395100396100397100398100399100400100401100402100403100404100405100406100407100408100409100410100411100412100413100414100415100416100417100418100419100420100421100422100423100424100425100426100427100428100429100430100431100432100433100434100435100436100437100438100439100440100441100442100443100444100445100446100447100448100449100450100451100452100453100454100455100456100457100458100459100460100461100462100463100464100465100466100467100468100469100470100471100472100473100474100475100476100477100478100479100480100481100482100483100484100485100486100487100488100489100490100491100492100493100494100495100496100497100498100499100500100501100502100503100504100505100506100507100508100509100510100511100512100513100514100515100516100517100518100519100520100521100522100523100524100525100526100527100528100529100530100531100532100533100534100535100536100537100538100539100540100541100542100543100544100545100546100547100548100549100550100551100552100553100554100555100556100557100558100559100560100561100562100563100564100565100566100567100568100569100570100571100572100573100574100575100576100577100578100579100580100581100582100583100584100585100586100587100588100589100590100591100592100593100594100595100596100597100598100599100600100601100602100603100604100605100606100607100608100609100610100611100612100613100614100615100616100617100618100619100620100621100622100623100624100625100626100627100628100629100630100631100632100633100634100635100636100637100638100639100640100641100642100643100644100645100646100647100648100649100650100651100652100653100654100655100656100657100658100659100660100661100662100663100664100665100666100667100668100669100670100671100672100673100674100675100676100677100678100679100680100681100682100683100684100685100686100687100688100689100690100691100692100693100694100695100696100697100698100699100700100701100702100703100704100705100706100707100708100709100710100711100712100713100714100715100716100717100718100719100720100721100722100723100724100725100726100727100728100729100730100731100732100733100734100735100736100737100738100739100740100741100742100743100744100745100746100747100748100749100750100751100752100753100754100755100756100757100758100759100760100761100762100763100764100765100766100767100768100769100770100771100772100773100774100775100776100777100778100779100780100781100782100783100784100785100786100787100788100789100790100791100792100793100794100795100796100797100798100799100800100801100802100803100804100805100806100807100808100809100810100811100812100813100814100815100816100817100818100819100820100821100822100823100824100825100826100827100828100829100830100831100832100833100834100835100836100837100838100839100840100841100842100843100844100845100846100847100848100849100850100851100852100853100854100855100856100857100858100859100860100861100862100863100864100865100866100867100868100869100870100871100872100873100874100875100876100877100878100879100880100881100882100883100884100885100886100887100888100889100890100891100892100893100894100895100896100897100898100899100900100901100902100903100904100905100906100907100908100909100910100911100912100913100914100915100916100917100918100919100920100921100922100923100924100925100926100927100928100929100930100931100932100933100934100935100936100937100938100939100940100941100942100943100944100945100946100947100948100949100950100951100952100953100954100955100956100957100958100959100960100961100962100963100964100965100966100967100968100969100970100971100972100973100974100975100976100977100978100979100980100981100982100983100984100985100986100987100988100989100990100991100992100993100994100995100996100997100998100999101000101001101002101003101004101005101006101007101008101009101010101011101012101013101014101015101016101017101018101019101020101021101022101023101024101025101026101027101028101029101030101031101032101033101034101035101036101037101038101039101040101041101042101043101044101045101046101047101048101049101050101051101052101053101054101055101056101057101058101059101060101061101062101063101064101065101066101067101068101069101070101071101072101073101074101075101076101077101078101079101080101081101082101083101084101085101086101087101088101089101090101091101092101093101094101095101096101097101098101099101100101101101102101103101104101105101106101107101108101109101110101111101112101113101114101115101116101117101118101119101120101121101122101123101124101125101126101127101128101129101130101131101132101133101134101135101136101137101138101139101140101141101142101143101144101145101146101147101148101149101150101151101152101153101154101155101156101157101158101159101160101161101162101163101164101165101166101167101168101169101170101171101172101173101174101175101176101177101178101179101180101181101182101183101184101185101186101187101188101189101190101191101192101193101194101195101196101197101198101199101200101201101202101203101204101205101206101207101208101209101210101211101212101213101214101215101216101217101218101219101220101221101222101223101224101225101226101227101228101229101230101231101232101233101234101235101236101237101238101239101240101241101242101243101244101245101246101247101248101249101250101251101252101253101254101255101256101257101258101259101260101261101262101263101264101265101266101267101268101269101270101271101272101273101274101275101276101277101278101279101280101281101282101283101284101285101286101287101288101289101290101291101292101293101294101295101296101297101298101299101300101301101302101303101304101305101306101307101308101309101310101311101312101313101314101315101316101317101318101319101320101321101322101323101324101325101326101327101328101329101330101331101332101333101334101335101336101337101338101339101340101341101342101343101344101345101346101347101348101349101350101351101352101353101354101355101356101357101358101359101360101361101362101363101364101365101366101367101368101369101370101371101372101373101374101375101376101377101378101379101380101381101382101383101384101385101386101387101388101389101390101391101392101393101394101395101396101397101398101399101400101401101402101403101404101405101406101407101408101409101410101411101412101413101414101415101416101417101418101419101420101421101422101423101424101425101426101427101428101429101430101431101432101433101434101435101436101437101438101439101440101441101442101443101444101445101446101447101448101449101450101451101452101453101454101455101456101457101458101459101460101461101462101463101464101465101466101467101468101469101470101471101472101473101474101475101476101477101478101479101480101481101482101483101484101485101486101487101488101489101490101491101492101493101494101495101496101497101498101499101500101501101502101503101504101505101506101507101508101509101510101511101512101513101514101515101516101517101518101519101520101521101522101523101524101525101526101527101528101529101530101531101532101533101534101535101536101537101538101539101540101541101542101543101544101545101546101547101548101549101550101551101552101553101554101555101556101557101558101559101560101561101562101563101564101565101566101567101568101569101570101571101572101573101574101575101576101577101578101579101580101581101582101583101584101585101586101587101588101589101590101591101592101593101594101595101596101597101598101599101600101601101602101603101604101605101606101607101608101609101610101611101612101613101614101615101616101617101618101619101620101621101622101623101624101625101626101627101628101629101630101631101632101633101634101635101636101637101638101639101640101641101642101643101644101645101646101647101648101649101650101651101652101653101654101655101656101657101658101659101660101661101662101663101664101665101666101667101668101669101670101671101672101673101674101675101676101677101678101679101680101681101682101683101684101685101686101687101688101689101690101691101692101693101694101695101696101697101698101699101700101701101702101703101704101705101706101707101708101709101710101711101712101713101714101715101716101717101718101719101720101721101722101723101724101725101726101727101728101729101730101731101732101733101734101735101736101737101738101739101740101741101742101743101744101745101746101747101748101749101750101751101752101753101754101755101756101757101758101759101760101761101762101763101764101765101766101767101768101769101770101771101772101773101774101775101776101777101778101779101780101781101782101783101784101785101786101787101788101789101790101791101792101793101794101795101796101797101798101799101800101801101802101803101804101805101806101807101808101809101810101811101812101813101814101815101816101817101818101819101820101821101822101823101824101825101826101827101828101829101830101831101832101833101834101835101836101837101838101839101840101841101842101843101844101845101846101847101848101849101850101851101852101853101854101855101856101857101858101859101860101861101862101863101864101865101866101867101868101869101870101871101872101873101874101875101876101877101878101879101880101881101882101883101884101885101886101887101888101889101890101891101892101893101894101895101896101897101898101899101900101901101902101903101904101905101906101907101908101909101910101911101912101913101914101915101916101917101918101919101920101921101922101923101924101925101926101927101928101929101930101931101932101933101934101935101936101937101938101939101940101941101942101943101944101945101946101947101948101949101950101951101952101953101954101955101956101957101958101959101960101961101962101963101964101965101966101967101968101969101970101971101972101973101974101975101976101977101978101979101980101981101982101983101984101985101986101987101988101989101990101991101992101993101994101995101996101997101998101999102000102001102002102003102004102005102006102007102008102009102010102011102012102013102014102015102016102017102018102019102020102021102022102023102024102025102026102027102028102029102030102031102032102033102034102035102036102037102038102039102040102041102042102043102044102045102046102047102048102049102050102051102052102053102054102055102056102057102058102059102060102061102062102063102064102065102066102067102068102069102070102071102072102073102074102075102076102077102078102079102080102081102082102083102084102085102086102087102088102089102090102091102092102093102094102095102096102097102098102099102100102101102102102103102104102105102106102107102108102109102110102111102112102113102114102115102116102117102118102119102120102121102122102123102124102125102126102127102128102129102130102131102132102133102134102135102136102137102138102139102140102141102142102143102144102145102146102147102148102149102150102151102152102153102154102155102156102157102158102159102160102161102162102163102164102165102166102167102168102169102170102171102172102173102174102175102176102177102178102179102180102181102182102183102184102185102186102187102188102189102190102191102192102193102194102195102196102197102198102199102200102201102202102203102204102205102206102207102208102209102210102211102212102213102214102215102216102217102218102219102220102221102222102223102224102225102226102227102228102229102230102231102232102233102234102235102236102237102238102239102240102241102242102243102244102245102246102247102248102249102250102251102252102253102254102255102256102257102258102259102260102261102262102263102264102265102266102267102268102269102270102271102272102273102274102275102276102277102278102279102280102281102282102283102284102285102286102287102288102289102290102291102292102293102294102295102296102297102298102299102300102301102302102303102304102305102306102307102308102309102310102311102312102313102314102315102316102317102318102319102320102321102322102323102324102325102326102327102328102329102330102331102332102333102334102335102336102337102338102339102340102341102342102343102344102345102346102347102348102349102350102351102352102353102354102355102356102357102358102359102360102361102362102363102364102365102366102367102368102369102370102371102372102373102374102375102376102377102378102379102380102381102382102383102384102385102386102387102388102389102390102391102392102393102394102395102396102397102398102399102400102401102402102403102404102405102406102407102408102409102410102411102412102413102414102415102416102417102418102419102420102421102422102423102424102425102426102427102428102429102430102431102432102433102434102435102436102437102438102439102440102441102442102443102444102445102446102447102448102449102450102451102452102453102454102455102456102457102458102459102460102461102462102463102464102465102466102467102468102469102470102471102472102473102474102475102476102477102478102479102480102481102482102483102484102485102486102487102488102489102490102491102492102493102494102495102496102497102498102499102500102501102502102503102504102505102506102507102508102509102510102511102512102513102514102515102516102517102518102519102520102521102522102523102524102525102526102527102528102529102530102531102532102533102534102535102536102537102538102539102540102541102542102543102544102545102546102547102548102549102550102551102552102553102554102555102556102557102558102559102560102561102562102563102564102565102566102567102568102569102570102571102572102573102574102575102576102577102578102579102580102581102582102583102584102585102586102587102588102589102590102591102592102593102594102595102596102597102598102599102600102601102602102603102604102605102606102607102608102609102610102611102612102613102614102615102616102617102618102619102620102621102622102623102624102625102626102627102628102629102630102631102632102633102634102635102636102637102638102639102640102641102642102643102644102645102646102647102648102649102650102651102652102653102654102655102656102657102658102659102660102661102662102663102664102665102666102667102668102669102670102671102672102673102674102675102676102677102678102679102680102681102682102683102684102685102686102687102688102689102690102691102692102693102694102695102696102697102698102699102700102701102702102703102704102705102706102707102708102709102710102711102712102713102714102715102716102717102718102719102720102721102722102723102724102725102726102727102728102729102730102731102732102733102734102735102736102737102738102739102740102741102742102743102744102745102746102747102748102749102750102751102752102753102754102755102756102757102758102759102760102761102762102763102764102765102766102767102768102769102770102771102772102773102774102775102776102777102778102779102780102781102782102783102784102785102786102787102788102789102790102791102792102793102794102795102796102797102798102799102800102801102802102803102804102805102806102807102808102809102810102811102812102813102814102815102816102817102818102819102820102821102822102823102824102825102826102827102828102829102830102831102832102833102834102835102836102837102838102839102840102841102842102843102844102845102846102847102848102849102850102851102852102853102854102855102856102857102858102859102860102861102862102863102864102865102866102867102868102869102870102871102872102873102874102875102876102877102878102879102880102881102882102883102884102885102886102887102888102889102890102891102892102893102894102895102896102897102898102899102900102901102902102903102904102905102906102907102908102909102910102911102912102913102914102915102916102917102918102919102920102921102922102923102924102925102926102927102928102929102930102931102932102933102934102935102936102937102938102939102940102941102942102943102944102945102946102947102948102949102950102951102952102953102954102955102956102957102958102959102960102961102962102963102964102965102966102967102968102969102970102971102972102973102974102975102976102977102978102979102980102981102982102983102984102985102986102987102988102989102990102991102992102993102994102995102996102997102998102999103000103001103002103003103004103005103006103007103008103009103010103011103012103013103014103015103016103017103018103019103020103021103022103023103024103025103026103027103028103029103030103031103032103033103034103035103036103037103038103039103040103041103042103043103044103045103046103047103048103049103050103051103052103053103054103055103056103057103058103059103060103061103062103063103064103065103066103067103068103069103070103071103072103073103074103075103076103077103078103079103080103081103082103083103084103085103086103087103088103089103090103091103092103093103094103095103096103097103098103099103100103101103102103103103104103105103106103107103108103109103110103111103112103113103114103115103116103117103118103119103120103121103122103123103124103125103126103127103128103129103130103131103132103133103134103135103136103137103138103139103140103141103142103143103144103145103146103147103148103149103150103151103152103153103154103155103156103157103158103159103160103161103162103163103164103165103166103167103168103169103170103171103172103173103174103175103176103177103178103179103180103181103182103183103184103185103186103187103188103189103190103191103192103193103194103195103196103197103198103199103200103201103202103203103204103205103206103207103208103209103210103211103212103213103214103215103216103217103218103219103220103221103222103223103224103225103226103227103228103229103230103231103232103233103234103235103236103237103238103239103240103241103242103243103244103245103246103247103248103249103250103251103252103253103254103255103256103257103258103259103260103261103262103263103264103265103266103267103268103269103270103271103272103273103274103275103276103277103278103279103280103281103282103283103284103285103286103287103288103289103290103291103292103293103294103295103296103297103298103299103300103301103302103303103304103305103306103307103308103309103310103311103312103313103314103315103316103317103318103319103320103321103322103323103324103325103326103327103328103329103330103331103332103333103334103335103336103337103338103339103340103341103342103343103344103345103346103347103348103349103350103351103352103353103354103355103356103357103358103359103360103361103362103363103364103365103366103367103368103369103370103371103372103373103374103375103376103377103378103379103380103381103382103383103384103385103386103387103388103389103390103391103392103393103394103395103396103397103398103399103400103401103402103403103404103405103406103407103408103409103410103411103412103413103414103415103416103417103418103419103420103421103422103423103424103425103426103427103428103429103430103431103432103433103434103435103436103437103438103439103440103441103442103443103444103445103446103447103448103449103450103451103452103453103454103455103456103457103458103459103460103461103462103463103464103465103466103467103468103469103470103471103472103473103474103475103476103477103478103479103480103481103482103483103484103485103486103487103488103489103490103491103492103493103494103495103496103497103498103499103500103501103502103503103504103505103506103507103508103509103510103511103512103513103514103515103516103517103518103519103520103521103522103523103524103525103526103527103528103529103530103531103532103533103534103535103536103537103538103539103540103541103542103543103544103545103546103547103548103549103550103551103552103553103554103555103556103557103558103559103560103561103562103563103564103565103566103567103568103569103570103571103572103573103574103575103576103577103578103579103580103581103582103583103584103585103586103587103588103589103590103591103592103593103594103595103596103597103598103599103600103601103602103603103604103605103606103607103608103609103610103611103612103613103614103615103616103617103618103619103620103621103622103623103624103625103626103627103628103629103630103631103632103633103634103635103636103637103638103639103640103641103642103643103644103645103646103647103648103649103650103651103652103653103654103655103656103657103658103659103660103661103662103663103664103665103666103667103668103669103670103671103672103673103674103675103676103677103678103679103680103681103682103683103684103685103686103687103688103689103690103691103692103693103694103695103696103697103698103699103700103701103702103703103704103705103706103707103708103709103710103711103712103713103714103715103716103717103718103719103720103721103722103723103724103725103726103727103728103729103730103731103732103733103734103735103736103737103738103739103740103741103742103743103744103745103746103747103748103749103750103751103752103753103754103755103756103757103758103759103760103761103762103763103764103765103766103767103768103769103770103771103772103773103774103775103776103777103778103779103780103781103782103783103784103785103786103787103788103789103790103791103792103793103794103795103796103797103798103799103800103801103802103803103804103805103806103807103808103809103810103811103812103813103814103815103816103817103818103819103820103821103822103823103824103825103826103827103828103829103830103831103832103833103834103835103836103837103838103839103840103841103842103843103844103845103846103847103848103849103850103851103852103853103854103855103856103857103858103859103860103861103862103863103864103865103866103867103868103869103870103871103872103873103874103875103876103877103878103879103880103881103882103883103884103885103886103887103888103889103890103891103892103893103894103895103896103897103898103899103900103901103902103903103904103905103906103907103908103909103910103911103912103913103914103915103916103917103918103919103920103921103922103923103924103925103926103927103928103929103930103931103932103933103934103935103936103937103938103939103940103941103942103943103944103945103946103947103948103949103950103951103952103953103954103955103956103957103958103959103960103961103962103963103964103965103966103967103968103969103970103971103972103973103974103975103976103977103978103979103980103981103982103983103984103985103986103987103988103989103990103991103992103993103994103995103996103997103998103999104000104001104002104003104004104005104006104007104008104009104010104011104012104013104014104015104016104017104018104019104020104021104022104023104024104025104026104027104028104029104030104031104032104033104034104035104036104037104038104039104040104041104042104043104044104045104046104047104048104049104050104051104052104053104054104055104056104057104058104059104060104061104062104063104064104065104066104067104068104069104070104071104072104073104074104075104076104077104078104079104080104081104082104083104084104085104086104087104088104089104090104091104092104093104094104095104096104097104098104099104100104101104102104103104104104105104106104107104108104109104110104111104112104113104114104115104116104117104118104119104120104121104122104123104124104125104126104127104128104129104130104131104132104133104134104135104136104137104138104139104140104141104142104143104144104145104146104147104148104149104150104151104152104153104154104155104156104157104158104159104160104161104162104163104164104165104166104167104168104169104170104171104172104173104174104175104176104177104178104179104180104181104182104183104184104185104186104187104188104189104190104191104192104193104194104195104196104197104198104199104200104201104202104203104204104205104206104207104208104209104210104211104212104213104214104215104216104217104218104219104220104221104222104223104224104225104226104227104228104229104230104231104232104233104234104235104236104237104238104239104240104241104242104243104244104245104246104247104248104249104250104251104252104253104254104255104256104257104258104259104260104261104262104263104264104265104266104267104268104269104270104271104272104273104274104275104276104277104278104279104280104281104282104283104284104285104286104287104288104289104290104291104292104293104294104295104296104297104298104299104300104301104302104303104304104305104306104307104308104309104310104311104312104313104314104315104316104317104318104319104320104321104322104323104324104325104326104327104328104329104330104331104332104333104334104335104336104337104338104339104340104341104342104343104344104345104346104347104348104349104350104351104352104353104354104355104356104357104358104359104360104361104362104363104364104365104366104367104368104369104370104371104372104373104374104375104376104377104378104379104380104381104382104383104384104385104386104387104388104389104390104391104392104393104394104395104396104397104398104399104400104401104402104403104404104405104406104407104408104409104410104411104412104413104414104415104416104417104418104419104420104421104422104423104424104425104426104427104428104429104430104431104432104433104434104435104436104437104438104439104440104441104442104443104444104445104446104447104448104449104450104451104452104453104454104455104456104457104458104459104460104461104462104463104464104465104466104467104468104469104470104471104472104473104474104475104476104477104478104479104480104481104482104483104484104485104486104487104488104489104490104491104492104493104494104495104496104497104498104499104500104501104502104503104504104505104506104507104508104509104510104511104512104513104514104515104516104517104518104519104520104521104522104523104524104525104526104527104528104529104530104531104532104533104534104535104536104537104538104539104540104541104542104543104544104545104546104547104548104549104550104551104552104553104554104555104556104557104558104559104560104561104562104563104564104565104566104567104568104569104570104571104572104573104574104575104576104577104578104579104580104581104582104583104584104585104586104587104588104589104590104591104592104593104594104595104596104597104598104599104600104601104602104603104604104605104606104607104608104609104610104611104612104613104614104615104616104617104618104619104620104621104622104623104624104625104626104627104628104629104630104631104632104633104634104635104636104637104638104639104640104641104642104643104644104645104646104647104648104649104650104651104652104653104654104655104656104657104658104659104660104661104662104663104664104665104666104667104668104669104670104671104672104673104674104675104676104677104678104679104680104681104682104683104684104685104686104687104688104689104690104691104692104693104694104695104696104697104698104699104700104701104702104703104704104705104706104707104708104709104710104711104712104713104714104715104716104717104718104719104720104721104722104723104724104725104726104727104728104729104730104731104732104733104734104735104736104737104738104739104740104741104742104743104744104745104746104747104748104749104750104751104752104753104754104755104756104757104758104759104760104761104762104763104764104765104766104767104768104769104770104771104772104773104774104775104776104777104778104779104780104781104782104783104784104785104786104787104788104789104790104791104792104793104794104795104796104797104798104799104800104801104802104803104804104805104806104807104808104809104810104811104812104813104814104815104816104817104818104819104820104821104822104823104824104825104826104827104828104829104830104831104832104833104834104835104836104837104838104839104840104841104842104843104844104845104846104847104848104849104850104851104852104853104854104855104856104857104858104859104860104861104862104863104864104865104866104867104868104869104870104871104872104873104874104875104876104877104878104879104880104881104882104883104884104885104886104887104888104889104890104891104892104893104894104895104896104897104898104899104900104901104902104903104904104905104906104907104908104909104910104911104912104913104914104915104916104917104918104919104920104921104922104923104924104925104926104927104928104929104930104931104932104933104934104935104936104937104938104939104940104941104942104943104944104945104946104947104948104949104950104951104952104953104954104955104956104957104958104959104960104961104962104963104964104965104966104967104968104969104970104971104972104973104974104975104976104977104978104979104980104981104982104983104984104985104986104987104988104989104990104991104992104993104994104995104996104997104998104999105000105001105002105003105004105005105006105007105008105009105010105011105012105013105014105015105016105017105018105019105020105021105022105023105024105025105026105027105028105029105030105031105032105033105034105035105036105037105038105039105040105041105042105043105044105045105046105047105048105049105050105051105052105053105054105055105056105057105058105059105060105061105062105063105064105065105066105067105068105069105070105071105072105073105074105075105076105077105078105079105080105081105082105083105084105085105086105087105088105089105090105091105092105093105094105095105096105097105098105099105100105101105102105103105104105105105106105107105108105109105110105111105112105113105114105115105116105117105118105119105120105121105122105123105124105125105126105127105128105129105130105131105132105133105134105135105136105137105138105139105140105141105142105143105144105145105146105147105148105149105150105151105152105153105154105155105156105157105158105159105160105161105162105163105164105165105166105167105168105169105170105171105172105173105174105175105176105177105178105179105180105181105182105183105184105185105186105187105188105189105190105191105192105193105194105195105196105197105198105199105200105201105202105203
  1. #!/usr/bin/env php
  2. <?php
  3. /*
  4. * This file is part of PHP CS Fixer.
  5. *
  6. * (c) Fabien Potencier <fabien@symfony.com>
  7. * Dariusz Rumiński <dariusz.ruminski@gmail.com>
  8. *
  9. * This source file is subject to the MIT license that is bundled
  10. * with this source code in the file LICENSE.
  11. */
  12. if (getenv('PHP_CS_FIXER_FUTURE_MODE')) {
  13. error_reporting(E_ALL & ~E_DEPRECATED & ~E_USER_DEPRECATED);
  14. }
  15. if (defined('HHVM_VERSION_ID')) {
  16. fwrite(STDERR, "HHVM is not supported.\n");
  17. if (getenv('PHP_CS_FIXER_IGNORE_ENV')) {
  18. fwrite(STDERR, "Ignoring environment requirements because `PHP_CS_FIXER_IGNORE_ENV` is set. Execution may be unstable.\n");
  19. } else {
  20. exit(1);
  21. }
  22. } elseif (!defined('PHP_VERSION_ID') || \PHP_VERSION_ID < 50600 || \PHP_VERSION_ID >= 70500) {
  23. fwrite(STDERR, "PHP needs to be a minimum version of PHP 5.6.0 and maximum version of PHP 7.4.*.\n");
  24. if (getenv('PHP_CS_FIXER_IGNORE_ENV')) {
  25. fwrite(STDERR, "Ignoring environment requirements because `PHP_CS_FIXER_IGNORE_ENV` is set. Execution may be unstable.\n");
  26. } else {
  27. exit(1);
  28. }
  29. }
  30. foreach (['json', 'tokenizer'] as $extension) {
  31. if (!extension_loaded($extension)) {
  32. fwrite(STDERR, sprintf("PHP extension ext-%s is missing from your system. Install or enable it.\n", $extension));
  33. if (getenv('PHP_CS_FIXER_IGNORE_ENV')) {
  34. fwrite(STDERR, "Ignoring environment requirements because `PHP_CS_FIXER_IGNORE_ENV` is set. Execution may be unstable.\n");
  35. } else {
  36. exit(1);
  37. }
  38. }
  39. }
  40. unset($extension);
  41. set_error_handler(static function ($severity, $message, $file, $line) {
  42. if ($severity & error_reporting()) {
  43. throw new ErrorException($message, 0, $severity, $file, $line);
  44. }
  45. });
  46. $require = true;
  47. if (class_exists('Phar')) {
  48. // Maybe this file is used as phar-stub? Let's try!
  49. try {
  50. Phar::mapPhar('php-cs-fixer.phar');
  51. require_once 'phar://php-cs-fixer.phar/vendor/autoload.php';
  52. $require = false;
  53. } catch (PharException $e) {
  54. }
  55. }
  56. if ($require) {
  57. // OK, it's not, let give Composer autoloader a try!
  58. $possibleFiles = [__DIR__.'/../../autoload.php', __DIR__.'/../autoload.php', __DIR__.'/vendor/autoload.php'];
  59. $file = null;
  60. foreach ($possibleFiles as $possibleFile) {
  61. if (file_exists($possibleFile)) {
  62. $file = $possibleFile;
  63. break;
  64. }
  65. }
  66. if (null === $file) {
  67. throw new RuntimeException('Unable to locate autoload.php file.');
  68. }
  69. require_once $file;
  70. unset($possibleFiles, $possibleFile, $file);
  71. }
  72. unset($require);
  73. use Composer\XdebugHandler\XdebugHandler;
  74. use PhpCsFixer\Console\Application;
  75. // Restart if xdebug is loaded, unless the environment variable PHP_CS_FIXER_ALLOW_XDEBUG is set.
  76. $xdebug = new XdebugHandler('PHP_CS_FIXER', '--ansi');
  77. $xdebug->check();
  78. unset($xdebug);
  79. $application = new Application();
  80. $application->run();
  81. __HALT_COMPILER(); ?>
  82. £Ê��¥��������������'���src/AbstractDoctrineAnnotationFixer.phph ��ÿà÷^h ��H•r´������'���src/FixerDefinition/FixerDefinition.php��ÿà÷^��z=´������:���src/FixerDefinition/VersionSpecificCodeSampleInterface.php¶���ÿà÷^¶���íƒál´������1���src/FixerDefinition/VersionSpecificCodeSample.phpÊ��ÿà÷^Ê��¢$NW´������0���src/FixerDefinition/FixerDefinitionInterface.phpb��ÿà÷^b��4/¹´������"���src/FixerDefinition/CodeSample.php¥��ÿà÷^¥��ïMÐ ´������+���src/FixerDefinition/CodeSampleInterface.php£���ÿà÷^£���ò—4/´������5���src/FixerDefinition/VersionSpecificationInterface.php•���ÿà÷^•���ø¢Ý¬´������,���src/FixerDefinition/VersionSpecification.phpm��ÿà÷^m��0E ±´������7���src/FixerDefinition/FileSpecificCodeSampleInterface.php¬���ÿà÷^¬���ÒvO´������.���src/FixerDefinition/FileSpecificCodeSample.phph��ÿà÷^h��uÏ‹¥´���������src/Report/GitlabReporter.phpÏ��ÿà÷^Ï��nŠÛ›´���������src/Report/JsonReporter.phpÓ��ÿà÷^Ó�� Ê(Ê´���������src/Report/ReporterFactory.phpŸ��ÿà÷^Ÿ��ªMg.´���������src/Report/ReportSummary.php¨��ÿà÷^¨��Í)nU´������!���src/Report/CheckstyleReporter.php��ÿà÷^��ãC¡ÿ´���������src/Report/XmlReporter.phpI
  83. ��ÿà÷^I
  84. �� k°Ñ´���������src/Report/TextReporter.phpd��ÿà÷^d��äAIÕ´���������src/Report/JunitReporter.php£ ��ÿà÷^£ ��ñÔ!s´������ ���src/Report/ReporterInterface.php°���ÿà÷^°���÷´������!���src/Doctrine/Annotation/Token.phpâ��ÿà÷^â��y¤Ø7´������"���src/Doctrine/Annotation/Tokens.php��ÿà÷^��yË�´���������src/FixerFileProcessedEvent.phpö��ÿà÷^ö��¼f´������ ���src/Preg.php°��ÿà÷^°���ýþ8´���������src/FixerNameValidator.php��ÿà÷^��˜±R´���������src/Console/Application.phpë ��ÿà÷^ë ��²Ön´������ ���src/Console/WarningsDetector.phpÔ��ÿà÷^Ô��ÓË/´������-���src/Console/Output/ProcessOutputInterface.php~���ÿà÷^~���ßøÕƒ´������$���src/Console/Output/ProcessOutput.php ��ÿà÷^ ��èôY´������!���src/Console/Output/NullOutput.php™���ÿà÷^™���~|œU´������"���src/Console/Output/ErrorOutput.php� ��ÿà÷^� ��y=4´������%���src/Console/ConfigurationResolver.phpE��ÿà÷^E��
  85. ¾šˆ´������)���src/Console/Command/SelfUpdateCommand.phpµ��ÿà÷^µ��þ0}ù´������#���src/Console/Command/HelpCommand.phpsE��ÿà÷^sE��sl6›´������"���src/Console/Command/FixCommand.phpO��ÿà÷^O��™ˆ´������6���src/Console/Command/FixCommandExitStatusCalculator.php;��ÿà÷^;��ƒ#¸´������%���src/Console/Command/ReadmeCommand.phpÍ��ÿà÷^Í��Î`|U´������5���src/Console/Command/DescribeNameNotFoundException.php“��ÿà÷^“��–„û´������'���src/Console/Command/DescribeCommand.php™&��ÿà÷^™&��`¨Õl´������5���src/Console/SelfUpdate/NewVersionCheckerInterface.php��ÿà÷^��,µKl´������0���src/Console/SelfUpdate/GithubClientInterface.php€���ÿà÷^€���´]ÆÎ´������,���src/Console/SelfUpdate/NewVersionChecker.phpy��ÿà÷^y��I‹´������'���src/Console/SelfUpdate/GithubClient.php·��ÿà÷^·��99⌴���������src/AbstractProxyFixer.php3��ÿà÷^3��Înªm´���������src/RuleSet.phpI1��ÿà÷^I1��#â`ê´���������src/FixerFactory.phpŠ��ÿà÷^Š��‰–”|´���������src/PharChecker.php“��ÿà÷^“��C"}Å´������)���src/Runner/FileCachingLintingIterator.php���ÿà÷^���ev
  86. ¯´���������src/Runner/Runner.php��ÿà÷^��ÃæŸ´������"���src/Runner/FileLintingIterator.php>��ÿà÷^>��®9»‹´������!���src/Runner/FileFilterIterator.phpL��ÿà÷^L��Œ‚´���������src/RuleSetInterface.phpj��ÿà÷^j��ÿúÒ´���������src/Linter/ProcessLinter.php1 ��ÿà÷^1 ��+
  87. ƒ´������#���src/Linter/ProcessLintingResult.php•��ÿà÷^•��€yÈ´������%���src/Linter/LintingResultInterface.phps���ÿà÷^s���O:§N´���������src/Linter/LintingException.phpg���ÿà÷^g���ÎKþ�´������*���src/Linter/ProcessLinterProcessBuilder.phpR��ÿà÷^R��ïCŸý´���������src/Linter/TokenizerLinter.php��ÿà÷^��ñÛÆÄ´������)���src/Linter/UnavailableLinterException.phps���ÿà÷^s���¡ýGÉ´���������src/Linter/Linter.php8��ÿà÷^8��×XÂÏ´������%���src/Linter/TokenizerLintingResult.phpÈ��ÿà÷^È��É+)´���������src/Linter/CachingLinter.phpê��ÿà÷^ê��Âln´���������src/Linter/LinterInterface.phpÆ���ÿà÷^Æ���/X‹Æ´������"���src/AbstractNoUselessElseFixer.php€ ��ÿà÷^€ ��¡¥ÃÌ´���������src/DocBlock/DocBlock.phpæ ��ÿà÷^æ ��à°³8´���������src/DocBlock/TagComparator.phpm��ÿà÷^m��ð~&´���������src/DocBlock/Line.php8��ÿà÷^8��Ñ „J´���������src/DocBlock/Tag.phpˆ��ÿà÷^ˆ��oX‘Ì´������!���src/DocBlock/ShortDescription.php��ÿà÷^��� ã–´���������src/DocBlock/Annotation.phpN��ÿà÷^N��*›m­´������)���src/AbstractLinesBeforeNamespaceFixer.phpA��ÿà÷^A��‡yKM´������=���src/FixerConfiguration/FixerConfigurationResolverRootless.php!��ÿà÷^!��ßL9´������0���src/FixerConfiguration/DeprecatedFixerOption.phpÐ��ÿà÷^Ð��êøI¨´������&���src/FixerConfiguration/FixerOption.phpˆ��ÿà÷^ˆ��J-Š´������-���src/FixerConfiguration/FixerOptionBuilder.php:��ÿà÷^:��=.á´������>���src/FixerConfiguration/FixerConfigurationResolverInterface.phpÃ���ÿà÷^Ã���÷–Ø#´������/���src/FixerConfiguration/FixerOptionInterface.php\��ÿà÷^\��j,‰½´������5���src/FixerConfiguration/FixerConfigurationResolver.phpÞ��ÿà÷^Þ��ê»oì´������4���src/FixerConfiguration/AliasedFixerOptionBuilder.phpŒ��ÿà÷^Œ��ô©Í*´������-���src/FixerConfiguration/AllowedValueSubset.phpê��ÿà÷^ê��œ8ÿ´������9���src/FixerConfiguration/DeprecatedFixerOptionInterface.php±���ÿà÷^±���$Æõ¤´������8���src/FixerConfiguration/InvalidOptionsForEnvException.phpØ���ÿà÷^Ø���˜ÈR´������-���src/FixerConfiguration/AliasedFixerOption.php°��ÿà÷^°��…ÚÛy´������#���src/AbstractPsrAutoloadingFixer.php!��ÿà÷^!��$ij:´���������src/Differ/NullDiffer.php›���ÿà÷^›���ø¨D´���������src/Differ/UnifiedDiffer.phpÇ��ÿà÷^Ç��/õ1¨´���������src/Differ/FullDiffer.php��ÿà÷^��A§m“´������&���src/Differ/SebastianBergmannDiffer.php=��ÿà÷^=��–îq´������#���src/Differ/DiffConsoleFormatter.phpÀ��ÿà÷^À��°Ø…´������+���src/Differ/SebastianBergmannShortDiffer.phpb��ÿà÷^b��Z!¨5´���������src/Differ/DifferInterface.php|���ÿà÷^|���ÙhÄB´���������src/Event/Event.php…��ÿà÷^…��£m Ý´���������src/ToolInfoInterface.phpB��ÿà÷^B��Ô-—W´���������src/ConfigInterface.phpe��ÿà÷^e��**ü=´���������src/PharCheckerInterface.php����ÿà÷^����Ñ�£´���������src/ToolInfo.phpø��ÿà÷^ø��|îÒ´������ ���src/AbstractAlignFixerHelper.phpÙ��ÿà÷^Ù��ä:“u´���������src/Finder.php(��ÿà÷^(��¸”�´���������src/WordMatcher.phpî��ÿà÷^î��x«ÿ¨´���������src/AbstractFopenFlagFixer.phpË��ÿà÷^Ë��'aд���������src/StdinFileInfo.php#��ÿà÷^#��`—)D´���������src/Error/ErrorsManager.phpä��ÿà÷^ä��æü錴���������src/Error/Error.php0��ÿà÷^0��Ð|ŸØ´���������src/FileRemoval.phpb��ÿà÷^b��ˆÙT¶´���������src/Config.php0 ��ÿà÷^0 ��•úŸ´������ ���src/AbstractPhpdocTypesFixer.phpÞ��ÿà÷^Þ��±Ü�è´���������src/WhitespacesFixerConfig.php¬��ÿà÷^¬��èB´������&���src/AbstractFunctionReferenceFixer.phpÌ��ÿà÷^Ì��¶Hˆ´������2���src/Fixer/Whitespace/SingleBlankLineAtEofFixer.phpû��ÿà÷^û�� ^Eü´������2���src/Fixer/Whitespace/NoSpacesAroundOffsetFixer.phpY ��ÿà÷^Y ��ÜnA´������7���src/Fixer/Whitespace/MethodChainingIndentationFixer.phpH��ÿà÷^H��üéYŽ´������2���src/Fixer/Whitespace/NoTrailingWhitespaceFixer.phpË��ÿà÷^Ë��í°Fi´������-���src/Fixer/Whitespace/IndentationTypeFixer.php
  88. ��ÿà÷^
  89. ��(`W´������6���src/Fixer/Whitespace/BlankLineBeforeStatementFixer.php¶��ÿà÷^¶��¸*Š´������7���src/Fixer/Whitespace/NoSpacesInsideParenthesisFixer.php/��ÿà÷^/��ûø$—´������5���src/Fixer/Whitespace/CompactNullableTypehintFixer.phpä��ÿà÷^ä��ig:´������:���src/Fixer/Whitespace/NoExtraConsecutiveBlankLinesFixer.php;��ÿà÷^;��Sêôд������/���src/Fixer/Whitespace/NoExtraBlankLinesFixer.php!��ÿà÷^!��ÿ¦N;´������(���src/Fixer/Whitespace/LineEndingFixer.phpº��ÿà÷^º��¾¸
  90. –´������5���src/Fixer/Whitespace/NoWhitespaceInBlankLineFixer.phpÈ��ÿà÷^È��ÅtÚδ������0���src/Fixer/Whitespace/HeredocIndentationFixer.phpT ��ÿà÷^T ��È›9¢´������.���src/Fixer/Whitespace/ArrayIndentationFixer.phpú!��ÿà÷^ú!��Ò´ì´������%���src/Fixer/Strict/StrictParamFixer.phpv ��ÿà÷^v ��¨&º ´������*���src/Fixer/Strict/StrictComparisonFixer.phpt��ÿà÷^t��¬Îc¶´������,���src/Fixer/Strict/DeclareStrictTypesFixer.phpw
  91. ��ÿà÷^w
  92. ��RwÁ´������>���src/Fixer/DoctrineAnnotation/DoctrineAnnotationSpacesFixer.phpW#��ÿà÷^W#��ü‘e´������G���src/Fixer/DoctrineAnnotation/DoctrineAnnotationArrayAssignmentFixer.phpî��ÿà÷^î��mE/´������C���src/Fixer/DoctrineAnnotation/DoctrineAnnotationIndentationFixer.php%��ÿà÷^%��÷w¨´������>���src/Fixer/DoctrineAnnotation/DoctrineAnnotationBracesFixer.php
  93. ��ÿà÷^
  94. ��G£:s´������#���src/Fixer/DefinedFixerInterface.phpÍ���ÿà÷^Í���� Ü´������/���src/Fixer/Import/GlobalNamespaceImportFixer.phpô=��ÿà÷^ô=���½”²´������)���src/Fixer/Import/NoUnusedImportsFixer.phpø��ÿà÷^ø��žþR9´������3���src/Fixer/Import/FullyQualifiedStrictTypesFixer.php! ��ÿà÷^! ��š´ë´������.���src/Fixer/Import/NoLeadingImportSlashFixer.php~��ÿà÷^~��02Û¯´������2���src/Fixer/Import/SingleImportPerStatementFixer.phpq��ÿà÷^q��œÃ‚i´������(���src/Fixer/Import/OrderedImportsFixer.php÷)��ÿà÷^÷)��
  95. œŠj´������0���src/Fixer/Import/SingleLineAfterImportsFixer.phpJ ��ÿà÷^J ��¸p´Š´������&���src/Fixer/PhpTag/NoClosingTagFixer.php‡��ÿà÷^‡�� +´������2���src/Fixer/PhpTag/LinebreakAfterOpeningTagFixer.phpž��ÿà÷^ž��.€©t´������2���src/Fixer/PhpTag/BlankLineAfterOpeningTagFixer.php<��ÿà÷^<��±¥õ´������(���src/Fixer/PhpTag/NoShortEchoTagFixer.php.��ÿà÷^.��îÑ—I´������(���src/Fixer/PhpTag/FullOpeningTagFixer.phpL��ÿà÷^L��»Eÿ¥´������*���src/Fixer/ListNotation/ListSyntaxFixer.phpÔ ��ÿà÷^Ô ��#ÕΧ´������6���src/Fixer/ReturnNotation/SimplifiedNullReturnFixer.php� ��ÿà÷^� ��íË4´������7���src/Fixer/ReturnNotation/BlankLineBeforeReturnFixer.php��ÿà÷^��ãGÑ—´������2���src/Fixer/ReturnNotation/ReturnAssignmentFixer.phpa��ÿà÷^a�� 3Š´������1���src/Fixer/ReturnNotation/NoUselessReturnFixer.phpp��ÿà÷^p��R|Ñ…´������-���src/Fixer/Comment/HashToSlashCommentFixer.phpú��ÿà÷^ú��MÔZ`´������)���src/Fixer/Comment/NoEmptyCommentFixer.php"
  96. ��ÿà÷^"
  97. ���…™h´������9���src/Fixer/Comment/MultilineCommentOpeningClosingFixer.php��ÿà÷^��Q¯´������8���src/Fixer/Comment/NoTrailingWhitespaceInCommentFixer.php¬��ÿà÷^¬��µÕÅš´������*���src/Fixer/Comment/CommentToPhpdocFixer.phpå��ÿà÷^å��ÑôÑ´������1���src/Fixer/Comment/SingleLineCommentStyleFixer.phpÑ ��ÿà÷^Ñ ��šéWn´������(���src/Fixer/Comment/HeaderCommentFixer.phpB'��ÿà÷^B'��ÓíV´������3���src/Fixer/ConfigurationDefinitionFixerInterface.php��ÿà÷^��MÕãµ´������#���src/Fixer/Alias/EregToPregFixer.php«
  98. ��ÿà÷^«
  99. ��ž^Îü´������+���src/Fixer/Alias/RandomApiMigrationFixer.php§��ÿà÷^§��Àú’2´������)���src/Fixer/Alias/NoAliasFunctionsFixer.phpí��ÿà÷^í��A$´������)���src/Fixer/Alias/NoMixedEchoPrintFixer.php¤
  100. ��ÿà÷^¤
  101. ��ÓäJ´������&���src/Fixer/Alias/SetTypeToCastFixer.php®��ÿà÷^®��ùôò´������,���src/Fixer/Alias/PowToExponentiationFixer.phpD��ÿà÷^D��ÒåE´������'���src/Fixer/Alias/MbStrFunctionsFixer.php
  102. ��ÿà÷^
  103. ��¸Ða´������,���src/Fixer/Alias/BacktickToShellExecFixer.php. ��ÿà÷^. ��Fž=´������&���src/Fixer/PhpUnit/PhpUnitMockFixer.phpK��ÿà÷^K��^æÔ£´������,���src/Fixer/PhpUnit/PhpUnitNamespacedFixer.phpd��ÿà÷^d��ZIØ3´������5���src/Fixer/PhpUnit/PhpUnitMockShortWillReturnFixer.phpæ��ÿà÷^æ��$ß­à´������<���src/Fixer/PhpUnit/PhpUnitDedicateAssertInternalTypeFixer.phpŠ��ÿà÷^Š��Äã/­´������0���src/Fixer/PhpUnit/PhpUnitTestAnnotationFixer.phpÂ)��ÿà÷^Â)��áˆ!î´������;���src/Fixer/PhpUnit/PhpUnitTestCaseStaticMethodCallsFixer.php.��ÿà÷^.��PÌÑí´������9���src/Fixer/PhpUnit/PhpUnitSetUpTearDownVisibilityFixer.php
  104. ��ÿà÷^
  105. ��/ §7´������/���src/Fixer/PhpUnit/PhpUnitOrderedCoversFixer.php��ÿà÷^��KCý)´������+���src/Fixer/PhpUnit/PhpUnitSizeClassFixer.phpÎ��ÿà÷^Î��’Y“�´������9���src/Fixer/PhpUnit/PhpUnitNoExpectationAnnotationFixer.php˜��ÿà÷^˜��Ò†>´������.���src/Fixer/PhpUnit/PhpUnitMethodCasingFixer.phpâ��ÿà÷^â��óŸÇy´������*���src/Fixer/PhpUnit/PhpUnitTargetVersion.php´��ÿà÷^´��?óƒ´������+���src/Fixer/PhpUnit/PhpUnitConstructFixer.php¬��ÿà÷^¬��ÅYì´������-���src/Fixer/PhpUnit/PhpUnitExpectationFixer.php‘��ÿà÷^‘��quÑ´������9���src/Fixer/PhpUnit/PhpUnitTestClassRequiresCoversFixer.phpÌ ��ÿà÷^Ì ��6‰´������0���src/Fixer/PhpUnit/PhpUnitFqcnAnnotationFixer.phpL��ÿà÷^L��·Æ×1´������0���src/Fixer/PhpUnit/PhpUnitDedicateAssertFixer.phpÒ&��ÿà÷^Ò&��;¥ÞP´������(���src/Fixer/PhpUnit/PhpUnitStrictFixer.php ��ÿà÷^ ��`È™´������/���src/Fixer/PhpUnit/PhpUnitInternalClassFixer.php?��ÿà÷^?��Þ]说���������src/Fixer/FixerInterface.php—��ÿà÷^—��eus`´������(���src/Fixer/ConfigurableFixerInterface.php��ÿà÷^��¿§Å´������:���src/Fixer/LanguageConstruct/DeclareEqualNormalizeFixer.php>
  106. ��ÿà÷^>
  107. ��ùÛÒO´������+���src/Fixer/LanguageConstruct/IsNullFixer.phpõ��ÿà÷^õ��’pN¢´������7���src/Fixer/LanguageConstruct/ClassKeywordRemoveFixer.php©��ÿà÷^©��íOÀZ´������6���src/Fixer/LanguageConstruct/NoUnsetOnPropertyFixer.phpÈ��ÿà÷^È��ªB‚ø´������=���src/Fixer/LanguageConstruct/ExplicitIndirectVariableFixer.php���ÿà÷^���ÛZ²#´������5���src/Fixer/LanguageConstruct/ErrorSuppressionFixer.php
  108. ��ÿà÷^
  109. ��t'¨¦´������7���src/Fixer/LanguageConstruct/FunctionToConstantFixer.php¿��ÿà÷^¿��ä�’þ´������=���src/Fixer/LanguageConstruct/SilencedDeprecationErrorFixer.php��ÿà÷^��Qª<á´������=���src/Fixer/LanguageConstruct/CombineConsecutiveIssetsFixer.php  ��ÿà÷^  ��ÍjÞ‹´������=���src/Fixer/LanguageConstruct/CombineConsecutiveUnsetsFixer.phpš ��ÿà÷^š ��‡åc´������0���src/Fixer/LanguageConstruct/DirConstantFixer.php4 ��ÿà÷^4 ��1Ÿ/@´���������src/Fixer/Basic/Psr4Fixer.php*��ÿà÷^*��ú•OÍ´������.���src/Fixer/Basic/NonPrintableCharacterFixer.php��ÿà÷^��_Ž'´���������src/Fixer/Basic/Psr0Fixer.phpŸ��ÿà÷^Ÿ��ŠX"Ç´���������src/Fixer/Basic/BracesFixer.php `��ÿà÷^ `�� Rî´������!���src/Fixer/Basic/EncodingFixer.php;��ÿà÷^;��xAШ´������0���src/Fixer/Semicolon/SpaceAfterSemicolonFixer.phpâ
  110. ��ÿà÷^â
  111. ��UÀJ5´������-���src/Fixer/Semicolon/NoEmptyStatementFixer.php¸ ��ÿà÷^¸ ��Ú’Rë´������C���src/Fixer/Semicolon/NoSinglelineWhitespaceBeforeSemicolonsFixer.php,��ÿà÷^,��aïâÜ´������6���src/Fixer/Semicolon/SemicolonAfterInstructionFixer.php´��ÿà÷^´��í_ßk´������B���src/Fixer/Semicolon/NoMultilineWhitespaceBeforeSemicolonsFixer.phpÆ��ÿà÷^Æ���ø‘.´������@���src/Fixer/Semicolon/MultilineWhitespaceBeforeSemicolonsFixer.php.��ÿà÷^.��é3�)´������,���src/Fixer/WhitespacesAwareFixerInterface.phpã���ÿà÷^ã���gó²s´������&���src/Fixer/DeprecatedFixerInterface.phpš���ÿà÷^š���=r”T´������<���src/Fixer/ArrayNotation/WhitespaceAfterCommaInArrayFixer.phpý��ÿà÷^ý��îÁ¬´������A���src/Fixer/ArrayNotation/NoTrailingCommaInSinglelineArrayFixer.php���ÿà÷^���$Îì³´������4���src/Fixer/ArrayNotation/NormalizeIndexBraceFixer.phpÈ��ÿà÷^È��$Ý“�´������0���src/Fixer/ArrayNotation/TrimArraySpacesFixer.php���ÿà÷^���È5ºý´������>���src/Fixer/ArrayNotation/TrailingCommaInMultilineArrayFixer.php ��ÿà÷^ ��û3{-´������?���src/Fixer/ArrayNotation/NoWhitespaceBeforeCommaInArrayFixer.phpä ��ÿà÷^ä �� á¼N´������,���src/Fixer/ArrayNotation/ArraySyntaxFixer.phpV ��ÿà÷^V ��؆)´������G���src/Fixer/ArrayNotation/NoMultilineWhitespaceAroundDoubleArrowFixer.phpË��ÿà÷^Ë��„m;Œ´������<���src/Fixer/ConstantNotation/NativeConstantInvocationFixer.phpº��ÿà÷^º��ãÉ-´������3���src/Fixer/Phpdoc/PhpdocReturnSelfReferenceFixer.php·��ÿà÷^·��*íÕ‘´������$���src/Fixer/Phpdoc/PhpdocTrimFixer.phpo��ÿà÷^o��ù´������*���src/Fixer/Phpdoc/PhpdocSeparationFixer.php]
  112. ��ÿà÷^]
  113. ��tæjà´������1���src/Fixer/Phpdoc/NoSuperfluousPhpdocTagsFixer.php¢*��ÿà÷^¢*��¸½˜ó´������)���src/Fixer/Phpdoc/PhpdocInlineTagFixer.phpk��ÿà÷^k��¦�…y´������%���src/Fixer/Phpdoc/PhpdocOrderFixer.php3 ��ÿà÷^3 ��8`�´������'���src/Fixer/Phpdoc/NoEmptyPhpdocFixer.phpu��ÿà÷^u��°DlA´������)���src/Fixer/Phpdoc/PhpdocNoPackageFixer.phpõ��ÿà÷^õ��ë9µ¤´������*���src/Fixer/Phpdoc/PhpdocTypesOrderFixer.phpñ��ÿà÷^ñ��ÿ.Ir´������9���src/Fixer/Phpdoc/PhpdocVarAnnotationCorrectOrderFixer.phpØ��ÿà÷^Ø��Pé ú´������'���src/Fixer/Phpdoc/PhpdocSummaryFixer.php3��ÿà÷^3���}x´������%���src/Fixer/Phpdoc/PhpdocTypesFixer.phpþ��ÿà÷^þ��æ¿�¬´������*���src/Fixer/Phpdoc/PhpdocNoAliasTagFixer.phpX ��ÿà÷^X �� m¥C´������&���src/Fixer/Phpdoc/PhpdocIndentFixer.php/��ÿà÷^/��1,]^´������%���src/Fixer/Phpdoc/PhpdocAlignFixer.php¢��ÿà÷^¢��*iІ´������1���src/Fixer/Phpdoc/NoBlankLinesAfterPhpdocFixer.php›��ÿà÷^›��à�´������(���src/Fixer/Phpdoc/PhpdocLineSpanFixer.phpú ��ÿà÷^ú ���$̾´������4���src/Fixer/Phpdoc/PhpdocSingleLineVarSpacingFixer.php)��ÿà÷^)��µ ¾Â´������&���src/Fixer/Phpdoc/PhpdocScalarFixer.php��ÿà÷^��‰7þÉ´������7���src/Fixer/Phpdoc/GeneralPhpdocAnnotationRemoveFixer.phpB��ÿà÷^B��ý@Ä´������(���src/Fixer/Phpdoc/PhpdocNoAccessFixer.phpå��ÿà÷^å�� lH´������-���src/Fixer/Phpdoc/PhpdocNoEmptyReturnFixer.phpž��ÿà÷^ž��eJ¸V´������)���src/Fixer/Phpdoc/PhpdocToCommentFixer.php%��ÿà÷^%��¹�´������3���src/Fixer/Phpdoc/PhpdocNoUselessInheritdocFixer.php ��ÿà÷^ ��%îe´������/���src/Fixer/Phpdoc/AlignMultilineCommentFixer.phpH ��ÿà÷^H ��‚íw´������4���src/Fixer/Phpdoc/PhpdocAnnotationWithoutDotFixer.phpÜ ��ÿà÷^Ü ��þšâ´������9���src/Fixer/Phpdoc/PhpdocAddMissingParamAnnotationFixer.php§��ÿà÷^§��O}�6´������.���src/Fixer/Phpdoc/PhpdocVarWithoutNameFixer.phpb ��ÿà÷^b ��D‰Lƒ´������B���src/Fixer/Phpdoc/PhpdocTrimConsecutiveBlankLineSeparationFixer.phpé ��ÿà÷^é ��éö‘¸´������,���src/Fixer/Operator/LogicalOperatorsFixer.phpQ��ÿà÷^Q��ðh°�´������'���src/Fixer/Operator/ConcatSpaceFixer.php­ ��ÿà÷^­ ��<Ò%w´������0���src/Fixer/Operator/NotOperatorWithSpaceFixer.php,��ÿà÷^,��GãÆ¦´������)���src/Fixer/Operator/NewWithBracesFixer.php— ��ÿà÷^— �� b’Ë´������/���src/Fixer/Operator/UnaryOperatorSpacesFixer.phpŒ��ÿà÷^Œ��Ã�´������0���src/Fixer/Operator/StandardizeIncrementFixer.phpD ��ÿà÷^D ��WÓ!Ž´������1���src/Fixer/Operator/TernaryOperatorSpacesFixer.phpc��ÿà÷^c��à¹y´������-���src/Fixer/Operator/AlignEqualsFixerHelper.phpæ��ÿà÷^æ��4IUR´������*���src/Fixer/Operator/IncrementStyleFixer.php��ÿà÷^���û厴������9���src/Fixer/Operator/NotOperatorWithSuccessorSpaceFixer.php��ÿà÷^�� ‹}´������0���src/Fixer/Operator/StandardizeNotEqualsFixer.php5��ÿà÷^5��GΫ„´������3���src/Fixer/Operator/TernaryToNullCoalescingFixer.php/��ÿà÷^/��ðqät´������0���src/Fixer/Operator/BinaryOperatorSpacesFixer.phpfC��ÿà÷^fC��ùK;´������;���src/Fixer/Operator/ObjectOperatorWithoutWhitespaceFixer.phpð��ÿà÷^ð��t�Ë´������2���src/Fixer/Operator/AlignDoubleArrowFixerHelper.phpg ��ÿà÷^g ��LàÐ=´������(���src/Fixer/Operator/PreIncrementFixer.phpÞ��ÿà÷^Þ��¿©­´������-���src/Fixer/ClassNotation/SelfAccessorFixer.php½��ÿà÷^½��Êü1Ò´������6���src/Fixer/ClassNotation/NoUnneededFinalMethodFixer.phpò��ÿà÷^ò��¡—k´������2���src/Fixer/ClassNotation/OrderedInterfacesFixer.phpÙ��ÿà÷^Ù��36ð´������3���src/Fixer/ClassNotation/ProtectedToPrivateFixer.phpi��ÿà÷^i��sj_†´������3���src/Fixer/ClassNotation/VisibilityRequiredFixer.phpú��ÿà÷^ú��ΰ"¾´������1���src/Fixer/ClassNotation/MethodSeparationFixer.phpæ��ÿà÷^æ��Q¹x§´������3���src/Fixer/ClassNotation/SelfStaticAccessorFixer.phpÞ ��ÿà÷^Þ ���º>‹´������>���src/Fixer/ClassNotation/SingleTraitInsertPerStatementFixer.phpç��ÿà÷^ç�� Ïδ������5���src/Fixer/ClassNotation/OrderedClassElementsFixer.phpk%��ÿà÷^k%��`Åa´������0���src/Fixer/ClassNotation/ClassDefinitionFixer.phpå)��ÿà÷^å)��ƒØf ´������2���src/Fixer/ClassNotation/NoPhp4ConstructorFixer.php¢��ÿà÷^¢��TÜy
  114. ´������?���src/Fixer/ClassNotation/SingleClassElementPerStatementFixer.phpœ��ÿà÷^œ���Y?t´������=���src/Fixer/ClassNotation/NoNullPropertyInitializationFixer.phpŒ��ÿà÷^Œ��nñ…Í´������+���src/Fixer/ClassNotation/FinalClassFixer.phpU��ÿà÷^U��Eh¹æ´������:���src/Fixer/ClassNotation/ClassAttributesSeparationFixer.php ��ÿà÷^ �� ê*"´������2���src/Fixer/ClassNotation/FinalStaticAccessFixer.php ��ÿà÷^ ��· ŸÓ´������>���src/Fixer/ClassNotation/NoBlankLinesAfterClassOpeningFixer.php ��ÿà÷^ ��`k£´������3���src/Fixer/ClassNotation/FinalInternalClassFixer.php ��ÿà÷^ ��ØÊÛ>´������B���src/Fixer/ClassNotation/FinalPublicMethodForAbstractClassFixer.phpÊ ��ÿà÷^Ê ��æ2Íð´������/���src/Fixer/ClassUsage/DateTimeImmutableFixer.phpå ��ÿà÷^å ��‚ÿx-´������0���src/Fixer/StringNotation/NoBinaryStringFixer.phpô��ÿà÷^ô��Ñ9t´������?���src/Fixer/StringNotation/SimpleToComplexStringVariableFixer.php¬��ÿà÷^¬��á÷´������2���src/Fixer/StringNotation/StringLineEndingFixer.php9��ÿà÷^9��k u´������-���src/Fixer/StringNotation/SingleQuoteFixer.php,��ÿà÷^,��ª7¸´������;���src/Fixer/StringNotation/EscapeImplicitBackslashesFixer.php��ÿà÷^��1ýŠ´������1���src/Fixer/StringNotation/HeredocToNowdocFixer.phps��ÿà÷^s��o\êÙ´������8���src/Fixer/StringNotation/ExplicitStringVariableFixer.php��ÿà÷^��?³Ûí´������0���src/Fixer/FunctionNotation/StaticLambdaFixer.php˜
  115. ��ÿà÷^˜
  116. ��Õ8ªà´������N���src/Fixer/FunctionNotation/NullableTypeDeclarationForDefaultNullValueFixer.php\ ��ÿà÷^\ ��t&BO´������/���src/Fixer/FunctionNotation/ImplodeCallFixer.php[ ��ÿà÷^[ ��ŽY,8´������=���src/Fixer/FunctionNotation/NoSpacesAfterFunctionNameFixer.php ��ÿà÷^ ��¤:9´������8���src/Fixer/FunctionNotation/CombineNestedDirnameFixer.phpD��ÿà÷^D��ʹ蓴������.���src/Fixer/FunctionNotation/VoidReturnFixer.phpI��ÿà÷^I��¹Ü¨c´������3���src/Fixer/FunctionNotation/SingleLineThrowFixer.phpð
  117. ��ÿà÷^ð
  118. ���$´������9���src/Fixer/FunctionNotation/ReturnTypeDeclarationFixer.php
  119. ��ÿà÷^
  120. ��ÀNQ—´������5���src/Fixer/FunctionNotation/PhpdocToParamTypeFixer.php—��ÿà÷^—��×U#´������<���src/Fixer/FunctionNotation/NativeFunctionInvocationFixer.phpf��ÿà÷^f��ûö{´������7���src/Fixer/FunctionNotation/MethodArgumentSpaceFixer.phpé-��ÿà÷^é-��03:I´������6���src/Fixer/FunctionNotation/PhpdocToReturnTypeFixer.php}��ÿà÷^}�� Ñ·´������.���src/Fixer/FunctionNotation/FopenFlagsFixer.php0 ��ÿà÷^0 ��¥°Á+´������9���src/Fixer/FunctionNotation/FunctionTypehintSpaceFixer.php²��ÿà÷^²��ý Y´������7���src/Fixer/FunctionNotation/FunctionDeclarationFixer.phpó��ÿà÷^ó��F‡é#´������2���src/Fixer/FunctionNotation/FopenFlagOrderFixer.phpW��ÿà÷^W��âd·»´������E���src/Fixer/FunctionNotation/NoUnreachableDefaultArgumentValueFixer.phpš��ÿà÷^š��ÞTþ)´������*���src/Fixer/Naming/NoHomoglyphNamesFixer.phpÐ ��ÿà÷^Ð ��{üË´������-���src/Fixer/Casing/MagicConstantCasingFixer.php>��ÿà÷^>��…œ6Ý´������.���src/Fixer/Casing/NativeFunctionCasingFixer.php¦��ÿà÷^¦��hz3)´������&���src/Fixer/Casing/ConstantCaseFixer.phpq ��ÿà÷^q ��êAlã´������,���src/Fixer/Casing/LowercaseConstantsFixer.php��ÿà÷^��<~@Ñ´������+���src/Fixer/Casing/LowercaseKeywordsFixer.phpM��ÿà÷^M�� ¢¼´������+���src/Fixer/Casing/MagicMethodCasingFixer.php‹��ÿà÷^‹��C}ŸV´������2���src/Fixer/Casing/LowercaseStaticReferenceFixer.phpÞ��ÿà÷^Þ��”äBü´������=���src/Fixer/Casing/NativeFunctionTypeDeclarationCasingFixer.phpï ��ÿà÷^ï ��žr²W´������<���src/Fixer/NamespaceNotation/BlankLineAfterNamespaceFixer.php ��ÿà÷^ ��‰¯|´������A���src/Fixer/NamespaceNotation/NoLeadingNamespaceWhitespaceFixer.phpA��ÿà÷^A��ü™mJ´������C���src/Fixer/NamespaceNotation/SingleBlankLineBeforeNamespaceFixer.php×��ÿà÷^×��˜�4$´������@���src/Fixer/NamespaceNotation/NoBlankLinesBeforeNamespaceFixer.phpÀ��ÿà÷^À��ï®u´������-���src/Fixer/CastNotation/LowercaseCastFixer.php9��ÿà÷^9��ϯ"±´������*���src/Fixer/CastNotation/CastSpacesFixer.phpE��ÿà÷^E��d³ú¼´������+���src/Fixer/CastNotation/NoUnsetCastFixer.php§��ÿà÷^§��œZ2´������/���src/Fixer/CastNotation/NoShortBoolCastFixer.php±��ÿà÷^±��úáµ'´������/���src/Fixer/CastNotation/ShortScalarCastFixer.php¨��ÿà÷^¨��š˜t´������5���src/Fixer/CastNotation/ModernizeTypesCastingFixer.phpª ��ÿà÷^ª ��m–ªÀ´������+���src/Fixer/ControlStructure/IncludeFixer.phpÅ ��ÿà÷^Å ��jè}´������9���src/Fixer/ControlStructure/NoUnneededCurlyBracesFixer.phpV ��ÿà÷^V ��'›Ð|´������1���src/Fixer/ControlStructure/NoUselessElseFixer.phpß��ÿà÷^ß��vÏ­´������7���src/Fixer/ControlStructure/NoAlternativeSyntaxFixer.phpÎ��ÿà÷^Î��ÉQü^´������3���src/Fixer/ControlStructure/SwitchCaseSpaceFixer.phpï��ÿà÷^ï��=«‰§´������@���src/Fixer/ControlStructure/NoUnneededControlParenthesesFixer.phpz��ÿà÷^z��¶úðŽ´������2���src/Fixer/ControlStructure/NoBreakCommentFixer.phpÆ!��ÿà÷^Æ!��S‹/´������>���src/Fixer/ControlStructure/SwitchCaseSemicolonToColonFixer.phpÁ��ÿà÷^Á��<�ô������*���src/Fixer/ControlStructure/ElseifFixer.phpF��ÿà÷^F��ðè'k´������=���src/Fixer/ControlStructure/NoTrailingCommaInListCallFixer.phpÎ��ÿà÷^Î��Y„ÊN´������-���src/Fixer/ControlStructure/YodaStyleFixer.phpÝ4��ÿà÷^Ý4��¾zƒ´������7���src/Fixer/ControlStructure/NoSuperfluousElseifFixer.phpÐ��ÿà÷^Ð��
  121. ñ�‘´���������src/PregException.phpg���ÿà÷^g���<Eš´������*���src/Indicator/PhpUnitTestCaseIndicator.phpb��ÿà÷^b��ȶ´������B���src/ConfigurationException/RequiredFixerConfigurationException.php£���ÿà÷^£���‹”Œ´������G���src/ConfigurationException/InvalidForEnvFixerConfigurationException.php¨���ÿà÷^¨���wSõδ������A���src/ConfigurationException/InvalidFixerConfigurationException.php5��ÿà÷^5��{øI´������<���src/ConfigurationException/InvalidConfigurationException.phpª��ÿà÷^ª��#sÖk´������ ���src/Utils.phpp��ÿà÷^p��»wõÄ´���������src/Tokenizer/Token.php»!��ÿà÷^»!��Í¿¡´������0���src/Tokenizer/Resolver/TypeShortNameResolver.php\��ÿà÷^\��ý-Ïb´������&���src/Tokenizer/TransformerInterface.phpN��ÿà÷^N��–´������ ���src/Tokenizer/TokensAnalyzer.phpd2��ÿà÷^d2��õè ´������:���src/Tokenizer/Generator/NamespacedStringTokenGenerator.php£��ÿà÷^£��ÝŠ�j´���������src/Tokenizer/CodeHasher.phpÑ���ÿà÷^Ñ���VâJþ´������:���src/Tokenizer/Transformer/WhitespacyCommentTransformer.phpÐ��ÿà÷^Ð���嬆´������5���src/Tokenizer/Transformer/NullableTypeTransformer.phpL��ÿà÷^L��¯›I&´������3���src/Tokenizer/Transformer/CurlyBraceTransformer.phpo��ÿà÷^o��N¨Má´������,���src/Tokenizer/Transformer/UseTransformer.php¸��ÿà÷^¸��;üÑ”´������6���src/Tokenizer/Transformer/ClassConstantTransformer.php��ÿà÷^��š™ó´´������6���src/Tokenizer/Transformer/ArrayTypehintTransformer.phpÛ��ÿà÷^Û��ÈùÍq´������:���src/Tokenizer/Transformer/NamespaceOperatorTransformer.phpú��ÿà÷^ú��÷t�´������/���src/Tokenizer/Transformer/ImportTransformer.php#��ÿà÷^#�� “P‘´������2���src/Tokenizer/Transformer/TypeColonTransformer.php»��ÿà÷^»��a%O5´������@���src/Tokenizer/Transformer/BraceClassInstantiationTransformer.phpÜ��ÿà÷^Ü��ïK ;´������8���src/Tokenizer/Transformer/TypeAlternationTransformer.phpi��ÿà÷^i��è²Ë9´������2���src/Tokenizer/Transformer/ReturnRefTransformer.phpÒ��ÿà÷^Ò��· Ìu´������4���src/Tokenizer/Transformer/SquareBraceTransformer.php± ��ÿà÷^± ��Jví®´������,���src/Tokenizer/Analyzer/ArgumentsAnalyzer.phpÔ ��ÿà÷^Ô ��¦ä"´������+���src/Tokenizer/Analyzer/CommentsAnalyzer.phpñ��ÿà÷^ñ��ýºÔ´������)���src/Tokenizer/Analyzer/BlocksAnalyzer.php!��ÿà÷^!��¹¼=ê´������-���src/Tokenizer/Analyzer/NamespacesAnalyzer.phpù��ÿà÷^ù��b«ƒÄ´������)���src/Tokenizer/Analyzer/ClassyAnalyzer.php��ÿà÷^�� ŒÏ´������0���src/Tokenizer/Analyzer/NamespaceUsesAnalyzer.php��ÿà÷^��ñê¼´������>���src/Tokenizer/Analyzer/Analysis/StartEndTokenAwareAnalysis.php¸���ÿà÷^¸���`9´������8���src/Tokenizer/Analyzer/Analysis/NamespaceUseAnalysis.php±��ÿà÷^±��Ĉ ´������4���src/Tokenizer/Analyzer/Analysis/ArgumentAnalysis.phpA��ÿà÷^A��Ô1WX´������5���src/Tokenizer/Analyzer/Analysis/NamespaceAnalysis.php ��ÿà÷^ ��Â7—ê´������0���src/Tokenizer/Analyzer/Analysis/TypeAnalysis.phpõ��ÿà÷^õ��],D ´������,���src/Tokenizer/Analyzer/FunctionsAnalyzer.php��ÿà÷^��,4Û~´���������src/Tokenizer/Transformers.phpÕ��ÿà÷^Õ��b3Jâ´���������src/Tokenizer/Tokens.php¨R��ÿà÷^¨R��V5¿‰´������%���src/Tokenizer/AbstractTransformer.php{��ÿà÷^{��tß
  122. ´���������src/Tokenizer/CT.phpž��ÿà÷^ž��ìá“ù´���������src/AbstractFixer.php¸��ÿà÷^¸��&ª´���������src/FileReader.php��ÿà÷^��Š1´������ ���src/Cache/DirectoryInterface.php����ÿà÷^����ÐF’d´���������src/Cache/FileHandler.phpL��ÿà÷^L��Oú~à´���������src/Cache/CacheInterface.php��ÿà÷^��'ë­´���������src/Cache/Directory.phpP��ÿà÷^P��…÷¬T´������"���src/Cache/FileHandlerInterface.php¿���ÿà÷^¿���¥ÿîh´���������src/Cache/Cache.php*��ÿà÷^*��oÐÝÜ´���������src/Cache/Signature.php{��ÿà÷^{��#R˜­´������ ���src/Cache/SignatureInterface.php4��ÿà÷^4��ßJ´���������src/Cache/FileCacheManager.phpÎ��ÿà÷^Î��¢š²«´������#���src/Cache/CacheManagerInterface.phpÁ���ÿà÷^Á���ÈD†´���������src/Cache/NullCacheManager.phpè���ÿà÷^è���Â4n´���������ci-integration.shš��ÿà÷^š��|U�{´������(���vendor/symfony/filesystem/Filesystem.phpt:��ÿà÷^t:��ô@ÀC´������)���vendor/symfony/filesystem/LockHandler.php6��ÿà÷^6��|u4´������<���vendor/symfony/filesystem/Exception/IOExceptionInterface.php¦���ÿà÷^¦���jÙwM´������:���vendor/symfony/filesystem/Exception/ExceptionInterface.phpi���ÿà÷^i���$ ÿ›´������3���vendor/symfony/filesystem/Exception/IOException.phpŸ��ÿà÷^Ÿ��†\5œ´������=���vendor/symfony/filesystem/Exception/FileNotFoundException.phpÌ��ÿà÷^Ì��ç†9`´���������vendor/symfony/finder/Glob.phpÕ��ÿà÷^Õ��U)j´������%���vendor/symfony/finder/SplFileInfo.php��ÿà÷^��þ�íù´������5���vendor/symfony/finder/Comparator/NumberComparator.php���ÿà÷^���ÙÚ¡3´������3���vendor/symfony/finder/Comparator/DateComparator.php#��ÿà÷^#��°δ������/���vendor/symfony/finder/Comparator/Comparator.phpˆ��ÿà÷^ˆ��ž»ƒÁ´������:���vendor/symfony/finder/Iterator/SizeRangeFilterIterator.php`��ÿà÷^`��!àky´������1���vendor/symfony/finder/Iterator/FilterIterator.phpÅ��ÿà÷^Å�� œ™´������=���vendor/symfony/finder/Iterator/MultiplePcreFilterIterator.php
  123. ��ÿà÷^
  124. ��úÙÆº´������9���vendor/symfony/finder/Iterator/FilenameFilterIterator.phpr��ÿà÷^r��tu´������;���vendor/symfony/finder/Iterator/DepthRangeFilterIterator.phpî��ÿà÷^î��üÍ�q´������A���vendor/symfony/finder/Iterator/ExcludeDirectoryFilterIterator.phpÞ��ÿà÷^Þ��fÛ_´������=���vendor/symfony/finder/Iterator/RecursiveDirectoryIterator.php= ��ÿà÷^= ��Y¬´������9���vendor/symfony/finder/Iterator/FileTypeFilterIterator.phpZ��ÿà÷^Z��(&ø´������:���vendor/symfony/finder/Iterator/DateRangeFilterIterator.phps��ÿà÷^s��=úµx´������7���vendor/symfony/finder/Iterator/CustomFilterIterator.phpX��ÿà÷^X��DVSB´������5���vendor/symfony/finder/Iterator/PathFilterIterator.phpÜ��ÿà÷^Ü��âÖúF´������<���vendor/symfony/finder/Iterator/FilecontentFilterIterator.phpA��ÿà÷^A��Ä&Þ¤´������3���vendor/symfony/finder/Iterator/SortableIterator.phpN��ÿà÷^N�� %ë´������ ���vendor/symfony/finder/Finder.php "��ÿà÷^ "��ÐR7¨´������9���vendor/symfony/finder/Exception/AccessDeniedException.php„���ÿà÷^„���½¾sœ´������6���vendor/symfony/finder/Exception/ExceptionInterface.php†���ÿà÷^†���Lôà~´������&���vendor/symfony/process/InputStream.php'��ÿà÷^'��³Xã>´������/���vendor/symfony/process/Pipes/PipesInterface.phpm��ÿà÷^m��ï‹u´������-���vendor/symfony/process/Pipes/WindowsPipes.phpú ��ÿà÷^ú ��æ;0´������.���vendor/symfony/process/Pipes/AbstractPipes.phpà
  125. ��ÿà÷^à
  126. ��àym´������*���vendor/symfony/process/Pipes/UnixPipes.php•��ÿà÷^•��º�Š�´������%���vendor/symfony/process/PhpProcess.phpÖ��ÿà÷^Ö���xp´������=���vendor/symfony/process/Exception/ProcessTimedOutException.php��ÿà÷^��ï«´������;���vendor/symfony/process/Exception/ProcessFailedException.phpx��ÿà÷^x��¨Ìzy´������7���vendor/symfony/process/Exception/ExceptionInterface.phpf���ÿà÷^f���]ö>T´������5���vendor/symfony/process/Exception/RuntimeException.php˜���ÿà÷^˜���¢Ø:´������3���vendor/symfony/process/Exception/LogicException.php”���ÿà÷^”��� ³ãñ´������=���vendor/symfony/process/Exception/InvalidArgumentException.php¨���ÿà÷^¨���ÐÀ+_´������'���vendor/symfony/process/ProcessUtils.php7��ÿà÷^7��Ì~¹¥´������)���vendor/symfony/process/ProcessBuilder.php ��ÿà÷^ ��AëeÑ´������.���vendor/symfony/process/PhpExecutableFinder.php±��ÿà÷^±��ùbˆ´������+���vendor/symfony/process/ExecutableFinder.php­��ÿà÷^­��c@�v´������"���vendor/symfony/process/Process.phpl��ÿà÷^l��³Ñ¯¯´������+���vendor/symfony/polyfill-php70/bootstrap.phpx��ÿà÷^x��Ÿ¦±´������'���vendor/symfony/polyfill-php70/Php70.phpˆ��ÿà÷^ˆ��=×+´������E���vendor/symfony/polyfill-php70/Resources/stubs/DivisionByZeroError.php3���ÿà÷^3���û�h;´������A���vendor/symfony/polyfill-php70/Resources/stubs/ArithmeticError.php/���ÿà÷^/���|mÍ´������<���vendor/symfony/polyfill-php70/Resources/stubs/ParseError.php*���ÿà÷^*���•¨á¤´������@���vendor/symfony/polyfill-php70/Resources/stubs/AssertionError.php.���ÿà÷^.���&8úy´������X���vendor/symfony/polyfill-php70/Resources/stubs/SessionUpdateTimestampHandlerInterface.php›���ÿà÷^›���£ú~ó´������;���vendor/symfony/polyfill-php70/Resources/stubs/TypeError.php)���ÿà÷^)���â¸O_´������7���vendor/symfony/polyfill-php70/Resources/stubs/Error.php)���ÿà÷^)���[k ´������&���vendor/symfony/console/Application.phpLg��ÿà÷^Lg�� _›+´������>���vendor/symfony/console/Formatter/OutputFormatterStyleStack.php;��ÿà÷^;��%�œ´������9���vendor/symfony/console/Formatter/OutputFormatterStyle.php›��ÿà÷^›��‹`*´������4���vendor/symfony/console/Formatter/OutputFormatter.php¥��ÿà÷^¥��LV!´������=���vendor/symfony/console/Formatter/OutputFormatterInterface.phpŒ��ÿà÷^Œ��òññÀ´������B���vendor/symfony/console/Formatter/OutputFormatterStyleInterface.php„��ÿà÷^„��÷½G´������8���vendor/symfony/console/Question/ConfirmationQuestion.phpî��ÿà÷^î��íd©?´������,���vendor/symfony/console/Question/Question.phpã ��ÿà÷^ã ��Æ ¦´������2���vendor/symfony/console/Question/ChoiceQuestion.phpB
  127. ��ÿà÷^B
  128. ���ùºÐ´������D���vendor/symfony/console/DependencyInjection/AddConsoleCommandPass.phpb ��ÿà÷^b ��è’œŠ´������#���vendor/symfony/console/Terminal.phps
  129. ��ÿà÷^s
  130. ��;Èiy´������0���vendor/symfony/console/Output/BufferedOutput.php_��ÿà÷^_��‹ >P´������(���vendor/symfony/console/Output/Output.php˜ ��ÿà÷^˜ ��0p´������/���vendor/symfony/console/Output/ConsoleOutput.phpŠ��ÿà÷^Š��‰©ˆû´������8���vendor/symfony/console/Output/ConsoleOutputInterface.phpà���ÿà÷^à���‡†ÆÊ´������.���vendor/symfony/console/Output/StreamOutput.php��ÿà÷^��^�Ó´������1���vendor/symfony/console/Output/OutputInterface.php£��ÿà÷^£��n ´������,���vendor/symfony/console/Output/NullOutput.phpÏ��ÿà÷^Ï��®˜‹Z´������6���vendor/symfony/console/Event/ConsoleExceptionEvent.phpÐ��ÿà÷^Ð��*¦\È´������4���vendor/symfony/console/Event/ConsoleCommandEvent.php°��ÿà÷^°��!�È´������6���vendor/symfony/console/Event/ConsoleTerminateEvent.phpz��ÿà÷^z��³,îL´������-���vendor/symfony/console/Event/ConsoleEvent.phpÌ��ÿà÷^Ì��ÙåÓ´������2���vendor/symfony/console/Event/ConsoleErrorEvent.phpb��ÿà÷^b��èMh´������.���vendor/symfony/console/Input/InputArgument.php ��ÿà÷^ ��•;À´������0���vendor/symfony/console/Input/InputDefinition.php¸��ÿà÷^¸��B"퀴������&���vendor/symfony/console/Input/Input.phpG ��ÿà÷^G ��ôùçè´������,���vendor/symfony/console/Input/StringInput.phpW��ÿà÷^W��}èËj´������*���vendor/symfony/console/Input/ArgvInput.php£��ÿà÷^£�� ç´������/���vendor/symfony/console/Input/InputInterface.phpÏ��ÿà÷^Ï��rrg´������,���vendor/symfony/console/Input/InputOption.php ��ÿà÷^ ��¾Ý´������4���vendor/symfony/console/Input/InputAwareInterface.php˜���ÿà÷^˜���­O°´������9���vendor/symfony/console/Input/StreamableInputInterface.phpÎ���ÿà÷^Î���ÖÕB›´������+���vendor/symfony/console/Input/ArrayInput.php+ ��ÿà÷^+ ��'ý½Ù´������=���vendor/symfony/console/Exception/CommandNotFoundException.phpÏ��ÿà÷^Ï��K*â5´������;���vendor/symfony/console/Exception/InvalidOptionException.php¦���ÿà÷^¦���Ë×H´������7���vendor/symfony/console/Exception/ExceptionInterface.phpf���ÿà÷^f���¡ABª´������5���vendor/symfony/console/Exception/RuntimeException.php–���ÿà÷^–���Ùí,6´������3���vendor/symfony/console/Exception/LogicException.php’���ÿà÷^’���ÍO\e´������=���vendor/symfony/console/Exception/InvalidArgumentException.php¦���ÿà÷^¦���Ö̽Z´������8���vendor/symfony/console/Descriptor/MarkdownDescriptor.php˜��ÿà÷^˜��Å>4�´������<���vendor/symfony/console/Descriptor/ApplicationDescription.php¿ ��ÿà÷^¿ ��@?,×´������0���vendor/symfony/console/Descriptor/Descriptor.phps��ÿà÷^s��cB·M´������4���vendor/symfony/console/Descriptor/JsonDescriptor.phpª��ÿà÷^ª��vf{’´������9���vendor/symfony/console/Descriptor/DescriptorInterface.phpõ���ÿà÷^õ���ºP~µ´������4���vendor/symfony/console/Descriptor/TextDescriptor.php÷!��ÿà÷^÷!��u²D´������3���vendor/symfony/console/Descriptor/XmlDescriptor.php ��ÿà÷^ ��4 δ������.���vendor/symfony/console/Command/HelpCommand.phpœ��ÿà÷^œ��õ<”´������.���vendor/symfony/console/Command/ListCommand.php��ÿà÷^��5œÿ-´������*���vendor/symfony/console/Command/Command.php;!��ÿà÷^;!��…~�´������0���vendor/symfony/console/Command/LockableTrait.php2��ÿà÷^2��N Òß´������/���vendor/symfony/console/Tester/CommandTester.php¿��ÿà÷^¿��…¢´������3���vendor/symfony/console/Tester/ApplicationTester.php' ��ÿà÷^' ��aÁå»´������6���vendor/symfony/console/Helper/DebugFormatterHelper.phpj��ÿà÷^j��OGú ´������1���vendor/symfony/console/Helper/HelperInterface.phpå���ÿà÷^å���Š ´������/���vendor/symfony/console/Helper/ProcessHelper.php
  131. ��ÿà÷^
  132. ��¹Oßÿ´������2���vendor/symfony/console/Helper/InputAwareHelper.phpc��ÿà÷^c��Ìøƒ´������(���vendor/symfony/console/Helper/Helper.phpk��ÿà÷^k��©'颴������'���vendor/symfony/console/Helper/Table.php™-��ÿà÷^™-��¦»œ´������2���vendor/symfony/console/Helper/DescriptorHelper.phpe��ÿà÷^e��2‰Î_´������7���vendor/symfony/console/Helper/SymfonyQuestionHelper.php ��ÿà÷^ ���~S´������0���vendor/symfony/console/Helper/TableSeparator.phpÅ���ÿà÷^Å���¼õËü´������1���vendor/symfony/console/Helper/FormatterHelper.phpD��ÿà÷^D��+¦æL´������+���vendor/symfony/console/Helper/HelperSet.phpf��ÿà÷^f��þxÁ´������,���vendor/symfony/console/Helper/TableStyle.php'
  133. ��ÿà÷^'
  134. ��gùb!´������+���vendor/symfony/console/Helper/TableCell.phpv��ÿà÷^v��Í+Í ´������3���vendor/symfony/console/Helper/ProgressIndicator.phpD��ÿà÷^D��JxñF´������0���vendor/symfony/console/Helper/QuestionHelper.php %��ÿà÷^ %��,¥V�´������-���vendor/symfony/console/Helper/ProgressBar.php7%��ÿà÷^7%��AÁò<´������/���vendor/symfony/console/Style/StyleInterface.phpÎ��ÿà÷^Î��Á ´������-���vendor/symfony/console/Style/SymfonyStyle.phpY��ÿà÷^Y���„í´������,���vendor/symfony/console/Style/OutputStyle.phpW��ÿà÷^W��ÉÈ?Š´������/���vendor/symfony/console/Logger/ConsoleLogger.phpî
  135. ��ÿà÷^î
  136. ��Û Z´������(���vendor/symfony/console/ConsoleEvents.php��ÿà÷^��“'Ñð´������?���vendor/symfony/console/CommandLoader/ContainerCommandLoader.phpH��ÿà÷^H��-ñ÷ß´������?���vendor/symfony/console/CommandLoader/CommandLoaderInterface.phpG��ÿà÷^G��?–�€´������=���vendor/symfony/console/CommandLoader/FactoryCommandLoader.php¡��ÿà÷^¡��þmŸ…´������6���vendor/symfony/console/EventListener/ErrorListener.php"��ÿà÷^"��M^“ ´������%���vendor/symfony/debug/ErrorHandler.php
  137. H��ÿà÷^
  138. H��Ÿø-´������)���vendor/symfony/debug/ExceptionHandler.php„M��ÿà÷^„M��>eÕ‰´������)���vendor/symfony/debug/DebugClassLoader.phpV+��ÿà÷^V+���uô������I���vendor/symfony/debug/FatalErrorHandler/ClassNotFoundFatalErrorHandler.phpz��ÿà÷^z��tr-´������K���vendor/symfony/debug/FatalErrorHandler/UndefinedMethodFatalErrorHandler.phpO��ÿà÷^O��hÔÑ´������M���vendor/symfony/debug/FatalErrorHandler/UndefinedFunctionFatalErrorHandler.php‚��ÿà÷^‚��Fd-´������E���vendor/symfony/debug/FatalErrorHandler/FatalErrorHandlerInterface.php��ÿà÷^��ĹBV´������6���vendor/symfony/debug/Exception/FatalErrorException.php.��ÿà÷^.��ôJ0´������=���vendor/symfony/debug/Exception/UndefinedFunctionException.phpš��ÿà÷^š���ñJÀ´������8���vendor/symfony/debug/Exception/ContextErrorException.php��ÿà÷^��^€¼@´������7���vendor/symfony/debug/Exception/OutOfMemoryException.php~���ÿà÷^~���ë¨oâ´������7���vendor/symfony/debug/Exception/SilencedErrorContext.php(��ÿà÷^(��ƒ+là´������3���vendor/symfony/debug/Exception/FlattenException.phpn��ÿà÷^n��wˆÊ
  139. ´������6���vendor/symfony/debug/Exception/FatalThrowableError.phpW��ÿà÷^W��?àèK´������9���vendor/symfony/debug/Exception/ClassNotFoundException.php–��ÿà÷^–��i‰æô´������;���vendor/symfony/debug/Exception/UndefinedMethodException.php˜��ÿà÷^˜��nöêØ´������(���vendor/symfony/debug/BufferingLogger.php`��ÿà÷^`��”DmÛ´���������vendor/symfony/debug/Debug.php+��ÿà÷^+��9Åb´������+���vendor/symfony/polyfill-php72/bootstrap.php��ÿà÷^��36º6´������'���vendor/symfony/polyfill-php72/Php72.php¹��ÿà÷^¹��u;ˆb´������+���vendor/symfony/polyfill-ctype/bootstrap.phpä��ÿà÷^ä��—o£´������'���vendor/symfony/polyfill-ctype/Ctype.phpH ��ÿà÷^H ��³�ÕÝ´������.���vendor/symfony/polyfill-mbstring/bootstrap.php)��ÿà÷^)��p¼B´������-���vendor/symfony/polyfill-mbstring/Mbstring.php€G��ÿà÷^€G��ɖз´������@���vendor/symfony/polyfill-mbstring/Resources/unidata/upperCase.phpîU��ÿà÷^îU��`þ8Q´������F���vendor/symfony/polyfill-mbstring/Resources/unidata/titleCaseRegexp.phpã��ÿà÷^ã��öy_•´������@���vendor/symfony/polyfill-mbstring/Resources/unidata/lowerCase.php÷T��ÿà÷^÷T��ß2ª?´������3���vendor/symfony/options-resolver/OptionsResolver.php·:��ÿà÷^·:��gìe´������E���vendor/symfony/options-resolver/Debug/OptionsResolverIntrospector.php��ÿà÷^���ãÑÜ´������+���vendor/symfony/options-resolver/Options.php{���ÿà÷^{���é|·Š´������E���vendor/symfony/options-resolver/Exception/MissingOptionsException.php’���ÿà÷^’���=¼½�´������=���vendor/symfony/options-resolver/Exception/AccessException.phpž���ÿà÷^ž���›5´������@���vendor/symfony/options-resolver/Exception/ExceptionInterface.phpn���ÿà÷^n���Ìøy´������G���vendor/symfony/options-resolver/Exception/OptionDefinitionException.php§���ÿà÷^§���ó@4�´������F���vendor/symfony/options-resolver/Exception/NoConfigurationException.phpõ���ÿà÷^õ���j‘®E´������G���vendor/symfony/options-resolver/Exception/UndefinedOptionsException.php•���ÿà÷^•���p Í�´������E���vendor/symfony/options-resolver/Exception/InvalidOptionsException.php’���ÿà÷^’���ëÿk ´������C���vendor/symfony/options-resolver/Exception/NoSuchOptionException.php®���ÿà÷^®���g]ÝÈ´������F���vendor/symfony/options-resolver/Exception/InvalidArgumentException.php°���ÿà÷^°���²G¹´������9���vendor/symfony/event-dispatcher/Debug/WrappedListener.php¾
  140. ��ÿà÷^¾
  141. ��!�¥´������K���vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcherInterface.php5��ÿà÷^5��fV´������B���vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php��ÿà÷^��O '´������M���vendor/symfony/event-dispatcher/DependencyInjection/RegisterListenersPass.phpÙ��ÿà÷^Ù��\]¯´������<���vendor/symfony/event-dispatcher/EventDispatcherInterface.phpŠ��ÿà÷^Š��p´«X´������0���vendor/symfony/event-dispatcher/GenericEvent.phpl��ÿà÷^l��@F^Ä´������3���vendor/symfony/event-dispatcher/EventDispatcher.php3��ÿà÷^3��Krx"´������A���vendor/symfony/event-dispatcher/ContainerAwareEventDispatcher.php×��ÿà÷^×��,¾ÏJ´������)���vendor/symfony/event-dispatcher/Event.php:��ÿà÷^:��EÚ ´������<���vendor/symfony/event-dispatcher/ImmutableEventDispatcher.phpq��ÿà÷^q��ñ½´������<���vendor/symfony/event-dispatcher/EventSubscriberInterface.phpÄ���ÿà÷^Ä���ýèŸô´������,���vendor/symfony/stopwatch/StopwatchPeriod.phpp��ÿà÷^p��ΧÉ!´������&���vendor/symfony/stopwatch/Stopwatch.php��ÿà÷^��#i{ ´������+���vendor/symfony/stopwatch/StopwatchEvent.php® ��ÿà÷^® ��!úA ´������$���vendor/symfony/stopwatch/Section.php²��ÿà÷^²��úó-�´���������vendor/autoload.phpŒ���ÿà÷^Œ���y? D´������#���vendor/composer/autoload_static.php*��ÿà÷^*��Ú÷¼ý´������4���vendor/composer/xdebug-handler/src/XdebugHandler.phpÌ!��ÿà÷^Ì!��:{•´������0���vendor/composer/xdebug-handler/src/PhpConfig.php´��ÿà÷^´��*D’�´������-���vendor/composer/xdebug-handler/src/Status.php
  142. ��ÿà÷^
  143. ��$Ÿv-´������.���vendor/composer/xdebug-handler/src/Process.php€ ��ÿà÷^€ ��«½5Ê´������!���vendor/composer/autoload_real.php���ÿà÷^���Já´������"���vendor/composer/autoload_files.php5��ÿà÷^5��ó|p´������!���vendor/composer/autoload_psr4.phpñ��ÿà÷^ñ��ô¦¶´������%���vendor/composer/autoload_classmap.php��ÿà÷^��ÆÉ;­´������,���vendor/composer/semver/src/VersionParser.php¸*��ÿà÷^¸*��GLÇí´������<���vendor/composer/semver/src/Constraint/AbstractConstraint.phpî��ÿà÷^î��Õ­w-´������4���vendor/composer/semver/src/Constraint/Constraint.php’ ��ÿà÷^’ ��I&â´������=���vendor/composer/semver/src/Constraint/ConstraintInterface.phpß���ÿà÷^ß���0C,‡´������9���vendor/composer/semver/src/Constraint/EmptyConstraint.phpä��ÿà÷^ä��ïõ‚³´������9���vendor/composer/semver/src/Constraint/MultiConstraint.php,��ÿà÷^,��0°=´������)���vendor/composer/semver/src/Comparator.php��ÿà÷^��wlƒï´������%���vendor/composer/semver/src/Semver.php‚��ÿà÷^‚��?nÝ´������'���vendor/composer/autoload_namespaces.phpd���ÿà÷^d���Z¡¦H´���������vendor/composer/ClassLoader.php���ÿà÷^���Xñv3´������M���vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/IndexedReader.phpÓ��ÿà÷^Ó��nWS´������F���vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/Reader.php"��ÿà÷^"��Р@Ö´������K���vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/TokenParser.php|��ÿà÷^|��w¬´������P���vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/AnnotationReader.phph��ÿà÷^h��zÔ·´������S���vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/Annotation/Required.phpm���ÿà÷^m���÷ÑZ’´������[���vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/Annotation/IgnoreAnnotation.phpð��ÿà÷^ð��¥ø´������T���vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/Annotation/Attribute.php¯���ÿà÷^¯���fʓ۴������U���vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/Annotation/Attributes.php����ÿà÷^����¾~½Ä´������O���vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/Annotation/Enum.phpt��ÿà÷^t��°ø]´������Q���vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/Annotation/Target.php0��ÿà÷^0��Û u£´������O���vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/FileCacheReader.phpƒ��ÿà÷^ƒ��ÞôÐq´������I���vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/PhpParser.php��ÿà÷^��V§¸´������H���vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/DocLexer.phpw��ÿà÷^w��‰&n´������L���vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/CachedReader.phpj��ÿà÷^j��—&}á´������S���vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/AnnotationException.php-��ÿà÷^-���æa´������I���vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/DocParser.php V��ÿà÷^ V��àõû`´������J���vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/Annotation.php<��ÿà÷^<��z˜X´������R���vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/AnnotationRegistry.phpî��ÿà÷^î��÷ޱü´������V���vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/SimpleAnnotationReader.phpJ��ÿà÷^J��q*´������A���vendor/doctrine/lexer/lib/Doctrine/Common/Lexer/AbstractLexer.php9 ��ÿà÷^9 ��ŠÞZ¹´������/���vendor/psr/log/Psr/Log/LoggerAwareInterface.php|���ÿà÷^|���$£ˆ´������+���vendor/psr/log/Psr/Log/LoggerAwareTrait.php§���ÿà÷^§���T½úB´������)���vendor/psr/log/Psr/Log/AbstractLogger.php;��ÿà÷^;��ñ>3[´������%���vendor/psr/log/Psr/Log/NullLogger.php ���ÿà÷^ ���ÆDi¯´������#���vendor/psr/log/Psr/Log/LogLevel.phpû���ÿà÷^û���jðñ8´������&���vendor/psr/log/Psr/Log/LoggerTrait.phpk��ÿà÷^k��£}‰’´������*���vendor/psr/log/Psr/Log/LoggerInterface.phpÈ��ÿà÷^È��šx´������3���vendor/psr/log/Psr/Log/InvalidArgumentException.php`���ÿà÷^`��� ˆX1´������+���vendor/php-cs-fixer/diff/src/v1_4/Chunk.php ��ÿà÷^ ��ŽÅýÛ´������*���vendor/php-cs-fixer/diff/src/v1_4/Line.php���ÿà÷^���!êâ/´������,���vendor/php-cs-fixer/diff/src/v1_4/Differ.phpa��ÿà÷^a��¥B¾´������]���vendor/php-cs-fixer/diff/src/v1_4/LCS/TimeEfficientLongestCommonSubsequenceImplementation.phpÜ��ÿà÷^Ü��® 8´������_���vendor/php-cs-fixer/diff/src/v1_4/LCS/MemoryEfficientLongestCommonSubsequenceImplementation.php��ÿà÷^��Í:ž´������B���vendor/php-cs-fixer/diff/src/v1_4/LCS/LongestCommonSubsequence.php™���ÿà÷^™���÷)—´������,���vendor/php-cs-fixer/diff/src/v1_4/Parser.phpõ��ÿà÷^õ��6qÑc´������*���vendor/php-cs-fixer/diff/src/v1_4/Diff.phpí��ÿà÷^í��0}n´������+���vendor/php-cs-fixer/diff/src/v3_0/Chunk.phpð��ÿà÷^ð��&_Fê´������*���vendor/php-cs-fixer/diff/src/v3_0/Line.phpŒ��ÿà÷^Œ��‹8ç´������,���vendor/php-cs-fixer/diff/src/v3_0/Differ.phpþ��ÿà÷^þ�� ûF*´������,���vendor/php-cs-fixer/diff/src/v3_0/Parser.php÷��ÿà÷^÷��«j?Š´������U���vendor/php-cs-fixer/diff/src/v3_0/TimeEfficientLongestCommonSubsequenceCalculator.phpï��ÿà÷^ï��#•1ñ´������K���vendor/php-cs-fixer/diff/src/v3_0/Output/StrictUnifiedDiffOutputBuilder.php��ÿà÷^��  }´������B���vendor/php-cs-fixer/diff/src/v3_0/Output/DiffOnlyOutputBuilder.phpú��ÿà÷^ú��¡7î“´������G���vendor/php-cs-fixer/diff/src/v3_0/Output/AbstractChunkOutputBuilder.php��ÿà÷^��ˆ=�h´������G���vendor/php-cs-fixer/diff/src/v3_0/Output/DiffOutputBuilderInterface.phpŠ���ÿà÷^Š���R8Oå´������E���vendor/php-cs-fixer/diff/src/v3_0/Output/UnifiedDiffOutputBuilder.php|��ÿà÷^|��¿o”–´������H���vendor/php-cs-fixer/diff/src/v3_0/LongestCommonSubsequenceCalculator.phpœ���ÿà÷^œ���kãb´������F���vendor/php-cs-fixer/diff/src/v3_0/Exception/ConfigurationException.php½��ÿà÷^½��k¦s´������9���vendor/php-cs-fixer/diff/src/v3_0/Exception/Exception.phpH���ÿà÷^H���{n‰´������H���vendor/php-cs-fixer/diff/src/v3_0/Exception/InvalidArgumentException.phpŠ���ÿà÷^Š���ù˜û´������*���vendor/php-cs-fixer/diff/src/v3_0/Diff.phpè��ÿà÷^è��¨aF�´������W���vendor/php-cs-fixer/diff/src/v3_0/MemoryEfficientLongestCommonSubsequenceCalculator.php
  144. ��ÿà÷^
  145. ��´€_‡´������W���vendor/php-cs-fixer/diff/src/GeckoPackages/DiffOutputBuilder/ConfigurationException.phpÞ��ÿà÷^Þ��áz8´������Y���vendor/php-cs-fixer/diff/src/GeckoPackages/DiffOutputBuilder/UnifiedDiffOutputBuilder.php��ÿà÷^��@´:L´������+���vendor/php-cs-fixer/diff/src/v2_0/Chunk.phpð��ÿà÷^ð��œk—Ë´������*���vendor/php-cs-fixer/diff/src/v2_0/Line.phpŒ��ÿà÷^Œ��AŸQû´������,���vendor/php-cs-fixer/diff/src/v2_0/Differ.php+��ÿà÷^+��N1 δ������,���vendor/php-cs-fixer/diff/src/v2_0/Parser.php÷��ÿà÷^÷��l°àC´������U���vendor/php-cs-fixer/diff/src/v2_0/TimeEfficientLongestCommonSubsequenceCalculator.phpï��ÿà÷^ï��˜æìK´������B���vendor/php-cs-fixer/diff/src/v2_0/Output/DiffOnlyOutputBuilder.php¤��ÿà÷^¤��E{I´������G���vendor/php-cs-fixer/diff/src/v2_0/Output/AbstractChunkOutputBuilder.php��ÿà÷^��1ò%|´������G���vendor/php-cs-fixer/diff/src/v2_0/Output/DiffOutputBuilderInterface.php‰���ÿà÷^‰���òu¤´������E���vendor/php-cs-fixer/diff/src/v2_0/Output/UnifiedDiffOutputBuilder.phpŽ ��ÿà÷^Ž ��.ÃÛ´������H���vendor/php-cs-fixer/diff/src/v2_0/LongestCommonSubsequenceCalculator.phpœ���ÿà÷^œ���5ä´������9���vendor/php-cs-fixer/diff/src/v2_0/Exception/Exception.phpH���ÿà÷^H���s�é-´������H���vendor/php-cs-fixer/diff/src/v2_0/Exception/InvalidArgumentException.phpŠ���ÿà÷^Š���;—ž$´������*���vendor/php-cs-fixer/diff/src/v2_0/Diff.phpè��ÿà÷^è��¹ù’´������W���vendor/php-cs-fixer/diff/src/v2_0/MemoryEfficientLongestCommonSubsequenceCalculator.php
  146. ��ÿà÷^
  147. ��âh ´������>���vendor/paragonie/random_compat/lib/random_bytes_com_dotnet.php÷��ÿà÷^÷��vA¨´������:���vendor/paragonie/random_compat/lib/random_bytes_mcrypt.php5��ÿà÷^5��IWyl´������8���vendor/paragonie/random_compat/lib/byte_safe_strings.phpp��ÿà÷^p��3Š6d´������-���vendor/paragonie/random_compat/lib/random.phpï ��ÿà÷^ï ��“êá´������=���vendor/paragonie/random_compat/lib/random_bytes_libsodium.phpá��ÿà÷^á��3+2g´������5���vendor/paragonie/random_compat/lib/error_polyfill.php��ÿà÷^��úša4´������2���vendor/paragonie/random_compat/lib/cast_to_int.php��ÿà÷^���û|w´������D���vendor/paragonie/random_compat/lib/random_bytes_libsodium_legacy.phpð��ÿà÷^ð��ˆÏ!¢´������?���vendor/paragonie/random_compat/lib/random_bytes_dev_urandom.php·��ÿà÷^·��°ü´À´������1���vendor/paragonie/random_compat/lib/random_int.php.��ÿà÷^.��m1Ï´���������LICENSES��ÿà÷^S��RMSê´������ ���php-cs-fixer– ��ÿà÷^– ��ÞìG¸´������<?php
  148. namespace PhpCsFixer;
  149. use PhpCsFixer\Doctrine\Annotation\Tokens as DoctrineAnnotationTokens;
  150. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  151. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  152. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  153. use PhpCsFixer\Tokenizer\Token as PhpToken;
  154. use PhpCsFixer\Tokenizer\Tokens as PhpTokens;
  155. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  156. abstract class AbstractDoctrineAnnotationFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface
  157. {
  158. private $classyElements;
  159. public function isCandidate(PhpTokens $tokens)
  160. {
  161. return $tokens->isTokenKindFound(T_DOC_COMMENT);
  162. }
  163. protected function applyFix(\SplFileInfo $file, PhpTokens $phpTokens)
  164. {
  165. $analyzer = new TokensAnalyzer($phpTokens);
  166. $this->classyElements = $analyzer->getClassyElements();
  167. foreach ($phpTokens->findGivenKind(T_DOC_COMMENT) as $index => $docCommentToken) {
  168. if (!$this->nextElementAcceptsDoctrineAnnotations($phpTokens, $index)) {
  169. continue;
  170. }
  171. $tokens = DoctrineAnnotationTokens::createFromDocComment(
  172. $docCommentToken,
  173. $this->configuration['ignored_tags']
  174. );
  175. $this->fixAnnotations($tokens);
  176. $phpTokens[$index] = new PhpToken([T_DOC_COMMENT, $tokens->getCode()]);
  177. }
  178. }
  179. abstract protected function fixAnnotations(DoctrineAnnotationTokens $doctrineAnnotationTokens);
  180. protected function createConfigurationDefinition()
  181. {
  182. return new FixerConfigurationResolver([
  183. (new FixerOptionBuilder('ignored_tags', 'List of tags that must not be treated as Doctrine Annotations.'))
  184. ->setAllowedTypes(['array'])
  185. ->setAllowedValues([static function ($values) {
  186. foreach ($values as $value) {
  187. if (!\is_string($value)) {
  188. return false;
  189. }
  190. }
  191. return true;
  192. }])
  193. ->setDefault([
  194. 'abstract',
  195. 'access',
  196. 'code',
  197. 'deprec',
  198. 'encode',
  199. 'exception',
  200. 'final',
  201. 'ingroup',
  202. 'inheritdoc',
  203. 'inheritDoc',
  204. 'magic',
  205. 'name',
  206. 'toc',
  207. 'tutorial',
  208. 'private',
  209. 'static',
  210. 'staticvar',
  211. 'staticVar',
  212. 'throw',
  213. 'api',
  214. 'author',
  215. 'category',
  216. 'copyright',
  217. 'deprecated',
  218. 'example',
  219. 'filesource',
  220. 'global',
  221. 'ignore',
  222. 'internal',
  223. 'license',
  224. 'link',
  225. 'method',
  226. 'package',
  227. 'param',
  228. 'property',
  229. 'property-read',
  230. 'property-write',
  231. 'return',
  232. 'see',
  233. 'since',
  234. 'source',
  235. 'subpackage',
  236. 'throws',
  237. 'todo',
  238. 'TODO',
  239. 'usedBy',
  240. 'uses',
  241. 'var',
  242. 'version',
  243. 'after',
  244. 'afterClass',
  245. 'backupGlobals',
  246. 'backupStaticAttributes',
  247. 'before',
  248. 'beforeClass',
  249. 'codeCoverageIgnore',
  250. 'codeCoverageIgnoreStart',
  251. 'codeCoverageIgnoreEnd',
  252. 'covers',
  253. 'coversDefaultClass',
  254. 'coversNothing',
  255. 'dataProvider',
  256. 'depends',
  257. 'expectedException',
  258. 'expectedExceptionCode',
  259. 'expectedExceptionMessage',
  260. 'expectedExceptionMessageRegExp',
  261. 'group',
  262. 'large',
  263. 'medium',
  264. 'preserveGlobalState',
  265. 'requires',
  266. 'runTestsInSeparateProcesses',
  267. 'runInSeparateProcess',
  268. 'small',
  269. 'test',
  270. 'testdox',
  271. 'ticket',
  272. 'uses',
  273. 'SuppressWarnings',
  274. 'noinspection',
  275. 'package_version',
  276. 'enduml',
  277. 'startuml',
  278. 'fix',
  279. 'FIXME',
  280. 'fixme',
  281. 'override',
  282. ])
  283. ->getOption(),
  284. ]);
  285. }
  286. private function nextElementAcceptsDoctrineAnnotations(PhpTokens $tokens, $index)
  287. {
  288. do {
  289. $index = $tokens->getNextMeaningfulToken($index);
  290. if (null === $index) {
  291. return false;
  292. }
  293. } while ($tokens[$index]->isGivenKind([T_ABSTRACT, T_FINAL]));
  294. if ($tokens[$index]->isClassy()) {
  295. return true;
  296. }
  297. while ($tokens[$index]->isGivenKind([T_PUBLIC, T_PROTECTED, T_PRIVATE, T_FINAL, T_ABSTRACT])) {
  298. $index = $tokens->getNextMeaningfulToken($index);
  299. }
  300. return isset($this->classyElements[$index]);
  301. }
  302. }
  303. <?php
  304. namespace PhpCsFixer\FixerDefinition;
  305. final class FixerDefinition implements FixerDefinitionInterface
  306. {
  307. private $riskyDescription;
  308. private $configurationDescription;
  309. private $defaultConfiguration;
  310. private $codeSamples;
  311. private $summary;
  312. private $description;
  313. public function __construct(
  314. $summary,
  315. array $codeSamples,
  316. $description = null,
  317. $configurationDescription = null,
  318. array $defaultConfiguration = null,
  319. $riskyDescription = null
  320. ) {
  321. if (6 === \func_num_args()) {
  322. @trigger_error('Arguments #5 and #6 of FixerDefinition::__construct() are deprecated and will be removed in 3.0, use argument #4 instead.', E_USER_DEPRECATED);
  323. } elseif (5 === \func_num_args()) {
  324. @trigger_error('Argument #5 of FixerDefinition::__construct() is deprecated and will be removed in 3.0.', E_USER_DEPRECATED);
  325. } else {
  326. $riskyDescription = $configurationDescription;
  327. $configurationDescription = null;
  328. }
  329. $this->summary = $summary;
  330. $this->codeSamples = $codeSamples;
  331. $this->description = $description;
  332. $this->configurationDescription = $configurationDescription;
  333. $this->defaultConfiguration = $defaultConfiguration;
  334. $this->riskyDescription = $riskyDescription;
  335. }
  336. public function getSummary()
  337. {
  338. return $this->summary;
  339. }
  340. public function getDescription()
  341. {
  342. return $this->description;
  343. }
  344. public function getConfigurationDescription()
  345. {
  346. @trigger_error(sprintf('%s is deprecated and will be removed in 3.0.', __METHOD__), E_USER_DEPRECATED);
  347. return $this->configurationDescription;
  348. }
  349. public function getDefaultConfiguration()
  350. {
  351. @trigger_error(sprintf('%s is deprecated and will be removed in 3.0.', __METHOD__), E_USER_DEPRECATED);
  352. return $this->defaultConfiguration;
  353. }
  354. public function getRiskyDescription()
  355. {
  356. return $this->riskyDescription;
  357. }
  358. public function getCodeSamples()
  359. {
  360. return $this->codeSamples;
  361. }
  362. }
  363. <?php
  364. namespace PhpCsFixer\FixerDefinition;
  365. interface VersionSpecificCodeSampleInterface extends CodeSampleInterface
  366. {
  367. public function isSuitableFor($version);
  368. }
  369. <?php
  370. namespace PhpCsFixer\FixerDefinition;
  371. final class VersionSpecificCodeSample implements VersionSpecificCodeSampleInterface
  372. {
  373. private $codeSample;
  374. private $versionSpecification;
  375. public function __construct(
  376. $code,
  377. VersionSpecificationInterface $versionSpecification,
  378. array $configuration = null
  379. ) {
  380. $this->codeSample = new CodeSample($code, $configuration);
  381. $this->versionSpecification = $versionSpecification;
  382. }
  383. public function getCode()
  384. {
  385. return $this->codeSample->getCode();
  386. }
  387. public function getConfiguration()
  388. {
  389. return $this->codeSample->getConfiguration();
  390. }
  391. public function isSuitableFor($version)
  392. {
  393. return $this->versionSpecification->isSatisfiedBy($version);
  394. }
  395. }
  396. <?php
  397. namespace PhpCsFixer\FixerDefinition;
  398. interface FixerDefinitionInterface
  399. {
  400. public function getSummary();
  401. public function getDescription();
  402. public function getConfigurationDescription();
  403. public function getDefaultConfiguration();
  404. public function getRiskyDescription();
  405. public function getCodeSamples();
  406. }
  407. <?php
  408. namespace PhpCsFixer\FixerDefinition;
  409. final class CodeSample implements CodeSampleInterface
  410. {
  411. private $code;
  412. private $configuration;
  413. public function __construct($code, array $configuration = null)
  414. {
  415. $this->code = $code;
  416. $this->configuration = $configuration;
  417. }
  418. public function getCode()
  419. {
  420. return $this->code;
  421. }
  422. public function getConfiguration()
  423. {
  424. return $this->configuration;
  425. }
  426. }
  427. <?php
  428. namespace PhpCsFixer\FixerDefinition;
  429. interface CodeSampleInterface
  430. {
  431. public function getCode();
  432. public function getConfiguration();
  433. }
  434. <?php
  435. namespace PhpCsFixer\FixerDefinition;
  436. interface VersionSpecificationInterface
  437. {
  438. public function isSatisfiedBy($version);
  439. }
  440. <?php
  441. namespace PhpCsFixer\FixerDefinition;
  442. final class VersionSpecification implements VersionSpecificationInterface
  443. {
  444. private $minimum;
  445. private $maximum;
  446. public function __construct($minimum = null, $maximum = null)
  447. {
  448. if (null === $minimum && null === $maximum) {
  449. throw new \InvalidArgumentException('Minimum or maximum need to be specified.');
  450. }
  451. if (null !== $minimum && (!\is_int($minimum) || 1 > $minimum)) {
  452. throw new \InvalidArgumentException('Minimum needs to be either null or an integer greater than 0.');
  453. }
  454. if (null !== $maximum) {
  455. if (!\is_int($maximum) || 1 > $maximum) {
  456. throw new \InvalidArgumentException('Maximum needs to be either null or an integer greater than 0.');
  457. }
  458. if (null !== $minimum && $maximum < $minimum) {
  459. throw new \InvalidArgumentException('Maximum should not be lower than the minimum.');
  460. }
  461. }
  462. $this->minimum = $minimum;
  463. $this->maximum = $maximum;
  464. }
  465. public function isSatisfiedBy($version)
  466. {
  467. if (null !== $this->minimum && $version < $this->minimum) {
  468. return false;
  469. }
  470. if (null !== $this->maximum && $version > $this->maximum) {
  471. return false;
  472. }
  473. return true;
  474. }
  475. }
  476. <?php
  477. namespace PhpCsFixer\FixerDefinition;
  478. interface FileSpecificCodeSampleInterface extends CodeSampleInterface
  479. {
  480. public function getSplFileInfo();
  481. }
  482. <?php
  483. namespace PhpCsFixer\FixerDefinition;
  484. final class FileSpecificCodeSample implements FileSpecificCodeSampleInterface
  485. {
  486. private $codeSample;
  487. private $splFileInfo;
  488. public function __construct(
  489. $code,
  490. \SplFileInfo $splFileInfo,
  491. array $configuration = null
  492. ) {
  493. $this->codeSample = new CodeSample($code, $configuration);
  494. $this->splFileInfo = $splFileInfo;
  495. }
  496. public function getCode()
  497. {
  498. return $this->codeSample->getCode();
  499. }
  500. public function getConfiguration()
  501. {
  502. return $this->codeSample->getConfiguration();
  503. }
  504. public function getSplFileInfo()
  505. {
  506. return $this->splFileInfo;
  507. }
  508. }
  509. <?php
  510. namespace PhpCsFixer\Report;
  511. use Symfony\Component\Console\Formatter\OutputFormatter;
  512. final class GitlabReporter implements ReporterInterface
  513. {
  514. public function getFormat()
  515. {
  516. return 'gitlab';
  517. }
  518. public function generate(ReportSummary $reportSummary)
  519. {
  520. $report = [];
  521. foreach ($reportSummary->getChanged() as $fileName => $change) {
  522. foreach ($change['appliedFixers'] as $fixerName) {
  523. $report[] = [
  524. 'description' => $fixerName,
  525. 'fingerprint' => md5($fileName.$fixerName),
  526. 'location' => [
  527. 'path' => $fileName,
  528. 'lines' => [
  529. 'begin' => 0,
  530. ],
  531. ],
  532. ];
  533. }
  534. }
  535. $jsonString = json_encode($report);
  536. return $reportSummary->isDecoratedOutput() ? OutputFormatter::escape($jsonString) : $jsonString;
  537. }
  538. }
  539. <?php
  540. namespace PhpCsFixer\Report;
  541. use Symfony\Component\Console\Formatter\OutputFormatter;
  542. final class JsonReporter implements ReporterInterface
  543. {
  544. public function getFormat()
  545. {
  546. return 'json';
  547. }
  548. public function generate(ReportSummary $reportSummary)
  549. {
  550. $jFiles = [];
  551. foreach ($reportSummary->getChanged() as $file => $fixResult) {
  552. $jfile = ['name' => $file];
  553. if ($reportSummary->shouldAddAppliedFixers()) {
  554. $jfile['appliedFixers'] = $fixResult['appliedFixers'];
  555. }
  556. if (!empty($fixResult['diff'])) {
  557. $jfile['diff'] = $fixResult['diff'];
  558. }
  559. $jFiles[] = $jfile;
  560. }
  561. $json = [
  562. 'files' => $jFiles,
  563. ];
  564. if (null !== $reportSummary->getTime()) {
  565. $json['time'] = [
  566. 'total' => round($reportSummary->getTime() / 1000, 3),
  567. ];
  568. }
  569. if (null !== $reportSummary->getMemory()) {
  570. $json['memory'] = round($reportSummary->getMemory() / 1024 / 1024, 3);
  571. }
  572. $json = json_encode($json);
  573. return $reportSummary->isDecoratedOutput() ? OutputFormatter::escape($json) : $json;
  574. }
  575. }
  576. <?php
  577. namespace PhpCsFixer\Report;
  578. use Symfony\Component\Finder\Finder as SymfonyFinder;
  579. use Symfony\Component\Finder\SplFileInfo;
  580. final class ReporterFactory
  581. {
  582. private $reporters = [];
  583. public static function create()
  584. {
  585. return new self();
  586. }
  587. public function registerBuiltInReporters()
  588. {
  589. static $builtInReporters;
  590. if (null === $builtInReporters) {
  591. $builtInReporters = [];
  592. foreach (SymfonyFinder::create()->files()->name('*Reporter.php')->in(__DIR__) as $file) {
  593. $relativeNamespace = $file->getRelativePath();
  594. $builtInReporters[] = sprintf(
  595. '%s\\%s%s',
  596. __NAMESPACE__,
  597. $relativeNamespace ? $relativeNamespace.'\\' : '',
  598. $file->getBasename('.php')
  599. );
  600. }
  601. }
  602. foreach ($builtInReporters as $reporterClass) {
  603. $this->registerReporter(new $reporterClass());
  604. }
  605. return $this;
  606. }
  607. public function registerReporter(ReporterInterface $reporter)
  608. {
  609. $format = $reporter->getFormat();
  610. if (isset($this->reporters[$format])) {
  611. throw new \UnexpectedValueException(sprintf('Reporter for format "%s" is already registered.', $format));
  612. }
  613. $this->reporters[$format] = $reporter;
  614. return $this;
  615. }
  616. public function getFormats()
  617. {
  618. $formats = array_keys($this->reporters);
  619. sort($formats);
  620. return $formats;
  621. }
  622. public function getReporter($format)
  623. {
  624. if (!isset($this->reporters[$format])) {
  625. throw new \UnexpectedValueException(sprintf('Reporter for format "%s" is not registered.', $format));
  626. }
  627. return $this->reporters[$format];
  628. }
  629. }
  630. <?php
  631. namespace PhpCsFixer\Report;
  632. final class ReportSummary
  633. {
  634. private $addAppliedFixers;
  635. private $changed;
  636. private $isDecoratedOutput;
  637. private $isDryRun;
  638. private $memory;
  639. private $time;
  640. public function __construct(
  641. array $changed,
  642. $time,
  643. $memory,
  644. $addAppliedFixers,
  645. $isDryRun,
  646. $isDecoratedOutput
  647. ) {
  648. $this->changed = $changed;
  649. $this->time = $time;
  650. $this->memory = $memory;
  651. $this->addAppliedFixers = $addAppliedFixers;
  652. $this->isDryRun = $isDryRun;
  653. $this->isDecoratedOutput = $isDecoratedOutput;
  654. }
  655. public function isDecoratedOutput()
  656. {
  657. return $this->isDecoratedOutput;
  658. }
  659. public function isDryRun()
  660. {
  661. return $this->isDryRun;
  662. }
  663. public function getChanged()
  664. {
  665. return $this->changed;
  666. }
  667. public function getMemory()
  668. {
  669. return $this->memory;
  670. }
  671. public function getTime()
  672. {
  673. return $this->time;
  674. }
  675. public function shouldAddAppliedFixers()
  676. {
  677. return $this->addAppliedFixers;
  678. }
  679. }
  680. <?php
  681. namespace PhpCsFixer\Report;
  682. use Symfony\Component\Console\Formatter\OutputFormatter;
  683. final class CheckstyleReporter implements ReporterInterface
  684. {
  685. public function getFormat()
  686. {
  687. return 'checkstyle';
  688. }
  689. public function generate(ReportSummary $reportSummary)
  690. {
  691. if (!\extension_loaded('dom')) {
  692. throw new \RuntimeException('Cannot generate report! `ext-dom` is not available!');
  693. }
  694. $dom = new \DOMDocument('1.0', 'UTF-8');
  695. $checkstyles = $dom->appendChild($dom->createElement('checkstyle'));
  696. foreach ($reportSummary->getChanged() as $filePath => $fixResult) {
  697. $file = $checkstyles->appendChild($dom->createElement('file'));
  698. $file->setAttribute('name', $filePath);
  699. foreach ($fixResult['appliedFixers'] as $appliedFixer) {
  700. $error = $this->createError($dom, $appliedFixer);
  701. $file->appendChild($error);
  702. }
  703. }
  704. $dom->formatOutput = true;
  705. return $reportSummary->isDecoratedOutput() ? OutputFormatter::escape($dom->saveXML()) : $dom->saveXML();
  706. }
  707. private function createError(\DOMDocument $dom, $appliedFixer)
  708. {
  709. $error = $dom->createElement('error');
  710. $error->setAttribute('severity', 'warning');
  711. $error->setAttribute('source', 'PHP-CS-Fixer.'.$appliedFixer);
  712. $error->setAttribute('message', 'Found violation(s) of type: '.$appliedFixer);
  713. return $error;
  714. }
  715. }
  716. <?php
  717. namespace PhpCsFixer\Report;
  718. use Symfony\Component\Console\Formatter\OutputFormatter;
  719. final class XmlReporter implements ReporterInterface
  720. {
  721. public function getFormat()
  722. {
  723. return 'xml';
  724. }
  725. public function generate(ReportSummary $reportSummary)
  726. {
  727. if (!\extension_loaded('dom')) {
  728. throw new \RuntimeException('Cannot generate report! `ext-dom` is not available!');
  729. }
  730. $dom = new \DOMDocument('1.0', 'UTF-8');
  731. $root = $dom->createElement('report');
  732. $dom->appendChild($root);
  733. $filesXML = $dom->createElement('files');
  734. $root->appendChild($filesXML);
  735. $i = 1;
  736. foreach ($reportSummary->getChanged() as $file => $fixResult) {
  737. $fileXML = $dom->createElement('file');
  738. $fileXML->setAttribute('id', (string) $i++);
  739. $fileXML->setAttribute('name', $file);
  740. $filesXML->appendChild($fileXML);
  741. if ($reportSummary->shouldAddAppliedFixers()) {
  742. $fileXML->appendChild($this->createAppliedFixersElement($dom, $fixResult));
  743. }
  744. if (!empty($fixResult['diff'])) {
  745. $fileXML->appendChild($this->createDiffElement($dom, $fixResult));
  746. }
  747. }
  748. if (0 !== $reportSummary->getTime()) {
  749. $root->appendChild($this->createTimeElement($reportSummary->getTime(), $dom));
  750. }
  751. if (0 !== $reportSummary->getMemory()) {
  752. $root->appendChild($this->createMemoryElement($reportSummary->getMemory(), $dom));
  753. }
  754. $dom->formatOutput = true;
  755. return $reportSummary->isDecoratedOutput() ? OutputFormatter::escape($dom->saveXML()) : $dom->saveXML();
  756. }
  757. private function createAppliedFixersElement($dom, array $fixResult)
  758. {
  759. $appliedFixersXML = $dom->createElement('applied_fixers');
  760. foreach ($fixResult['appliedFixers'] as $appliedFixer) {
  761. $appliedFixerXML = $dom->createElement('applied_fixer');
  762. $appliedFixerXML->setAttribute('name', $appliedFixer);
  763. $appliedFixersXML->appendChild($appliedFixerXML);
  764. }
  765. return $appliedFixersXML;
  766. }
  767. private function createDiffElement(\DOMDocument $dom, array $fixResult)
  768. {
  769. $diffXML = $dom->createElement('diff');
  770. $diffXML->appendChild($dom->createCDATASection($fixResult['diff']));
  771. return $diffXML;
  772. }
  773. private function createTimeElement($time, \DOMDocument $dom)
  774. {
  775. $time = round($time / 1000, 3);
  776. $timeXML = $dom->createElement('time');
  777. $timeXML->setAttribute('unit', 's');
  778. $timeTotalXML = $dom->createElement('total');
  779. $timeTotalXML->setAttribute('value', (string) $time);
  780. $timeXML->appendChild($timeTotalXML);
  781. return $timeXML;
  782. }
  783. private function createMemoryElement($memory, \DOMDocument $dom)
  784. {
  785. $memory = round($memory / 1024 / 1024, 3);
  786. $memoryXML = $dom->createElement('memory');
  787. $memoryXML->setAttribute('value', (string) $memory);
  788. $memoryXML->setAttribute('unit', 'MB');
  789. return $memoryXML;
  790. }
  791. }
  792. <?php
  793. namespace PhpCsFixer\Report;
  794. use PhpCsFixer\Differ\DiffConsoleFormatter;
  795. final class TextReporter implements ReporterInterface
  796. {
  797. public function getFormat()
  798. {
  799. return 'txt';
  800. }
  801. public function generate(ReportSummary $reportSummary)
  802. {
  803. $output = '';
  804. $i = 0;
  805. foreach ($reportSummary->getChanged() as $file => $fixResult) {
  806. ++$i;
  807. $output .= sprintf('%4d) %s', $i, $file);
  808. if ($reportSummary->shouldAddAppliedFixers()) {
  809. $output .= $this->getAppliedFixers($reportSummary->isDecoratedOutput(), $fixResult);
  810. }
  811. $output .= $this->getDiff($reportSummary->isDecoratedOutput(), $fixResult);
  812. $output .= PHP_EOL;
  813. }
  814. return $output.$this->getFooter($reportSummary->getTime(), $reportSummary->getMemory(), $reportSummary->isDryRun());
  815. }
  816. private function getAppliedFixers($isDecoratedOutput, array $fixResult)
  817. {
  818. return sprintf(
  819. $isDecoratedOutput ? ' (<comment>%s</comment>)' : ' (%s)',
  820. implode(', ', $fixResult['appliedFixers'])
  821. );
  822. }
  823. private function getDiff($isDecoratedOutput, array $fixResult)
  824. {
  825. if (empty($fixResult['diff'])) {
  826. return '';
  827. }
  828. $diffFormatter = new DiffConsoleFormatter($isDecoratedOutput, sprintf(
  829. '<comment> ---------- begin diff ----------</comment>%s%%s%s<comment> ----------- end diff -----------</comment>',
  830. PHP_EOL,
  831. PHP_EOL
  832. ));
  833. return PHP_EOL.$diffFormatter->format($fixResult['diff']).PHP_EOL;
  834. }
  835. private function getFooter($time, $memory, $isDryRun)
  836. {
  837. if (0 === $time || 0 === $memory) {
  838. return '';
  839. }
  840. return PHP_EOL.sprintf(
  841. '%s all files in %.3f seconds, %.3f MB memory used'.PHP_EOL,
  842. $isDryRun ? 'Checked' : 'Fixed',
  843. $time / 1000,
  844. $memory / 1024 / 1024
  845. );
  846. }
  847. }
  848. <?php
  849. namespace PhpCsFixer\Report;
  850. use PhpCsFixer\Preg;
  851. use Symfony\Component\Console\Formatter\OutputFormatter;
  852. final class JunitReporter implements ReporterInterface
  853. {
  854. public function getFormat()
  855. {
  856. return 'junit';
  857. }
  858. public function generate(ReportSummary $reportSummary)
  859. {
  860. if (!\extension_loaded('dom')) {
  861. throw new \RuntimeException('Cannot generate report! `ext-dom` is not available!');
  862. }
  863. $dom = new \DOMDocument('1.0', 'UTF-8');
  864. $testsuites = $dom->appendChild($dom->createElement('testsuites'));
  865. $testsuite = $testsuites->appendChild($dom->createElement('testsuite'));
  866. $testsuite->setAttribute('name', 'PHP CS Fixer');
  867. if (\count($reportSummary->getChanged())) {
  868. $this->createFailedTestCases($dom, $testsuite, $reportSummary);
  869. } else {
  870. $this->createSuccessTestCase($dom, $testsuite);
  871. }
  872. if ($reportSummary->getTime()) {
  873. $testsuite->setAttribute(
  874. 'time',
  875. sprintf(
  876. '%.3f',
  877. $reportSummary->getTime() / 1000
  878. )
  879. );
  880. }
  881. $dom->formatOutput = true;
  882. return $reportSummary->isDecoratedOutput() ? OutputFormatter::escape($dom->saveXML()) : $dom->saveXML();
  883. }
  884. private function createSuccessTestCase(\DOMDocument $dom, \DOMElement $testsuite)
  885. {
  886. $testcase = $dom->createElement('testcase');
  887. $testcase->setAttribute('name', 'All OK');
  888. $testcase->setAttribute('assertions', '1');
  889. $testsuite->appendChild($testcase);
  890. $testsuite->setAttribute('tests', '1');
  891. $testsuite->setAttribute('assertions', '1');
  892. $testsuite->setAttribute('failures', '0');
  893. $testsuite->setAttribute('errors', '0');
  894. }
  895. private function createFailedTestCases(\DOMDocument $dom, \DOMElement $testsuite, ReportSummary $reportSummary)
  896. {
  897. $assertionsCount = 0;
  898. foreach ($reportSummary->getChanged() as $file => $fixResult) {
  899. $testcase = $this->createFailedTestCase(
  900. $dom,
  901. $file,
  902. $fixResult,
  903. $reportSummary->shouldAddAppliedFixers()
  904. );
  905. $testsuite->appendChild($testcase);
  906. $assertionsCount += (int) $testcase->getAttribute('assertions');
  907. }
  908. $testsuite->setAttribute('tests', (string) \count($reportSummary->getChanged()));
  909. $testsuite->setAttribute('assertions', (string) $assertionsCount);
  910. $testsuite->setAttribute('failures', (string) $assertionsCount);
  911. $testsuite->setAttribute('errors', '0');
  912. }
  913. private function createFailedTestCase(\DOMDocument $dom, $file, array $fixResult, $shouldAddAppliedFixers)
  914. {
  915. $appliedFixersCount = \count($fixResult['appliedFixers']);
  916. $testName = str_replace('.', '_DOT_', Preg::replace('@\.'.pathinfo($file, PATHINFO_EXTENSION).'$@', '', $file));
  917. $testcase = $dom->createElement('testcase');
  918. $testcase->setAttribute('name', $testName);
  919. $testcase->setAttribute('file', $file);
  920. $testcase->setAttribute('assertions', (string) $appliedFixersCount);
  921. $failure = $dom->createElement('failure');
  922. $failure->setAttribute('type', 'code_style');
  923. $testcase->appendChild($failure);
  924. if ($shouldAddAppliedFixers) {
  925. $failureContent = "applied fixers:\n---------------\n";
  926. foreach ($fixResult['appliedFixers'] as $appliedFixer) {
  927. $failureContent .= "* {$appliedFixer}\n";
  928. }
  929. } else {
  930. $failureContent = "Wrong code style\n";
  931. }
  932. if (!empty($fixResult['diff'])) {
  933. $failureContent .= "\nDiff:\n---------------\n\n".$fixResult['diff'];
  934. }
  935. $failure->appendChild($dom->createCDATASection(trim($failureContent)));
  936. return $testcase;
  937. }
  938. }
  939. <?php
  940. namespace PhpCsFixer\Report;
  941. interface ReporterInterface
  942. {
  943. public function getFormat();
  944. public function generate(ReportSummary $reportSummary);
  945. }
  946. <?php
  947. namespace PhpCsFixer\Doctrine\Annotation;
  948. use Doctrine\Common\Annotations\DocLexer;
  949. final class Token
  950. {
  951. private $type;
  952. private $content;
  953. public function __construct($type = DocLexer::T_NONE, $content = '')
  954. {
  955. $this->type = $type;
  956. $this->content = $content;
  957. }
  958. public function getType()
  959. {
  960. return $this->type;
  961. }
  962. public function setType($type)
  963. {
  964. $this->type = $type;
  965. }
  966. public function getContent()
  967. {
  968. return $this->content;
  969. }
  970. public function setContent($content)
  971. {
  972. $this->content = $content;
  973. }
  974. public function isType($types)
  975. {
  976. if (!\is_array($types)) {
  977. $types = [$types];
  978. }
  979. return \in_array($this->getType(), $types, true);
  980. }
  981. public function clear()
  982. {
  983. $this->setContent('');
  984. }
  985. }
  986. <?php
  987. namespace PhpCsFixer\Doctrine\Annotation;
  988. use Doctrine\Common\Annotations\DocLexer;
  989. use PhpCsFixer\Preg;
  990. use PhpCsFixer\Tokenizer\Token as PhpToken;
  991. final class Tokens extends \SplFixedArray
  992. {
  993. public static function createFromDocComment(PhpToken $input, array $ignoredTags = [])
  994. {
  995. if (!$input->isGivenKind(T_DOC_COMMENT)) {
  996. throw new \InvalidArgumentException('Input must be a T_DOC_COMMENT token.');
  997. }
  998. $tokens = new self();
  999. $content = $input->getContent();
  1000. $ignoredTextPosition = 0;
  1001. $currentPosition = 0;
  1002. while (false !== $nextAtPosition = strpos($content, '@', $currentPosition)) {
  1003. if (0 !== $nextAtPosition && !Preg::match('/\s/', $content[$nextAtPosition - 1])) {
  1004. $currentPosition = $nextAtPosition + 1;
  1005. continue;
  1006. }
  1007. $lexer = new DocLexer();
  1008. $lexer->setInput(substr($content, $nextAtPosition));
  1009. $scannedTokens = [];
  1010. $index = 0;
  1011. $nbScannedTokensToUse = 0;
  1012. $nbScopes = 0;
  1013. while (null !== $token = $lexer->peek()) {
  1014. if (0 === $index && DocLexer::T_AT !== $token['type']) {
  1015. break;
  1016. }
  1017. if (1 === $index) {
  1018. if (DocLexer::T_IDENTIFIER !== $token['type'] || \in_array($token['value'], $ignoredTags, true)) {
  1019. break;
  1020. }
  1021. $nbScannedTokensToUse = 2;
  1022. }
  1023. if ($index >= 2 && 0 === $nbScopes && !\in_array($token['type'], [DocLexer::T_NONE, DocLexer::T_OPEN_PARENTHESIS], true)) {
  1024. break;
  1025. }
  1026. $scannedTokens[] = $token;
  1027. if (DocLexer::T_OPEN_PARENTHESIS === $token['type']) {
  1028. ++$nbScopes;
  1029. } elseif (DocLexer::T_CLOSE_PARENTHESIS === $token['type']) {
  1030. if (0 === --$nbScopes) {
  1031. $nbScannedTokensToUse = \count($scannedTokens);
  1032. break;
  1033. }
  1034. }
  1035. ++$index;
  1036. }
  1037. if (0 !== $nbScopes) {
  1038. break;
  1039. }
  1040. if (0 !== $nbScannedTokensToUse) {
  1041. $ignoredTextLength = $nextAtPosition - $ignoredTextPosition;
  1042. if (0 !== $ignoredTextLength) {
  1043. $tokens[] = new Token(DocLexer::T_NONE, substr($content, $ignoredTextPosition, $ignoredTextLength));
  1044. }
  1045. $lastTokenEndIndex = 0;
  1046. foreach (\array_slice($scannedTokens, 0, $nbScannedTokensToUse) as $token) {
  1047. if (DocLexer::T_STRING === $token['type']) {
  1048. $token['value'] = '"'.str_replace('"', '""', $token['value']).'"';
  1049. }
  1050. $missingTextLength = $token['position'] - $lastTokenEndIndex;
  1051. if ($missingTextLength > 0) {
  1052. $tokens[] = new Token(DocLexer::T_NONE, substr(
  1053. $content,
  1054. $nextAtPosition + $lastTokenEndIndex,
  1055. $missingTextLength
  1056. ));
  1057. }
  1058. $tokens[] = new Token($token['type'], $token['value']);
  1059. $lastTokenEndIndex = $token['position'] + \strlen($token['value']);
  1060. }
  1061. $currentPosition = $ignoredTextPosition = $nextAtPosition + $token['position'] + \strlen($token['value']);
  1062. } else {
  1063. $currentPosition = $nextAtPosition + 1;
  1064. }
  1065. }
  1066. if ($ignoredTextPosition < \strlen($content)) {
  1067. $tokens[] = new Token(DocLexer::T_NONE, substr($content, $ignoredTextPosition));
  1068. }
  1069. return $tokens;
  1070. }
  1071. public function getNextMeaningfulToken($index)
  1072. {
  1073. return $this->getMeaningfulTokenSibling($index, 1);
  1074. }
  1075. public function getPreviousMeaningfulToken($index)
  1076. {
  1077. return $this->getMeaningfulTokenSibling($index, -1);
  1078. }
  1079. public function getNextTokenOfType($type, $index)
  1080. {
  1081. return $this->getTokenOfTypeSibling($index, $type, 1);
  1082. }
  1083. public function getPreviousTokenOfType($type, $index)
  1084. {
  1085. return $this->getTokenOfTypeSibling($index, $type, -1);
  1086. }
  1087. public function getAnnotationEnd($index)
  1088. {
  1089. $currentIndex = null;
  1090. if (isset($this[$index + 2])) {
  1091. if ($this[$index + 2]->isType(DocLexer::T_OPEN_PARENTHESIS)) {
  1092. $currentIndex = $index + 2;
  1093. } elseif (
  1094. isset($this[$index + 3])
  1095. && $this[$index + 2]->isType(DocLexer::T_NONE)
  1096. && $this[$index + 3]->isType(DocLexer::T_OPEN_PARENTHESIS)
  1097. && Preg::match('/^(\R\s*\*\s*)*\s*$/', $this[$index + 2]->getContent())
  1098. ) {
  1099. $currentIndex = $index + 3;
  1100. }
  1101. }
  1102. if (null !== $currentIndex) {
  1103. $level = 0;
  1104. for ($max = \count($this); $currentIndex < $max; ++$currentIndex) {
  1105. if ($this[$currentIndex]->isType(DocLexer::T_OPEN_PARENTHESIS)) {
  1106. ++$level;
  1107. } elseif ($this[$currentIndex]->isType(DocLexer::T_CLOSE_PARENTHESIS)) {
  1108. --$level;
  1109. }
  1110. if (0 === $level) {
  1111. return $currentIndex;
  1112. }
  1113. }
  1114. return null;
  1115. }
  1116. return $index + 1;
  1117. }
  1118. public function getArrayEnd($index)
  1119. {
  1120. $level = 1;
  1121. for (++$index, $max = \count($this); $index < $max; ++$index) {
  1122. if ($this[$index]->isType(DocLexer::T_OPEN_CURLY_BRACES)) {
  1123. ++$level;
  1124. } elseif ($this[$index]->isType($index, DocLexer::T_CLOSE_CURLY_BRACES)) {
  1125. --$level;
  1126. }
  1127. if (0 === $level) {
  1128. return $index;
  1129. }
  1130. }
  1131. return null;
  1132. }
  1133. public function getCode()
  1134. {
  1135. $code = '';
  1136. foreach ($this as $token) {
  1137. $code .= $token->getContent();
  1138. }
  1139. return $code;
  1140. }
  1141. public function insertAt($index, Token $token)
  1142. {
  1143. $this->setSize($this->getSize() + 1);
  1144. for ($i = $this->getSize() - 1; $i > $index; --$i) {
  1145. $this[$i] = isset($this[$i - 1]) ? $this[$i - 1] : new Token();
  1146. }
  1147. $this[$index] = $token;
  1148. }
  1149. public function offsetSet($index, $token)
  1150. {
  1151. if (!$token instanceof Token) {
  1152. $type = \gettype($token);
  1153. if ('object' === $type) {
  1154. $type = \get_class($token);
  1155. }
  1156. throw new \InvalidArgumentException(sprintf(
  1157. 'Token must be an instance of PhpCsFixer\\Doctrine\\Annotation\\Token, %s given.',
  1158. $type
  1159. ));
  1160. }
  1161. if (null === $index) {
  1162. $index = \count($this);
  1163. $this->setSize($this->getSize() + 1);
  1164. }
  1165. parent::offsetSet($index, $token);
  1166. }
  1167. public function offsetUnset($index)
  1168. {
  1169. if (!isset($this[$index])) {
  1170. throw new \OutOfBoundsException(sprintf('Index %s is invalid or does not exist.', $index));
  1171. }
  1172. $max = \count($this) - 1;
  1173. while ($index < $max) {
  1174. $this[$index] = $this[$index + 1];
  1175. ++$index;
  1176. }
  1177. parent::offsetUnset($index);
  1178. $this->setSize($max);
  1179. }
  1180. private function getMeaningfulTokenSibling($index, $direction)
  1181. {
  1182. while (true) {
  1183. $index += $direction;
  1184. if (!$this->offsetExists($index)) {
  1185. break;
  1186. }
  1187. if (!$this[$index]->isType(DocLexer::T_NONE)) {
  1188. return $index;
  1189. }
  1190. }
  1191. return null;
  1192. }
  1193. private function getTokenOfTypeSibling($index, $type, $direction)
  1194. {
  1195. while (true) {
  1196. $index += $direction;
  1197. if (!$this->offsetExists($index)) {
  1198. break;
  1199. }
  1200. if ($this[$index]->isType($type)) {
  1201. return $index;
  1202. }
  1203. }
  1204. return null;
  1205. }
  1206. }
  1207. <?php
  1208. namespace PhpCsFixer;
  1209. use PhpCsFixer\Event\Event;
  1210. final class FixerFileProcessedEvent extends Event
  1211. {
  1212. const NAME = 'fixer.file_processed';
  1213. const STATUS_UNKNOWN = 0;
  1214. const STATUS_INVALID = 1;
  1215. const STATUS_SKIPPED = 2;
  1216. const STATUS_NO_CHANGES = 3;
  1217. const STATUS_FIXED = 4;
  1218. const STATUS_EXCEPTION = 5;
  1219. const STATUS_LINT = 6;
  1220. private $status;
  1221. public function __construct($status)
  1222. {
  1223. $this->status = $status;
  1224. }
  1225. public function getStatus()
  1226. {
  1227. return $this->status;
  1228. }
  1229. }
  1230. <?php
  1231. namespace PhpCsFixer;
  1232. final class Preg
  1233. {
  1234. public static function match($pattern, $subject, &$matches = null, $flags = 0, $offset = 0)
  1235. {
  1236. $result = @preg_match(self::addUtf8Modifier($pattern), $subject, $matches, $flags, $offset);
  1237. if (false !== $result && PREG_NO_ERROR === preg_last_error()) {
  1238. return $result;
  1239. }
  1240. $result = @preg_match(self::removeUtf8Modifier($pattern), $subject, $matches, $flags, $offset);
  1241. if (false !== $result && PREG_NO_ERROR === preg_last_error()) {
  1242. return $result;
  1243. }
  1244. throw self::newPregException(preg_last_error(), __METHOD__, (array) $pattern);
  1245. }
  1246. public static function matchAll($pattern, $subject, &$matches = null, $flags = PREG_PATTERN_ORDER, $offset = 0)
  1247. {
  1248. $result = @preg_match_all(self::addUtf8Modifier($pattern), $subject, $matches, $flags, $offset);
  1249. if (false !== $result && PREG_NO_ERROR === preg_last_error()) {
  1250. return $result;
  1251. }
  1252. $result = @preg_match_all(self::removeUtf8Modifier($pattern), $subject, $matches, $flags, $offset);
  1253. if (false !== $result && PREG_NO_ERROR === preg_last_error()) {
  1254. return $result;
  1255. }
  1256. throw self::newPregException(preg_last_error(), __METHOD__, (array) $pattern);
  1257. }
  1258. public static function replace($pattern, $replacement, $subject, $limit = -1, &$count = null)
  1259. {
  1260. $result = @preg_replace(self::addUtf8Modifier($pattern), $replacement, $subject, $limit, $count);
  1261. if (null !== $result && PREG_NO_ERROR === preg_last_error()) {
  1262. return $result;
  1263. }
  1264. $result = @preg_replace(self::removeUtf8Modifier($pattern), $replacement, $subject, $limit, $count);
  1265. if (null !== $result && PREG_NO_ERROR === preg_last_error()) {
  1266. return $result;
  1267. }
  1268. throw self::newPregException(preg_last_error(), __METHOD__, (array) $pattern);
  1269. }
  1270. public static function replaceCallback($pattern, $callback, $subject, $limit = -1, &$count = null)
  1271. {
  1272. $result = @preg_replace_callback(self::addUtf8Modifier($pattern), $callback, $subject, $limit, $count);
  1273. if (null !== $result && PREG_NO_ERROR === preg_last_error()) {
  1274. return $result;
  1275. }
  1276. $result = @preg_replace_callback(self::removeUtf8Modifier($pattern), $callback, $subject, $limit, $count);
  1277. if (null !== $result && PREG_NO_ERROR === preg_last_error()) {
  1278. return $result;
  1279. }
  1280. throw self::newPregException(preg_last_error(), __METHOD__, (array) $pattern);
  1281. }
  1282. public static function split($pattern, $subject, $limit = -1, $flags = 0)
  1283. {
  1284. $result = @preg_split(self::addUtf8Modifier($pattern), $subject, $limit, $flags);
  1285. if (false !== $result && PREG_NO_ERROR === preg_last_error()) {
  1286. return $result;
  1287. }
  1288. $result = @preg_split(self::removeUtf8Modifier($pattern), $subject, $limit, $flags);
  1289. if (false !== $result && PREG_NO_ERROR === preg_last_error()) {
  1290. return $result;
  1291. }
  1292. throw self::newPregException(preg_last_error(), __METHOD__, (array) $pattern);
  1293. }
  1294. private static function addUtf8Modifier($pattern)
  1295. {
  1296. if (\is_array($pattern)) {
  1297. return array_map(__METHOD__, $pattern);
  1298. }
  1299. return $pattern.'u';
  1300. }
  1301. private static function removeUtf8Modifier($pattern)
  1302. {
  1303. if (\is_array($pattern)) {
  1304. return array_map(__METHOD__, $pattern);
  1305. }
  1306. if ('' === $pattern) {
  1307. return '';
  1308. }
  1309. $delimiter = $pattern[0];
  1310. $endDelimiterPosition = strrpos($pattern, $delimiter);
  1311. return substr($pattern, 0, $endDelimiterPosition).str_replace('u', '', substr($pattern, $endDelimiterPosition));
  1312. }
  1313. private static function newPregException($error, $method, array $patterns)
  1314. {
  1315. foreach ($patterns as $pattern) {
  1316. $last = error_get_last();
  1317. $result = @preg_match($pattern, '');
  1318. if (false !== $result) {
  1319. continue;
  1320. }
  1321. $code = preg_last_error();
  1322. $next = error_get_last();
  1323. if ($last !== $next) {
  1324. $message = sprintf(
  1325. '(code: %d) %s',
  1326. $code,
  1327. preg_replace('~preg_[a-z_]+[()]{2}: ~', '', $next['message'])
  1328. );
  1329. } else {
  1330. $message = sprintf('(code: %d)', $code);
  1331. }
  1332. return new PregException(
  1333. sprintf('%s(): Invalid PCRE pattern "%s": %s (version: %s)', $method, $pattern, $message, PCRE_VERSION),
  1334. $code
  1335. );
  1336. }
  1337. return new PregException(sprintf('Error occurred when calling %s.', $method), $error);
  1338. }
  1339. }
  1340. <?php
  1341. namespace PhpCsFixer;
  1342. final class FixerNameValidator
  1343. {
  1344. public function isValid($name, $isCustom)
  1345. {
  1346. if (!$isCustom) {
  1347. return 1 === Preg::match('/^[a-z][a-z0-9_]*$/', $name);
  1348. }
  1349. return 1 === Preg::match('/^[A-Z][a-zA-Z0-9]*\/[a-z][a-z0-9_]*$/', $name);
  1350. }
  1351. }
  1352. <?php
  1353. namespace PhpCsFixer\Console;
  1354. use PhpCsFixer\Console\Command\DescribeCommand;
  1355. use PhpCsFixer\Console\Command\FixCommand;
  1356. use PhpCsFixer\Console\Command\HelpCommand;
  1357. use PhpCsFixer\Console\Command\ReadmeCommand;
  1358. use PhpCsFixer\Console\Command\SelfUpdateCommand;
  1359. use PhpCsFixer\Console\SelfUpdate\GithubClient;
  1360. use PhpCsFixer\Console\SelfUpdate\NewVersionChecker;
  1361. use PhpCsFixer\PharChecker;
  1362. use PhpCsFixer\ToolInfo;
  1363. use Symfony\Component\Console\Application as BaseApplication;
  1364. use Symfony\Component\Console\Command\ListCommand;
  1365. use Symfony\Component\Console\Input\InputInterface;
  1366. use Symfony\Component\Console\Output\ConsoleOutputInterface;
  1367. use Symfony\Component\Console\Output\OutputInterface;
  1368. /**
  1369. @gmail
  1370. */
  1371. final class Application extends BaseApplication
  1372. {
  1373. const VERSION = '2.16.4';
  1374. const VERSION_CODENAME = 'Yellow Bird';
  1375. private $toolInfo;
  1376. public function __construct()
  1377. {
  1378. if (!getenv('PHP_CS_FIXER_FUTURE_MODE')) {
  1379. error_reporting(E_ALL & ~E_DEPRECATED & ~E_USER_DEPRECATED);
  1380. }
  1381. parent::__construct('PHP CS Fixer', self::VERSION);
  1382. $this->toolInfo = new ToolInfo();
  1383. $this->add(new DescribeCommand());
  1384. $this->add(new FixCommand($this->toolInfo));
  1385. $this->add(new ReadmeCommand());
  1386. $this->add(new SelfUpdateCommand(
  1387. new NewVersionChecker(new GithubClient()),
  1388. $this->toolInfo,
  1389. new PharChecker()
  1390. ));
  1391. }
  1392. public static function getMajorVersion()
  1393. {
  1394. return (int) explode('.', self::VERSION)[0];
  1395. }
  1396. public function doRun(InputInterface $input, OutputInterface $output)
  1397. {
  1398. $stdErr = $output instanceof ConsoleOutputInterface
  1399. ? $output->getErrorOutput()
  1400. : ($input->hasParameterOption('--format', true) && 'txt' !== $input->getParameterOption('--format', null, true) ? null : $output)
  1401. ;
  1402. if (null !== $stdErr) {
  1403. $warningsDetector = new WarningsDetector($this->toolInfo);
  1404. $warningsDetector->detectOldVendor();
  1405. $warningsDetector->detectOldMajor();
  1406. foreach ($warningsDetector->getWarnings() as $warning) {
  1407. $stdErr->writeln(sprintf($stdErr->isDecorated() ? '<bg=yellow;fg=black;>%s</>' : '%s', $warning));
  1408. }
  1409. }
  1410. return parent::doRun($input, $output);
  1411. }
  1412. public function getLongVersion()
  1413. {
  1414. $version = sprintf(
  1415. '%s <info>%s</info> by <comment>Fabien Potencier</comment> and <comment>Dariusz Ruminski</comment>',
  1416. parent::getLongVersion(),
  1417. self::VERSION_CODENAME
  1418. );
  1419. $commit = '1023c3458137ab052f6ff1e09621a721bfdeca13';
  1420. if ('@'.'git-commit@' !== $commit) {
  1421. $version .= ' ('.substr($commit, 0, 7).')';
  1422. }
  1423. return $version;
  1424. }
  1425. protected function getDefaultCommands()
  1426. {
  1427. return [new HelpCommand(), new ListCommand()];
  1428. }
  1429. }
  1430. <?php
  1431. namespace PhpCsFixer\Console;
  1432. use PhpCsFixer\ToolInfo;
  1433. use PhpCsFixer\ToolInfoInterface;
  1434. final class WarningsDetector
  1435. {
  1436. private $toolInfo;
  1437. private $warnings = [];
  1438. public function __construct(ToolInfoInterface $toolInfo)
  1439. {
  1440. $this->toolInfo = $toolInfo;
  1441. }
  1442. public function detectOldMajor()
  1443. {
  1444. }
  1445. public function detectOldVendor()
  1446. {
  1447. if ($this->toolInfo->isInstalledByComposer()) {
  1448. $details = $this->toolInfo->getComposerInstallationDetails();
  1449. if (ToolInfo::COMPOSER_LEGACY_PACKAGE_NAME === $details['name']) {
  1450. $this->warnings[] = sprintf(
  1451. 'You are running PHP CS Fixer installed with old vendor `%s`. Please update to `%s`.',
  1452. ToolInfo::COMPOSER_LEGACY_PACKAGE_NAME,
  1453. ToolInfo::COMPOSER_PACKAGE_NAME
  1454. );
  1455. }
  1456. }
  1457. }
  1458. public function getWarnings()
  1459. {
  1460. if (!\count($this->warnings)) {
  1461. return [];
  1462. }
  1463. return array_unique(array_merge(
  1464. $this->warnings,
  1465. ['If you need help while solving warnings, ask at https://gitter.im/PHP-CS-Fixer, we will help you!']
  1466. ));
  1467. }
  1468. }
  1469. <?php
  1470. namespace PhpCsFixer\Console\Output;
  1471. interface ProcessOutputInterface
  1472. {
  1473. public function printLegend();
  1474. }
  1475. <?php
  1476. namespace PhpCsFixer\Console\Output;
  1477. use PhpCsFixer\FixerFileProcessedEvent;
  1478. use Symfony\Component\Console\Output\OutputInterface;
  1479. use Symfony\Component\EventDispatcher\EventDispatcherInterface;
  1480. final class ProcessOutput implements ProcessOutputInterface
  1481. {
  1482. private static $eventStatusMap = [
  1483. FixerFileProcessedEvent::STATUS_UNKNOWN => ['symbol' => '?', 'format' => '%s', 'description' => 'unknown'],
  1484. FixerFileProcessedEvent::STATUS_INVALID => ['symbol' => 'I', 'format' => '<bg=red>%s</bg=red>', 'description' => 'invalid file syntax (file ignored)'],
  1485. FixerFileProcessedEvent::STATUS_SKIPPED => ['symbol' => 'S', 'format' => '<fg=cyan>%s</fg=cyan>', 'description' => 'skipped (cached or empty file)'],
  1486. FixerFileProcessedEvent::STATUS_NO_CHANGES => ['symbol' => '.', 'format' => '%s', 'description' => 'no changes'],
  1487. FixerFileProcessedEvent::STATUS_FIXED => ['symbol' => 'F', 'format' => '<fg=green>%s</fg=green>', 'description' => 'fixed'],
  1488. FixerFileProcessedEvent::STATUS_EXCEPTION => ['symbol' => 'E', 'format' => '<bg=red>%s</bg=red>', 'description' => 'error'],
  1489. FixerFileProcessedEvent::STATUS_LINT => ['symbol' => 'E', 'format' => '<bg=red>%s</bg=red>', 'description' => 'error'],
  1490. ];
  1491. private $eventDispatcher;
  1492. private $output;
  1493. private $files;
  1494. private $processedFiles = 0;
  1495. private $symbolsPerLine;
  1496. public function __construct(OutputInterface $output, EventDispatcherInterface $dispatcher, $width, $nbFiles)
  1497. {
  1498. $this->output = $output;
  1499. $this->eventDispatcher = $dispatcher;
  1500. $this->eventDispatcher->addListener(FixerFileProcessedEvent::NAME, [$this, 'onFixerFileProcessed']);
  1501. $this->symbolsPerLine = $width;
  1502. if (null !== $nbFiles) {
  1503. $this->files = $nbFiles;
  1504. $this->symbolsPerLine = max(1, ($width ?: 80) - \strlen((string) $this->files) * 2 - 11);
  1505. }
  1506. }
  1507. public function __destruct()
  1508. {
  1509. $this->eventDispatcher->removeListener(FixerFileProcessedEvent::NAME, [$this, 'onFixerFileProcessed']);
  1510. }
  1511. public function onFixerFileProcessed(FixerFileProcessedEvent $event)
  1512. {
  1513. if (
  1514. null === $this->files
  1515. && null !== $this->symbolsPerLine
  1516. && 0 === $this->processedFiles % $this->symbolsPerLine
  1517. && 0 !== $this->processedFiles
  1518. ) {
  1519. $this->output->writeln('');
  1520. }
  1521. $status = self::$eventStatusMap[$event->getStatus()];
  1522. $this->output->write($this->output->isDecorated() ? sprintf($status['format'], $status['symbol']) : $status['symbol']);
  1523. ++$this->processedFiles;
  1524. if (null !== $this->files) {
  1525. $symbolsOnCurrentLine = $this->processedFiles % $this->symbolsPerLine;
  1526. $isLast = $this->processedFiles === $this->files;
  1527. if (0 === $symbolsOnCurrentLine || $isLast) {
  1528. $this->output->write(sprintf(
  1529. '%s %'.\strlen((string) $this->files).'d / %d (%3d%%)',
  1530. $isLast && 0 !== $symbolsOnCurrentLine ? str_repeat(' ', $this->symbolsPerLine - $symbolsOnCurrentLine) : '',
  1531. $this->processedFiles,
  1532. $this->files,
  1533. round($this->processedFiles / $this->files * 100)
  1534. ));
  1535. if (!$isLast) {
  1536. $this->output->writeln('');
  1537. }
  1538. }
  1539. }
  1540. }
  1541. public function printLegend()
  1542. {
  1543. $symbols = [];
  1544. foreach (self::$eventStatusMap as $status) {
  1545. $symbol = $status['symbol'];
  1546. if ('' === $symbol || isset($symbols[$symbol])) {
  1547. continue;
  1548. }
  1549. $symbols[$symbol] = sprintf('%s-%s', $this->output->isDecorated() ? sprintf($status['format'], $symbol) : $symbol, $status['description']);
  1550. }
  1551. $this->output->write(sprintf("\nLegend: %s\n", implode(', ', $symbols)));
  1552. }
  1553. }
  1554. <?php
  1555. namespace PhpCsFixer\Console\Output;
  1556. final class NullOutput implements ProcessOutputInterface
  1557. {
  1558. public function printLegend()
  1559. {
  1560. }
  1561. }
  1562. <?php
  1563. namespace PhpCsFixer\Console\Output;
  1564. use PhpCsFixer\Differ\DiffConsoleFormatter;
  1565. use PhpCsFixer\Error\Error;
  1566. use PhpCsFixer\Linter\LintingException;
  1567. use Symfony\Component\Console\Formatter\OutputFormatter;
  1568. use Symfony\Component\Console\Output\OutputInterface;
  1569. final class ErrorOutput
  1570. {
  1571. private $output;
  1572. private $isDecorated;
  1573. public function __construct(OutputInterface $output)
  1574. {
  1575. $this->output = $output;
  1576. $this->isDecorated = $output->isDecorated();
  1577. }
  1578. public function listErrors($process, array $errors)
  1579. {
  1580. $this->output->writeln(['', sprintf(
  1581. 'Files that were not fixed due to errors reported during %s:',
  1582. $process
  1583. )]);
  1584. $showDetails = $this->output->getVerbosity() >= OutputInterface::VERBOSITY_VERY_VERBOSE;
  1585. $showTrace = $this->output->getVerbosity() >= OutputInterface::VERBOSITY_DEBUG;
  1586. foreach ($errors as $i => $error) {
  1587. $this->output->writeln(sprintf('%4d) %s', $i + 1, $error->getFilePath()));
  1588. $e = $error->getSource();
  1589. if (!$showDetails || null === $e) {
  1590. continue;
  1591. }
  1592. $class = sprintf('[%s]', \get_class($e));
  1593. $message = $e->getMessage();
  1594. $code = $e->getCode();
  1595. if (0 !== $code) {
  1596. $message .= " ({$code})";
  1597. }
  1598. $length = max(\strlen($class), \strlen($message));
  1599. $lines = [
  1600. '',
  1601. $class,
  1602. $message,
  1603. '',
  1604. ];
  1605. $this->output->writeln('');
  1606. foreach ($lines as $line) {
  1607. if (\strlen($line) < $length) {
  1608. $line .= str_repeat(' ', $length - \strlen($line));
  1609. }
  1610. $this->output->writeln(sprintf(' <error> %s </error>', $this->prepareOutput($line)));
  1611. }
  1612. if ($showTrace && !$e instanceof LintingException) {
  1613. $this->output->writeln('');
  1614. $stackTrace = $e->getTrace();
  1615. foreach ($stackTrace as $trace) {
  1616. if (isset($trace['class'], $trace['function']) && \Symfony\Component\Console\Command\Command::class === $trace['class'] && 'run' === $trace['function']) {
  1617. $this->output->writeln(' [ ... ]');
  1618. break;
  1619. }
  1620. $this->outputTrace($trace);
  1621. }
  1622. }
  1623. if (Error::TYPE_LINT === $error->getType() && 0 < \count($error->getAppliedFixers())) {
  1624. $this->output->writeln('');
  1625. $this->output->writeln(sprintf(' Applied fixers: <comment>%s</comment>', implode(', ', $error->getAppliedFixers())));
  1626. $diff = $error->getDiff();
  1627. if (!empty($diff)) {
  1628. $diffFormatter = new DiffConsoleFormatter(
  1629. $this->isDecorated,
  1630. sprintf(
  1631. '<comment> ---------- begin diff ----------</comment>%s%%s%s<comment> ----------- end diff -----------</comment>',
  1632. PHP_EOL,
  1633. PHP_EOL
  1634. )
  1635. );
  1636. $this->output->writeln($diffFormatter->format($diff));
  1637. }
  1638. }
  1639. }
  1640. }
  1641. private function outputTrace(array $trace)
  1642. {
  1643. if (isset($trace['class'], $trace['type'], $trace['function'])) {
  1644. $this->output->writeln(sprintf(
  1645. ' <comment>%s</comment>%s<comment>%s()</comment>',
  1646. $this->prepareOutput($trace['class']),
  1647. $this->prepareOutput($trace['type']),
  1648. $this->prepareOutput($trace['function'])
  1649. ));
  1650. } elseif (isset($trace['function'])) {
  1651. $this->output->writeln(sprintf(' <comment>%s()</comment>', $this->prepareOutput($trace['function'])));
  1652. }
  1653. if (isset($trace['file'])) {
  1654. $this->output->writeln(sprintf(' in <info>%s</info> at line <info>%d</info>', $this->prepareOutput($trace['file']), $trace['line']));
  1655. }
  1656. }
  1657. private function prepareOutput($string)
  1658. {
  1659. return $this->isDecorated
  1660. ? OutputFormatter::escape($string)
  1661. : $string
  1662. ;
  1663. }
  1664. }
  1665. <?php
  1666. namespace PhpCsFixer\Console;
  1667. use PhpCsFixer\Cache\CacheManagerInterface;
  1668. use PhpCsFixer\Cache\Directory;
  1669. use PhpCsFixer\Cache\DirectoryInterface;
  1670. use PhpCsFixer\Cache\FileCacheManager;
  1671. use PhpCsFixer\Cache\FileHandler;
  1672. use PhpCsFixer\Cache\NullCacheManager;
  1673. use PhpCsFixer\Cache\Signature;
  1674. use PhpCsFixer\ConfigInterface;
  1675. use PhpCsFixer\ConfigurationException\InvalidConfigurationException;
  1676. use PhpCsFixer\Differ\DifferInterface;
  1677. use PhpCsFixer\Differ\NullDiffer;
  1678. use PhpCsFixer\Differ\SebastianBergmannDiffer;
  1679. use PhpCsFixer\Differ\UnifiedDiffer;
  1680. use PhpCsFixer\Finder;
  1681. use PhpCsFixer\Fixer\DeprecatedFixerInterface;
  1682. use PhpCsFixer\Fixer\FixerInterface;
  1683. use PhpCsFixer\FixerFactory;
  1684. use PhpCsFixer\Linter\Linter;
  1685. use PhpCsFixer\Linter\LinterInterface;
  1686. use PhpCsFixer\Report\ReporterFactory;
  1687. use PhpCsFixer\Report\ReporterInterface;
  1688. use PhpCsFixer\RuleSet;
  1689. use PhpCsFixer\StdinFileInfo;
  1690. use PhpCsFixer\ToolInfoInterface;
  1691. use PhpCsFixer\Utils;
  1692. use PhpCsFixer\WhitespacesFixerConfig;
  1693. use PhpCsFixer\WordMatcher;
  1694. use Symfony\Component\Console\Output\OutputInterface;
  1695. use Symfony\Component\Filesystem\Filesystem;
  1696. use Symfony\Component\Finder\Finder as SymfonyFinder;
  1697. /**
  1698. @gmail
  1699. @gmail
  1700. */
  1701. final class ConfigurationResolver
  1702. {
  1703. const PATH_MODE_OVERRIDE = 'override';
  1704. const PATH_MODE_INTERSECTION = 'intersection';
  1705. private $allowRisky;
  1706. private $config;
  1707. private $configFile;
  1708. private $cwd;
  1709. private $defaultConfig;
  1710. private $reporter;
  1711. private $isStdIn;
  1712. private $isDryRun;
  1713. private $fixers;
  1714. private $configFinderIsOverridden;
  1715. private $toolInfo;
  1716. private $options = [
  1717. 'allow-risky' => null,
  1718. 'cache-file' => null,
  1719. 'config' => null,
  1720. 'diff' => null,
  1721. 'diff-format' => null,
  1722. 'dry-run' => null,
  1723. 'format' => null,
  1724. 'path' => [],
  1725. 'path-mode' => self::PATH_MODE_OVERRIDE,
  1726. 'rules' => null,
  1727. 'show-progress' => null,
  1728. 'stop-on-violation' => null,
  1729. 'using-cache' => null,
  1730. 'verbosity' => null,
  1731. ];
  1732. private $cacheFile;
  1733. private $cacheManager;
  1734. private $differ;
  1735. private $directory;
  1736. private $finder;
  1737. private $format;
  1738. private $linter;
  1739. private $path;
  1740. private $progress;
  1741. private $ruleSet;
  1742. private $usingCache;
  1743. private $fixerFactory;
  1744. public function __construct(
  1745. ConfigInterface $config,
  1746. array $options,
  1747. $cwd,
  1748. ToolInfoInterface $toolInfo
  1749. ) {
  1750. $this->cwd = $cwd;
  1751. $this->defaultConfig = $config;
  1752. $this->toolInfo = $toolInfo;
  1753. foreach ($options as $name => $value) {
  1754. $this->setOption($name, $value);
  1755. }
  1756. }
  1757. public function getCacheFile()
  1758. {
  1759. if (!$this->getUsingCache()) {
  1760. return null;
  1761. }
  1762. if (null === $this->cacheFile) {
  1763. if (null === $this->options['cache-file']) {
  1764. $this->cacheFile = $this->getConfig()->getCacheFile();
  1765. } else {
  1766. $this->cacheFile = $this->options['cache-file'];
  1767. }
  1768. }
  1769. return $this->cacheFile;
  1770. }
  1771. public function getCacheManager()
  1772. {
  1773. if (null === $this->cacheManager) {
  1774. if ($this->getUsingCache() && ($this->toolInfo->isInstalledAsPhar() || $this->toolInfo->isInstalledByComposer())) {
  1775. $this->cacheManager = new FileCacheManager(
  1776. new FileHandler($this->getCacheFile()),
  1777. new Signature(
  1778. PHP_VERSION,
  1779. $this->toolInfo->getVersion(),
  1780. $this->getConfig()->getIndent(),
  1781. $this->getConfig()->getLineEnding(),
  1782. $this->getRules()
  1783. ),
  1784. $this->isDryRun(),
  1785. $this->getDirectory()
  1786. );
  1787. } else {
  1788. $this->cacheManager = new NullCacheManager();
  1789. }
  1790. }
  1791. return $this->cacheManager;
  1792. }
  1793. public function getConfig()
  1794. {
  1795. if (null === $this->config) {
  1796. foreach ($this->computeConfigFiles() as $configFile) {
  1797. if (!file_exists($configFile)) {
  1798. continue;
  1799. }
  1800. $config = self::separatedContextLessInclude($configFile);
  1801. if (!$config instanceof ConfigInterface) {
  1802. throw new InvalidConfigurationException(sprintf('The config file: "%s" does not return a "PhpCsFixer\ConfigInterface" instance. Got: "%s".', $configFile, \is_object($config) ? \get_class($config) : \gettype($config)));
  1803. }
  1804. $this->config = $config;
  1805. $this->configFile = $configFile;
  1806. break;
  1807. }
  1808. if (null === $this->config) {
  1809. $this->config = $this->defaultConfig;
  1810. }
  1811. }
  1812. return $this->config;
  1813. }
  1814. public function getConfigFile()
  1815. {
  1816. if (null === $this->configFile) {
  1817. $this->getConfig();
  1818. }
  1819. return $this->configFile;
  1820. }
  1821. public function getDiffer()
  1822. {
  1823. if (null === $this->differ) {
  1824. $mapper = [
  1825. 'null' => static function () { return new NullDiffer(); },
  1826. 'sbd' => static function () { return new SebastianBergmannDiffer(); },
  1827. 'udiff' => static function () { return new UnifiedDiffer(); },
  1828. ];
  1829. if ($this->options['diff-format']) {
  1830. $option = $this->options['diff-format'];
  1831. if (!isset($mapper[$option])) {
  1832. throw new InvalidConfigurationException(sprintf(
  1833. '"diff-format" must be any of "%s", got "%s".',
  1834. implode('", "', array_keys($mapper)),
  1835. $option
  1836. ));
  1837. }
  1838. } else {
  1839. $default = 'sbd';
  1840. if (getenv('PHP_CS_FIXER_FUTURE_MODE')) {
  1841. $default = 'udiff';
  1842. }
  1843. $option = $this->options['diff'] ? $default : 'null';
  1844. }
  1845. $this->differ = $mapper[$option]();
  1846. }
  1847. return $this->differ;
  1848. }
  1849. public function getDirectory()
  1850. {
  1851. if (null === $this->directory) {
  1852. $path = $this->getCacheFile();
  1853. if (null === $path) {
  1854. $absolutePath = $this->cwd;
  1855. } else {
  1856. $filesystem = new Filesystem();
  1857. $absolutePath = $filesystem->isAbsolutePath($path)
  1858. ? $path
  1859. : $this->cwd.\DIRECTORY_SEPARATOR.$path;
  1860. }
  1861. $this->directory = new Directory(\dirname($absolutePath));
  1862. }
  1863. return $this->directory;
  1864. }
  1865. public function getFixers()
  1866. {
  1867. if (null === $this->fixers) {
  1868. $this->fixers = $this->createFixerFactory()
  1869. ->useRuleSet($this->getRuleSet())
  1870. ->setWhitespacesConfig(new WhitespacesFixerConfig($this->config->getIndent(), $this->config->getLineEnding()))
  1871. ->getFixers()
  1872. ;
  1873. if (false === $this->getRiskyAllowed()) {
  1874. $riskyFixers = array_map(
  1875. static function (FixerInterface $fixer) {
  1876. return $fixer->getName();
  1877. },
  1878. array_filter(
  1879. $this->fixers,
  1880. static function (FixerInterface $fixer) {
  1881. return $fixer->isRisky();
  1882. }
  1883. )
  1884. );
  1885. if (\count($riskyFixers)) {
  1886. 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?', implode(', ', $riskyFixers)));
  1887. }
  1888. }
  1889. }
  1890. return $this->fixers;
  1891. }
  1892. public function getLinter()
  1893. {
  1894. if (null === $this->linter) {
  1895. $this->linter = new Linter($this->getConfig()->getPhpExecutable());
  1896. }
  1897. return $this->linter;
  1898. }
  1899. public function getPath()
  1900. {
  1901. if (null === $this->path) {
  1902. $filesystem = new Filesystem();
  1903. $cwd = $this->cwd;
  1904. if (1 === \count($this->options['path']) && '-' === $this->options['path'][0]) {
  1905. $this->path = $this->options['path'];
  1906. } else {
  1907. $this->path = array_map(
  1908. static function ($rawPath) use ($cwd, $filesystem) {
  1909. $path = trim($rawPath);
  1910. if ('' === $path) {
  1911. throw new InvalidConfigurationException("Invalid path: \"{$rawPath}\".");
  1912. }
  1913. $absolutePath = $filesystem->isAbsolutePath($path)
  1914. ? $path
  1915. : $cwd.\DIRECTORY_SEPARATOR.$path;
  1916. if (!file_exists($absolutePath)) {
  1917. throw new InvalidConfigurationException(sprintf(
  1918. 'The path "%s" is not readable.',
  1919. $path
  1920. ));
  1921. }
  1922. return $absolutePath;
  1923. },
  1924. $this->options['path']
  1925. );
  1926. }
  1927. }
  1928. return $this->path;
  1929. }
  1930. public function getProgress()
  1931. {
  1932. if (null === $this->progress) {
  1933. if (OutputInterface::VERBOSITY_VERBOSE <= $this->options['verbosity'] && 'txt' === $this->getFormat()) {
  1934. $progressType = $this->options['show-progress'];
  1935. $progressTypes = ['none', 'run-in', 'estimating', 'estimating-max', 'dots'];
  1936. if (null === $progressType) {
  1937. $default = 'run-in';
  1938. if (getenv('PHP_CS_FIXER_FUTURE_MODE')) {
  1939. $default = 'dots';
  1940. }
  1941. $progressType = $this->getConfig()->getHideProgress() ? 'none' : $default;
  1942. } elseif (!\in_array($progressType, $progressTypes, true)) {
  1943. throw new InvalidConfigurationException(sprintf(
  1944. 'The progress type "%s" is not defined, supported are "%s".',
  1945. $progressType,
  1946. implode('", "', $progressTypes)
  1947. ));
  1948. } elseif (\in_array($progressType, ['estimating', 'estimating-max', 'run-in'], true)) {
  1949. $message = 'Passing `estimating`, `estimating-max` or `run-in` is deprecated and will not be supported in 3.0, use `none` or `dots` instead.';
  1950. if (getenv('PHP_CS_FIXER_FUTURE_MODE')) {
  1951. throw new \InvalidArgumentException("{$message} This check was performed as `PHP_CS_FIXER_FUTURE_MODE` env var is set.");
  1952. }
  1953. @trigger_error($message, E_USER_DEPRECATED);
  1954. }
  1955. $this->progress = $progressType;
  1956. } else {
  1957. $this->progress = 'none';
  1958. }
  1959. }
  1960. return $this->progress;
  1961. }
  1962. public function getReporter()
  1963. {
  1964. if (null === $this->reporter) {
  1965. $reporterFactory = ReporterFactory::create();
  1966. $reporterFactory->registerBuiltInReporters();
  1967. $format = $this->getFormat();
  1968. try {
  1969. $this->reporter = $reporterFactory->getReporter($format);
  1970. } catch (\UnexpectedValueException $e) {
  1971. $formats = $reporterFactory->getFormats();
  1972. sort($formats);
  1973. throw new InvalidConfigurationException(sprintf('The format "%s" is not defined, supported are "%s".', $format, implode('", "', $formats)));
  1974. }
  1975. }
  1976. return $this->reporter;
  1977. }
  1978. public function getRiskyAllowed()
  1979. {
  1980. if (null === $this->allowRisky) {
  1981. if (null === $this->options['allow-risky']) {
  1982. $this->allowRisky = $this->getConfig()->getRiskyAllowed();
  1983. } else {
  1984. $this->allowRisky = $this->resolveOptionBooleanValue('allow-risky');
  1985. }
  1986. }
  1987. return $this->allowRisky;
  1988. }
  1989. public function getRules()
  1990. {
  1991. return $this->getRuleSet()->getRules();
  1992. }
  1993. public function getUsingCache()
  1994. {
  1995. if (null === $this->usingCache) {
  1996. if (null === $this->options['using-cache']) {
  1997. $this->usingCache = $this->getConfig()->getUsingCache();
  1998. } else {
  1999. $this->usingCache = $this->resolveOptionBooleanValue('using-cache');
  2000. }
  2001. }
  2002. return $this->usingCache;
  2003. }
  2004. public function getFinder()
  2005. {
  2006. if (null === $this->finder) {
  2007. $this->finder = $this->resolveFinder();
  2008. }
  2009. return $this->finder;
  2010. }
  2011. public function isDryRun()
  2012. {
  2013. if (null === $this->isDryRun) {
  2014. if ($this->isStdIn()) {
  2015. $this->isDryRun = true;
  2016. } else {
  2017. $this->isDryRun = $this->options['dry-run'];
  2018. }
  2019. }
  2020. return $this->isDryRun;
  2021. }
  2022. public function shouldStopOnViolation()
  2023. {
  2024. return $this->options['stop-on-violation'];
  2025. }
  2026. public function configFinderIsOverridden()
  2027. {
  2028. if (null === $this->configFinderIsOverridden) {
  2029. $this->resolveFinder();
  2030. }
  2031. return $this->configFinderIsOverridden;
  2032. }
  2033. private function computeConfigFiles()
  2034. {
  2035. $configFile = $this->options['config'];
  2036. if (null !== $configFile) {
  2037. if (false === file_exists($configFile) || false === is_readable($configFile)) {
  2038. throw new InvalidConfigurationException(sprintf('Cannot read config file "%s".', $configFile));
  2039. }
  2040. return [$configFile];
  2041. }
  2042. $path = $this->getPath();
  2043. if ($this->isStdIn() || 0 === \count($path)) {
  2044. $configDir = $this->cwd;
  2045. } elseif (1 < \count($path)) {
  2046. throw new InvalidConfigurationException('For multiple paths config parameter is required.');
  2047. } elseif (is_file($path[0]) && $dirName = pathinfo($path[0], PATHINFO_DIRNAME)) {
  2048. $configDir = $dirName;
  2049. } else {
  2050. $configDir = $path[0];
  2051. }
  2052. $candidates = [
  2053. $configDir.\DIRECTORY_SEPARATOR.'.php_cs',
  2054. $configDir.\DIRECTORY_SEPARATOR.'.php_cs.dist',
  2055. ];
  2056. if ($configDir !== $this->cwd) {
  2057. $candidates[] = $this->cwd.\DIRECTORY_SEPARATOR.'.php_cs';
  2058. $candidates[] = $this->cwd.\DIRECTORY_SEPARATOR.'.php_cs.dist';
  2059. }
  2060. return $candidates;
  2061. }
  2062. private function createFixerFactory()
  2063. {
  2064. if (null === $this->fixerFactory) {
  2065. $fixerFactory = new FixerFactory();
  2066. $fixerFactory->registerBuiltInFixers();
  2067. $fixerFactory->registerCustomFixers($this->getConfig()->getCustomFixers());
  2068. $this->fixerFactory = $fixerFactory;
  2069. }
  2070. return $this->fixerFactory;
  2071. }
  2072. private function getFormat()
  2073. {
  2074. if (null === $this->format) {
  2075. $this->format = null === $this->options['format']
  2076. ? $this->getConfig()->getFormat()
  2077. : $this->options['format'];
  2078. }
  2079. return $this->format;
  2080. }
  2081. private function getRuleSet()
  2082. {
  2083. if (null === $this->ruleSet) {
  2084. $rules = $this->parseRules();
  2085. $this->validateRules($rules);
  2086. $this->ruleSet = new RuleSet($rules);
  2087. }
  2088. return $this->ruleSet;
  2089. }
  2090. private function isStdIn()
  2091. {
  2092. if (null === $this->isStdIn) {
  2093. $this->isStdIn = 1 === \count($this->options['path']) && '-' === $this->options['path'][0];
  2094. }
  2095. return $this->isStdIn;
  2096. }
  2097. private function iterableToTraversable($iterable)
  2098. {
  2099. return \is_array($iterable) ? new \ArrayIterator($iterable) : $iterable;
  2100. }
  2101. private function parseRules()
  2102. {
  2103. if (null === $this->options['rules']) {
  2104. return $this->getConfig()->getRules();
  2105. }
  2106. $rules = trim($this->options['rules']);
  2107. if ('' === $rules) {
  2108. throw new InvalidConfigurationException('Empty rules value is not allowed.');
  2109. }
  2110. if ('{' === $rules[0]) {
  2111. $rules = json_decode($rules, true);
  2112. if (JSON_ERROR_NONE !== json_last_error()) {
  2113. throw new InvalidConfigurationException(sprintf('Invalid JSON rules input: "%s".', json_last_error_msg()));
  2114. }
  2115. return $rules;
  2116. }
  2117. $rules = [];
  2118. foreach (explode(',', $this->options['rules']) as $rule) {
  2119. $rule = trim($rule);
  2120. if ('' === $rule) {
  2121. throw new InvalidConfigurationException('Empty rule name is not allowed.');
  2122. }
  2123. if ('-' === $rule[0]) {
  2124. $rules[substr($rule, 1)] = false;
  2125. } else {
  2126. $rules[$rule] = true;
  2127. }
  2128. }
  2129. return $rules;
  2130. }
  2131. private function validateRules(array $rules)
  2132. {
  2133. $ruleSet = [];
  2134. foreach ($rules as $key => $value) {
  2135. if (\is_int($key)) {
  2136. throw new InvalidConfigurationException(sprintf('Missing value for "%s" rule/set.', $value));
  2137. }
  2138. $ruleSet[$key] = true;
  2139. }
  2140. $ruleSet = new RuleSet($ruleSet);
  2141. $configuredFixers = array_keys($ruleSet->getRules());
  2142. $fixers = $this->createFixerFactory()->getFixers();
  2143. $availableFixers = array_map(static function (FixerInterface $fixer) {
  2144. return $fixer->getName();
  2145. }, $fixers);
  2146. $unknownFixers = array_diff(
  2147. $configuredFixers,
  2148. $availableFixers
  2149. );
  2150. if (\count($unknownFixers)) {
  2151. $matcher = new WordMatcher($availableFixers);
  2152. $message = 'The rules contain unknown fixers: ';
  2153. foreach ($unknownFixers as $unknownFixer) {
  2154. $alternative = $matcher->match($unknownFixer);
  2155. $message .= sprintf(
  2156. '"%s"%s, ',
  2157. $unknownFixer,
  2158. null === $alternative ? '' : ' (did you mean "'.$alternative.'"?)'
  2159. );
  2160. }
  2161. throw new InvalidConfigurationException(substr($message, 0, -2).'.');
  2162. }
  2163. foreach ($fixers as $fixer) {
  2164. $fixerName = $fixer->getName();
  2165. if (isset($rules[$fixerName]) && $fixer instanceof DeprecatedFixerInterface) {
  2166. $successors = $fixer->getSuccessorsNames();
  2167. $messageEnd = [] === $successors
  2168. ? sprintf(' and will be removed in version %d.0.', Application::getMajorVersion())
  2169. : sprintf('. Use %s instead.', str_replace('`', '"', Utils::naturalLanguageJoinWithBackticks($successors)));
  2170. $message = "Rule \"{$fixerName}\" is deprecated{$messageEnd}";
  2171. if (getenv('PHP_CS_FIXER_FUTURE_MODE')) {
  2172. throw new \RuntimeException("{$message} This check was performed as `PHP_CS_FIXER_FUTURE_MODE` env var is set.");
  2173. }
  2174. @trigger_error($message, E_USER_DEPRECATED);
  2175. }
  2176. }
  2177. }
  2178. private function resolveFinder()
  2179. {
  2180. $this->configFinderIsOverridden = false;
  2181. if ($this->isStdIn()) {
  2182. return new \ArrayIterator([new StdinFileInfo()]);
  2183. }
  2184. $modes = [self::PATH_MODE_OVERRIDE, self::PATH_MODE_INTERSECTION];
  2185. if (!\in_array(
  2186. $this->options['path-mode'],
  2187. $modes,
  2188. true
  2189. )) {
  2190. throw new InvalidConfigurationException(sprintf(
  2191. 'The path-mode "%s" is not defined, supported are "%s".',
  2192. $this->options['path-mode'],
  2193. implode('", "', $modes)
  2194. ));
  2195. }
  2196. $isIntersectionPathMode = self::PATH_MODE_INTERSECTION === $this->options['path-mode'];
  2197. $paths = array_filter(array_map(
  2198. static function ($path) {
  2199. return realpath($path);
  2200. },
  2201. $this->getPath()
  2202. ));
  2203. if (!\count($paths)) {
  2204. if ($isIntersectionPathMode) {
  2205. return new \ArrayIterator([]);
  2206. }
  2207. return $this->iterableToTraversable($this->getConfig()->getFinder());
  2208. }
  2209. $pathsByType = [
  2210. 'file' => [],
  2211. 'dir' => [],
  2212. ];
  2213. foreach ($paths as $path) {
  2214. if (is_file($path)) {
  2215. $pathsByType['file'][] = $path;
  2216. } else {
  2217. $pathsByType['dir'][] = $path.\DIRECTORY_SEPARATOR;
  2218. }
  2219. }
  2220. $nestedFinder = null;
  2221. $currentFinder = $this->iterableToTraversable($this->getConfig()->getFinder());
  2222. try {
  2223. $nestedFinder = $currentFinder instanceof \IteratorAggregate ? $currentFinder->getIterator() : $currentFinder;
  2224. } catch (\Exception $e) {
  2225. }
  2226. if ($isIntersectionPathMode) {
  2227. if (null === $nestedFinder) {
  2228. throw new InvalidConfigurationException(
  2229. 'Cannot create intersection with not-fully defined Finder in configuration file.'
  2230. );
  2231. }
  2232. return new \CallbackFilterIterator(
  2233. new \IteratorIterator($nestedFinder),
  2234. static function (\SplFileInfo $current) use ($pathsByType) {
  2235. $currentRealPath = $current->getRealPath();
  2236. if (\in_array($currentRealPath, $pathsByType['file'], true)) {
  2237. return true;
  2238. }
  2239. foreach ($pathsByType['dir'] as $path) {
  2240. if (0 === strpos($currentRealPath, $path)) {
  2241. return true;
  2242. }
  2243. }
  2244. return false;
  2245. }
  2246. );
  2247. }
  2248. if (null !== $this->getConfigFile() && null !== $nestedFinder) {
  2249. $this->configFinderIsOverridden = true;
  2250. }
  2251. if ($currentFinder instanceof SymfonyFinder && null === $nestedFinder) {
  2252. return $currentFinder->in($pathsByType['dir'])->append($pathsByType['file']);
  2253. }
  2254. return Finder::create()->in($pathsByType['dir'])->append($pathsByType['file']);
  2255. }
  2256. private function setOption($name, $value)
  2257. {
  2258. if (!\array_key_exists($name, $this->options)) {
  2259. throw new InvalidConfigurationException(sprintf('Unknown option name: "%s".', $name));
  2260. }
  2261. $this->options[$name] = $value;
  2262. }
  2263. private function resolveOptionBooleanValue($optionName)
  2264. {
  2265. $value = $this->options[$optionName];
  2266. if (\is_bool($value)) {
  2267. return $value;
  2268. }
  2269. if (!\is_string($value)) {
  2270. throw new InvalidConfigurationException(sprintf('Expected boolean or string value for option "%s".', $optionName));
  2271. }
  2272. if ('yes' === $value) {
  2273. return true;
  2274. }
  2275. if ('no' === $value) {
  2276. return false;
  2277. }
  2278. $message = sprintf('Expected "yes" or "no" for option "%s", other values are deprecated and support will be removed in 3.0. Got "%s", this implicitly set the option to "false".', $optionName, $value);
  2279. if (getenv('PHP_CS_FIXER_FUTURE_MODE')) {
  2280. throw new InvalidConfigurationException("{$message} This check was performed as `PHP_CS_FIXER_FUTURE_MODE` env var is set.");
  2281. }
  2282. @trigger_error($message, E_USER_DEPRECATED);
  2283. return false;
  2284. }
  2285. private static function separatedContextLessInclude($path)
  2286. {
  2287. return include $path;
  2288. }
  2289. }
  2290. <?php
  2291. namespace PhpCsFixer\Console\Command;
  2292. use PhpCsFixer\Console\SelfUpdate\NewVersionCheckerInterface;
  2293. use PhpCsFixer\PharCheckerInterface;
  2294. use PhpCsFixer\Preg;
  2295. use PhpCsFixer\ToolInfoInterface;
  2296. use Symfony\Component\Console\Command\Command;
  2297. use Symfony\Component\Console\Input\InputInterface;
  2298. use Symfony\Component\Console\Input\InputOption;
  2299. use Symfony\Component\Console\Output\OutputInterface;
  2300. /**
  2301. @gmail
  2302. @lyrixx
  2303. @gmail
  2304. */
  2305. final class SelfUpdateCommand extends Command
  2306. {
  2307. protected static $defaultName = 'self-update';
  2308. private $versionChecker;
  2309. private $toolInfo;
  2310. private $pharChecker;
  2311. public function __construct(
  2312. NewVersionCheckerInterface $versionChecker,
  2313. ToolInfoInterface $toolInfo,
  2314. PharCheckerInterface $pharChecker
  2315. ) {
  2316. parent::__construct();
  2317. $this->versionChecker = $versionChecker;
  2318. $this->toolInfo = $toolInfo;
  2319. $this->pharChecker = $pharChecker;
  2320. }
  2321. protected function configure()
  2322. {
  2323. $this
  2324. ->setAliases(['selfupdate'])
  2325. ->setDefinition(
  2326. [
  2327. new InputOption('--force', '-f', InputOption::VALUE_NONE, 'Force update to next major version if available.'),
  2328. ]
  2329. )
  2330. ->setDescription('Update php-cs-fixer.phar to the latest stable version.')
  2331. ->setHelp(
  2332. <<<'EOT'
  2333. The <info>%command.name%</info> command replace your php-cs-fixer.phar by the
  2334. latest version released on:
  2335. <comment>https://github.com/FriendsOfPHP/PHP-CS-Fixer/releases</comment>
  2336. <info>$ php php-cs-fixer.phar %command.name%</info>
  2337. EOT
  2338. )
  2339. ;
  2340. }
  2341. protected function execute(InputInterface $input, OutputInterface $output)
  2342. {
  2343. if (!$this->toolInfo->isInstalledAsPhar()) {
  2344. $output->writeln('<error>Self-update is available only for PHAR version.</error>');
  2345. return 1;
  2346. }
  2347. $currentVersion = $this->getApplication()->getVersion();
  2348. Preg::match('/^v?(?<major>\d+)\./', $currentVersion, $matches);
  2349. $currentMajor = (int) $matches['major'];
  2350. try {
  2351. $latestVersion = $this->versionChecker->getLatestVersion();
  2352. $latestVersionOfCurrentMajor = $this->versionChecker->getLatestVersionOfMajor($currentMajor);
  2353. } catch (\Exception $exception) {
  2354. $output->writeln(sprintf(
  2355. '<error>Unable to determine newest version: %s</error>',
  2356. $exception->getMessage()
  2357. ));
  2358. return 1;
  2359. }
  2360. if (1 !== $this->versionChecker->compareVersions($latestVersion, $currentVersion)) {
  2361. $output->writeln('<info>php-cs-fixer is already up to date.</info>');
  2362. return 0;
  2363. }
  2364. $remoteTag = $latestVersion;
  2365. if (
  2366. 0 !== $this->versionChecker->compareVersions($latestVersionOfCurrentMajor, $latestVersion)
  2367. && true !== $input->getOption('force')
  2368. ) {
  2369. $output->writeln(sprintf('<info>A new major version of php-cs-fixer is available</info> (<comment>%s</comment>)', $latestVersion));
  2370. $output->writeln(sprintf('<info>Before upgrading please read</info> https://github.com/FriendsOfPHP/PHP-CS-Fixer/blob/%s/UPGRADE.md', $latestVersion));
  2371. $output->writeln('<info>If you are ready to upgrade run this command with</info> <comment>-f</comment>');
  2372. $output->writeln('<info>Checking for new minor/patch version...</info>');
  2373. if (1 !== $this->versionChecker->compareVersions($latestVersionOfCurrentMajor, $currentVersion)) {
  2374. $output->writeln('<info>No minor update for php-cs-fixer.</info>');
  2375. return 0;
  2376. }
  2377. $remoteTag = $latestVersionOfCurrentMajor;
  2378. }
  2379. $localFilename = realpath($_SERVER['argv'][0]) ?: $_SERVER['argv'][0];
  2380. if (!is_writable($localFilename)) {
  2381. $output->writeln(sprintf('<error>No permission to update %s file.</error>', $localFilename));
  2382. return 1;
  2383. }
  2384. $tempFilename = \dirname($localFilename).'/'.basename($localFilename, '.phar').'-tmp.phar';
  2385. $remoteFilename = $this->toolInfo->getPharDownloadUri($remoteTag);
  2386. if (false === @copy($remoteFilename, $tempFilename)) {
  2387. $output->writeln(sprintf('<error>Unable to download new version %s from the server.</error>', $remoteTag));
  2388. return 1;
  2389. }
  2390. chmod($tempFilename, 0777 & ~umask());
  2391. $pharInvalidityReason = $this->pharChecker->checkFileValidity($tempFilename);
  2392. if (null !== $pharInvalidityReason) {
  2393. unlink($tempFilename);
  2394. $output->writeln(sprintf('<error>The download of %s is corrupt (%s).</error>', $remoteTag, $pharInvalidityReason));
  2395. $output->writeln('<error>Please re-run the self-update command to try again.</error>');
  2396. return 1;
  2397. }
  2398. rename($tempFilename, $localFilename);
  2399. $output->writeln(sprintf('<info>php-cs-fixer updated</info> (<comment>%s</comment>)', $remoteTag));
  2400. return 0;
  2401. }
  2402. }
  2403. <?php
  2404. namespace PhpCsFixer\Console\Command;
  2405. use PhpCsFixer\AbstractFixer;
  2406. use PhpCsFixer\Console\Application;
  2407. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  2408. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  2409. use PhpCsFixer\Fixer\DeprecatedFixerInterface;
  2410. use PhpCsFixer\Fixer\FixerInterface;
  2411. use PhpCsFixer\FixerConfiguration\AliasedFixerOption;
  2412. use PhpCsFixer\FixerConfiguration\AllowedValueSubset;
  2413. use PhpCsFixer\FixerConfiguration\DeprecatedFixerOption;
  2414. use PhpCsFixer\FixerConfiguration\FixerOptionInterface;
  2415. use PhpCsFixer\FixerFactory;
  2416. use PhpCsFixer\Preg;
  2417. use PhpCsFixer\RuleSet;
  2418. use PhpCsFixer\Utils;
  2419. use Symfony\Component\Console\Command\HelpCommand as BaseHelpCommand;
  2420. use Symfony\Component\Console\Formatter\OutputFormatter;
  2421. use Symfony\Component\Console\Formatter\OutputFormatterStyle;
  2422. use Symfony\Component\Console\Input\InputInterface;
  2423. use Symfony\Component\Console\Output\OutputInterface;
  2424. /**
  2425. @gmail
  2426. */
  2427. final class HelpCommand extends BaseHelpCommand
  2428. {
  2429. protected static $defaultName = 'help';
  2430. public static function getHelpCopy()
  2431. {
  2432. $template =
  2433. <<<'EOF'
  2434. The <info>%command.name%</info> command tries to fix as much coding standards
  2435. problems as possible on a given file or files in a given directory and its subdirectories:
  2436. <info>$ php %command.full_name% /path/to/dir</info>
  2437. <info>$ php %command.full_name% /path/to/file</info>
  2438. 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
  2439. command arguments, then the paths provided to a ``Finder`` in config file will be ignored. You can use <comment>--path-mode=intersection</comment>
  2440. to merge paths from the config file and from the argument:
  2441. <info>$ php %command.full_name% --path-mode=intersection /path/to/dir</info>
  2442. The <comment>--format</comment> option for the output format. Supported formats are ``txt`` (default one), ``json``, ``xml``, ``checkstyle``, ``junit`` and ``gitlab``.
  2443. NOTE: the output for the following formats are generated in accordance with XML schemas
  2444. * ``junit`` follows the `JUnit xml schema from Jenkins </doc/junit-10.xsd>`_
  2445. * ``checkstyle`` follows the common `"checkstyle" xml schema </doc/checkstyle.xsd>`_
  2446. The <comment>--quiet</comment> Do not output any message.
  2447. The <comment>--verbose</comment> option will show the applied rules. When using the ``txt`` format it will also display progress notifications.
  2448. 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
  2449. * ``--verbose=0`` or no option: normal
  2450. * ``--verbose``, ``--verbose=1``, ``-v``: verbose
  2451. * ``--verbose=2``, ``-vv``: very verbose
  2452. * ``--verbose=3``, ``-vvv``: debug
  2453. The <comment>--rules</comment> option limits the rules to apply to the
  2454. project:
  2455. <info>$ php %command.full_name% /path/to/project --rules=@PSR2</info>
  2456. By default the PSR1 and PSR2 rules are used.
  2457. The <comment>--rules</comment> option lets you choose the exact rules to
  2458. apply (the rule names must be separated by a comma):
  2459. <info>$ php %command.full_name% /path/to/dir --rules=line_ending,full_opening_tag,indentation_type</info>
  2460. 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,
  2461. using <comment>-name_of_fixer</comment>:
  2462. <info>$ php %command.full_name% /path/to/dir --rules=-full_opening_tag,-indentation_type</info>
  2463. When using combinations of exact and exclude rules, applying exact rules along with above excluded results:
  2464. <info>$ php %command.full_name% /path/to/project --rules=@Symfony,-@PSR1,-blank_line_before_statement,strict_comparison</info>
  2465. Complete configuration for rules can be supplied using a ``json`` formatted string.
  2466. <info>$ php %command.full_name% /path/to/project --rules='{"concat_space": {"spacing": "none"}}'</info>
  2467. The <comment>--dry-run</comment> flag will run the fixer without making changes to your files.
  2468. The <comment>--diff</comment> flag can be used to let the fixer output all the changes it makes.
  2469. The <comment>--diff-format</comment> option allows to specify in which format the fixer should output the changes it makes:
  2470. * <comment>udiff</comment>: unified diff format;
  2471. * <comment>sbd</comment>: Sebastianbergmann/diff format (default when using `--diff` without specifying `diff-format`).
  2472. 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.
  2473. A rule is considered risky if it could change code behaviour. By default no risky rules are run.
  2474. The <comment>--stop-on-violation</comment> flag stops the execution upon first file that needs to be fixed.
  2475. The <comment>--show-progress</comment> option allows you to choose the way process progress is rendered:
  2476. * <comment>none</comment>: disables progress output;
  2477. * <comment>run-in</comment>: [deprecated] simple single-line progress output;
  2478. * <comment>estimating</comment>: [deprecated] multiline progress output with number of files and percentage on each line. Note that with this option, the files list is evaluated before processing to get the total number of files and then kept in memory to avoid using the file iterator twice. This has an impact on memory usage so using this option is not recommended on very large projects;
  2479. * <comment>estimating-max</comment>: [deprecated] same as <comment>dots</comment>;
  2480. * <comment>dots</comment>: same as <comment>estimating</comment> but using all terminal columns instead of default 80.
  2481. If the option is not provided, it defaults to <comment>run-in</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>.
  2482. <info>$ php %command.full_name% --verbose --show-progress=estimating</info>
  2483. The command can also read from standard input, in which case it won't
  2484. automatically fix anything:
  2485. <info>$ cat foo.php | php %command.full_name% --diff -</info>
  2486. Finally, if you don't need BC kept on CLI level, you might use `PHP_CS_FIXER_FUTURE_MODE` to start using options that
  2487. would be default in next MAJOR release (unified differ, estimating, full-width progress indicator):
  2488. <info>$ PHP_CS_FIXER_FUTURE_MODE=1 php %command.full_name% -v --diff</info>
  2489. Rules
  2490. -----
  2491. Use the following command to quickly understand what a rule will do to your code:
  2492. <info>$ php php-cs-fixer.phar describe align_multiline_comment</info>
  2493. To visualize all the rules that belong to a ruleset:
  2494. <info>$ php php-cs-fixer.phar describe @PSR2</info>
  2495. Choose from the list of available rules:
  2496. %%%FIXERS_DETAILS%%%
  2497. The <comment>--dry-run</comment> option displays the files that need to be
  2498. fixed but without actually modifying them:
  2499. <info>$ php %command.full_name% /path/to/code --dry-run</info>
  2500. Config file
  2501. -----------
  2502. Instead of using command line options to customize the rule, you can save the
  2503. project configuration in a <comment>.php_cs.dist</comment> file in the root directory of your project.
  2504. The file must return an instance of `PhpCsFixer\ConfigInterface` (<url>%%%CONFIG_INTERFACE_URL%%%</url>)
  2505. which lets you configure the rules, the files and directories that
  2506. need to be analyzed. You may also create <comment>.php_cs</comment> file, which is
  2507. the local configuration that will be used instead of the project configuration. It
  2508. is a good practice to add that file into your <comment>.gitignore</comment> file.
  2509. With the <comment>--config</comment> option you can specify the path to the
  2510. <comment>.php_cs</comment> file.
  2511. The example below will add two rules to the default list of PSR2 set rules:
  2512. <?php
  2513. $finder = PhpCsFixer\Finder::create()
  2514. ->exclude('somedir')
  2515. ->notPath('src/Symfony/Component/Translation/Tests/fixtures/resources.php')
  2516. ->in(__DIR__)
  2517. ;
  2518. return PhpCsFixer\Config::create()
  2519. ->setRules([
  2520. '@PSR2' => true,
  2521. 'strict_param' => true,
  2522. 'array_syntax' => ['syntax' => 'short'],
  2523. ])
  2524. ->setFinder($finder)
  2525. ;
  2526. ?>
  2527. **NOTE**: ``exclude`` will work only for directories, so if you need to exclude file, try ``notPath``.
  2528. Both ``exclude`` and ``notPath`` methods accept only relative paths to the ones defined with the ``in`` method.
  2529. See `Symfony\Finder` (<url>https://symfony.com/doc/current/components/finder.html</url>)
  2530. online documentation for other `Finder` methods.
  2531. You may also use an exclude list for the rules instead of the above shown include approach.
  2532. The following example shows how to use all ``Symfony`` rules but the ``full_opening_tag`` rule.
  2533. <?php
  2534. $finder = PhpCsFixer\Finder::create()
  2535. ->exclude('somedir')
  2536. ->in(__DIR__)
  2537. ;
  2538. return PhpCsFixer\Config::create()
  2539. ->setRules([
  2540. '@Symfony' => true,
  2541. 'full_opening_tag' => false,
  2542. ])
  2543. ->setFinder($finder)
  2544. ;
  2545. ?>
  2546. You may want to use non-linux whitespaces in your project. Then you need to
  2547. configure them in your config file.
  2548. <?php
  2549. return PhpCsFixer\Config::create()
  2550. ->setIndent("\t")
  2551. ->setLineEnding("\r\n")
  2552. ;
  2553. ?>
  2554. By using ``--using-cache`` option with ``yes`` or ``no`` you can set if the caching
  2555. mechanism should be used.
  2556. Caching
  2557. -------
  2558. The caching mechanism is enabled by default. This will speed up further runs by
  2559. fixing only files that were modified since the last run. The tool will fix all
  2560. files if the tool version has changed or the list of rules has changed.
  2561. Cache is supported only for tool downloaded as phar file or installed via
  2562. composer.
  2563. Cache can be disabled via ``--using-cache`` option or config file:
  2564. <?php
  2565. return PhpCsFixer\Config::create()
  2566. ->setUsingCache(false)
  2567. ;
  2568. ?>
  2569. Cache file can be specified via ``--cache-file`` option or config file:
  2570. <?php
  2571. return PhpCsFixer\Config::create()
  2572. ->setCacheFile(__DIR__.'/.php_cs.cache')
  2573. ;
  2574. ?>
  2575. Using PHP CS Fixer on CI
  2576. ------------------------
  2577. Require ``friendsofphp/php-cs-fixer`` as a ``dev`` dependency:
  2578. $ ./composer.phar require --dev friendsofphp/php-cs-fixer
  2579. Then, add the following command to your CI:
  2580. %%%CI_INTEGRATION%%%
  2581. Where ``$COMMIT_RANGE`` is your range of commits, e.g. ``$TRAVIS_COMMIT_RANGE`` or ``HEAD~..HEAD``.
  2582. Exit code
  2583. ---------
  2584. Exit code is built using following bit flags:
  2585. * 0 - OK.
  2586. * 1 - General error (or PHP minimal requirement not matched).
  2587. * 4 - Some files have invalid syntax (only in dry-run mode).
  2588. * 8 - Some files need fixing (only in dry-run mode).
  2589. * 16 - Configuration error of the application.
  2590. * 32 - Configuration error of a Fixer.
  2591. * 64 - Exception raised within the application.
  2592. (Applies to exit code of the ``fix`` command only)
  2593. EOF
  2594. ;
  2595. return strtr($template, [
  2596. '%%%CONFIG_INTERFACE_URL%%%' => sprintf(
  2597. 'https://github.com/FriendsOfPHP/PHP-CS-Fixer/blob/v%s/src/ConfigInterface.php',
  2598. self::getLatestReleaseVersionFromChangeLog()
  2599. ),
  2600. '%%%CI_INTEGRATION%%%' => implode("\n", array_map(
  2601. static function ($line) { return ' $ '.$line; },
  2602. \array_slice(file(__DIR__.'/../../../ci-integration.sh', FILE_IGNORE_NEW_LINES), 3)
  2603. )),
  2604. '%%%FIXERS_DETAILS%%%' => self::getFixersHelp(),
  2605. ]);
  2606. }
  2607. public static function toString($value)
  2608. {
  2609. if (\is_array($value)) {
  2610. static $replaces = [
  2611. ['#\r|\n#', '#\s{1,}#', '#array\s*\((.*)\)#s', '#\[\s+#', '#,\s*\]#', '#\d+\s*=>\s*#'],
  2612. ['', ' ', '[$1]', '[', ']', ''],
  2613. ];
  2614. $str = var_export($value, true);
  2615. do {
  2616. $strNew = Preg::replace(
  2617. $replaces[0],
  2618. $replaces[1],
  2619. $str
  2620. );
  2621. if ($strNew === $str) {
  2622. break;
  2623. }
  2624. $str = $strNew;
  2625. } while (true);
  2626. } else {
  2627. $str = var_export($value, true);
  2628. }
  2629. return Preg::replace('/\bNULL\b/', 'null', $str);
  2630. }
  2631. public static function getDisplayableAllowedValues(FixerOptionInterface $option)
  2632. {
  2633. $allowed = $option->getAllowedValues();
  2634. if (null !== $allowed) {
  2635. $allowed = array_filter($allowed, static function ($value) {
  2636. return !($value instanceof \Closure);
  2637. });
  2638. usort($allowed, static function ($valueA, $valueB) {
  2639. if ($valueA instanceof AllowedValueSubset) {
  2640. return -1;
  2641. }
  2642. if ($valueB instanceof AllowedValueSubset) {
  2643. return 1;
  2644. }
  2645. return strcasecmp(
  2646. self::toString($valueA),
  2647. self::toString($valueB)
  2648. );
  2649. });
  2650. if (0 === \count($allowed)) {
  2651. $allowed = null;
  2652. }
  2653. }
  2654. return $allowed;
  2655. }
  2656. public static function getLatestReleaseVersionFromChangeLog()
  2657. {
  2658. static $version = null;
  2659. if (null !== $version) {
  2660. return $version;
  2661. }
  2662. $changelogFile = self::getChangeLogFile();
  2663. if (null === $changelogFile) {
  2664. $version = Application::VERSION;
  2665. return $version;
  2666. }
  2667. $changelog = @file_get_contents($changelogFile);
  2668. if (false === $changelog) {
  2669. $error = error_get_last();
  2670. throw new \RuntimeException(sprintf(
  2671. 'Failed to read content of the changelog file "%s".%s',
  2672. $changelogFile,
  2673. $error ? ' '.$error['message'] : ''
  2674. ));
  2675. }
  2676. for ($i = Application::getMajorVersion(); $i > 0; --$i) {
  2677. if (1 === Preg::match('/Changelog for v('.$i.'.\d+.\d+)/', $changelog, $matches)) {
  2678. $version = $matches[1];
  2679. break;
  2680. }
  2681. }
  2682. if (null === $version) {
  2683. throw new \RuntimeException(sprintf('Failed to parse changelog data of "%s".', $changelogFile));
  2684. }
  2685. return $version;
  2686. }
  2687. protected function initialize(InputInterface $input, OutputInterface $output)
  2688. {
  2689. $output->getFormatter()->setStyle('url', new OutputFormatterStyle('blue'));
  2690. }
  2691. private static function getChangeLogFile()
  2692. {
  2693. $changelogFile = __DIR__.'/../../../CHANGELOG.md';
  2694. return is_file($changelogFile) ? $changelogFile : null;
  2695. }
  2696. private static function getFixersHelp()
  2697. {
  2698. $help = '';
  2699. $fixerFactory = new FixerFactory();
  2700. $fixers = $fixerFactory->registerBuiltInFixers()->getFixers();
  2701. usort(
  2702. $fixers,
  2703. static function (FixerInterface $a, FixerInterface $b) {
  2704. return strcmp($a->getName(), $b->getName());
  2705. }
  2706. );
  2707. $ruleSets = [];
  2708. foreach (RuleSet::create()->getSetDefinitionNames() as $setName) {
  2709. $ruleSets[$setName] = new RuleSet([$setName => true]);
  2710. }
  2711. $getSetsWithRule = static function ($rule) use ($ruleSets) {
  2712. $sets = [];
  2713. foreach ($ruleSets as $setName => $ruleSet) {
  2714. if ($ruleSet->hasRule($rule)) {
  2715. $sets[] = $setName;
  2716. }
  2717. }
  2718. return $sets;
  2719. };
  2720. $count = \count($fixers) - 1;
  2721. foreach ($fixers as $i => $fixer) {
  2722. $sets = $getSetsWithRule($fixer->getName());
  2723. $description = $fixer->getDefinition()->getSummary();
  2724. if ($fixer instanceof DeprecatedFixerInterface) {
  2725. $successors = $fixer->getSuccessorsNames();
  2726. $message = [] === $successors
  2727. ? 'will be removed on next major version'
  2728. : sprintf('use %s instead', Utils::naturalLanguageJoinWithBackticks($successors));
  2729. $description .= sprintf(' DEPRECATED: %s.', $message);
  2730. }
  2731. $description = implode("\n | ", self::wordwrap(
  2732. Preg::replace('/(`.+?`)/', '<info>$1</info>', $description),
  2733. 72
  2734. ));
  2735. if (!empty($sets)) {
  2736. $help .= sprintf(" * <comment>%s</comment> [%s]\n | %s\n", $fixer->getName(), implode(', ', $sets), $description);
  2737. } else {
  2738. $help .= sprintf(" * <comment>%s</comment>\n | %s\n", $fixer->getName(), $description);
  2739. }
  2740. if ($fixer->isRisky()) {
  2741. $help .= sprintf(
  2742. " | *Risky rule: %s.*\n",
  2743. Preg::replace(
  2744. '/(`.+?`)/',
  2745. '<info>$1</info>',
  2746. lcfirst(Preg::replace('/\.$/', '', $fixer->getDefinition()->getRiskyDescription()))
  2747. )
  2748. );
  2749. }
  2750. if ($fixer instanceof ConfigurationDefinitionFixerInterface) {
  2751. $configurationDefinition = $fixer->getConfigurationDefinition();
  2752. $configurationDefinitionOptions = $configurationDefinition->getOptions();
  2753. if (\count($configurationDefinitionOptions)) {
  2754. $help .= " |\n | Configuration options:\n";
  2755. usort(
  2756. $configurationDefinitionOptions,
  2757. static function (FixerOptionInterface $optionA, FixerOptionInterface $optionB) {
  2758. return strcmp($optionA->getName(), $optionB->getName());
  2759. }
  2760. );
  2761. foreach ($configurationDefinitionOptions as $option) {
  2762. $line = '<info>'.OutputFormatter::escape($option->getName()).'</info>';
  2763. $allowed = self::getDisplayableAllowedValues($option);
  2764. if (null !== $allowed) {
  2765. foreach ($allowed as &$value) {
  2766. if ($value instanceof AllowedValueSubset) {
  2767. $value = 'a subset of <comment>'.self::toString($value->getAllowedValues()).'</comment>';
  2768. } else {
  2769. $value = '<comment>'.self::toString($value).'</comment>';
  2770. }
  2771. }
  2772. } else {
  2773. $allowed = array_map(
  2774. static function ($type) {
  2775. return '<comment>'.$type.'</comment>';
  2776. },
  2777. $option->getAllowedTypes()
  2778. );
  2779. }
  2780. if (null !== $allowed) {
  2781. $line .= ' ('.implode(', ', $allowed).')';
  2782. }
  2783. $line .= ': '.Preg::replace(
  2784. '/(`.+?`)/',
  2785. '<info>$1</info>',
  2786. lcfirst(Preg::replace('/\.$/', '', OutputFormatter::escape($option->getDescription())))
  2787. ).'; ';
  2788. if ($option->hasDefault()) {
  2789. $line .= 'defaults to <comment>'.self::toString($option->getDefault()).'</comment>';
  2790. } else {
  2791. $line .= 'required';
  2792. }
  2793. if ($option instanceof DeprecatedFixerOption) {
  2794. $line .= '. DEPRECATED: '.Preg::replace(
  2795. '/(`.+?`)/',
  2796. '<info>$1</info>',
  2797. lcfirst(Preg::replace('/\.$/', '', OutputFormatter::escape($option->getDeprecationMessage())))
  2798. );
  2799. }
  2800. if ($option instanceof AliasedFixerOption) {
  2801. $line .= '; DEPRECATED alias: <comment>'.$option->getAlias().'</comment>';
  2802. }
  2803. foreach (self::wordwrap($line, 72) as $index => $line) {
  2804. $help .= (0 === $index ? ' | - ' : ' | ').$line."\n";
  2805. }
  2806. }
  2807. }
  2808. } elseif ($fixer instanceof ConfigurableFixerInterface) {
  2809. $help .= " | *Configurable rule.*\n";
  2810. }
  2811. if ($count !== $i) {
  2812. $help .= "\n";
  2813. }
  2814. }
  2815. return Preg::replace('#\\\\(</.*?>)#', '<<$1', $help);
  2816. }
  2817. private static function wordwrap($string, $width)
  2818. {
  2819. $result = [];
  2820. $currentLine = 0;
  2821. $lineLength = 0;
  2822. foreach (explode(' ', $string) as $word) {
  2823. $wordLength = \strlen(Preg::replace('~</?(\w+)>~', '', $word));
  2824. if (0 !== $lineLength) {
  2825. ++$wordLength;
  2826. }
  2827. if ($lineLength + $wordLength > $width) {
  2828. ++$currentLine;
  2829. $lineLength = 0;
  2830. }
  2831. $result[$currentLine][] = $word;
  2832. $lineLength += $wordLength;
  2833. }
  2834. return array_map(static function ($line) {
  2835. return implode(' ', $line);
  2836. }, $result);
  2837. }
  2838. }
  2839. <?php
  2840. namespace PhpCsFixer\Console\Command;
  2841. use PhpCsFixer\Config;
  2842. use PhpCsFixer\ConfigInterface;
  2843. use PhpCsFixer\Console\ConfigurationResolver;
  2844. use PhpCsFixer\Console\Output\ErrorOutput;
  2845. use PhpCsFixer\Console\Output\NullOutput;
  2846. use PhpCsFixer\Console\Output\ProcessOutput;
  2847. use PhpCsFixer\Error\ErrorsManager;
  2848. use PhpCsFixer\Report\ReportSummary;
  2849. use PhpCsFixer\Runner\Runner;
  2850. use PhpCsFixer\ToolInfoInterface;
  2851. use Symfony\Component\Console\Command\Command;
  2852. use Symfony\Component\Console\Input\InputArgument;
  2853. use Symfony\Component\Console\Input\InputInterface;
  2854. use Symfony\Component\Console\Input\InputOption;
  2855. use Symfony\Component\Console\Output\ConsoleOutputInterface;
  2856. use Symfony\Component\Console\Output\OutputInterface;
  2857. use Symfony\Component\Console\Terminal;
  2858. use Symfony\Component\EventDispatcher\EventDispatcher;
  2859. use Symfony\Component\EventDispatcher\EventDispatcherInterface;
  2860. use Symfony\Component\Stopwatch\Stopwatch;
  2861. /**
  2862. @gmail
  2863. */
  2864. final class FixCommand extends Command
  2865. {
  2866. protected static $defaultName = 'fix';
  2867. private $eventDispatcher;
  2868. private $errorsManager;
  2869. private $stopwatch;
  2870. private $defaultConfig;
  2871. private $toolInfo;
  2872. public function __construct(ToolInfoInterface $toolInfo)
  2873. {
  2874. parent::__construct();
  2875. $this->defaultConfig = new Config();
  2876. $this->errorsManager = new ErrorsManager();
  2877. $this->eventDispatcher = new EventDispatcher();
  2878. $this->stopwatch = new Stopwatch();
  2879. $this->toolInfo = $toolInfo;
  2880. }
  2881. public function getHelp()
  2882. {
  2883. return HelpCommand::getHelpCopy();
  2884. }
  2885. protected function configure()
  2886. {
  2887. $this
  2888. ->setDefinition(
  2889. [
  2890. new InputArgument('path', InputArgument::IS_ARRAY, 'The path.'),
  2891. new InputOption('path-mode', '', InputOption::VALUE_REQUIRED, 'Specify path mode (can be override or intersection).', 'override'),
  2892. new InputOption('allow-risky', '', InputOption::VALUE_REQUIRED, 'Are risky fixers allowed (can be yes or no).'),
  2893. new InputOption('config', '', InputOption::VALUE_REQUIRED, 'The path to a .php_cs file.'),
  2894. new InputOption('dry-run', '', InputOption::VALUE_NONE, 'Only shows which files would have been modified.'),
  2895. new InputOption('rules', '', InputOption::VALUE_REQUIRED, 'The rules.'),
  2896. new InputOption('using-cache', '', InputOption::VALUE_REQUIRED, 'Does cache should be used (can be yes or no).'),
  2897. new InputOption('cache-file', '', InputOption::VALUE_REQUIRED, 'The path to the cache file.'),
  2898. new InputOption('diff', '', InputOption::VALUE_NONE, 'Also produce diff for each file.'),
  2899. new InputOption('diff-format', '', InputOption::VALUE_REQUIRED, 'Specify diff format.'),
  2900. new InputOption('format', '', InputOption::VALUE_REQUIRED, 'To output results in other formats.'),
  2901. new InputOption('stop-on-violation', '', InputOption::VALUE_NONE, 'Stop execution on first violation.'),
  2902. new InputOption('show-progress', '', InputOption::VALUE_REQUIRED, 'Type of progress indicator (none, run-in, estimating, estimating-max or dots).'),
  2903. ]
  2904. )
  2905. ->setDescription('Fixes a directory or a file.')
  2906. ;
  2907. }
  2908. protected function execute(InputInterface $input, OutputInterface $output)
  2909. {
  2910. $verbosity = $output->getVerbosity();
  2911. $passedConfig = $input->getOption('config');
  2912. $passedRules = $input->getOption('rules');
  2913. $resolver = new ConfigurationResolver(
  2914. $this->defaultConfig,
  2915. [
  2916. 'allow-risky' => $input->getOption('allow-risky'),
  2917. 'config' => $passedConfig,
  2918. 'dry-run' => $input->getOption('dry-run'),
  2919. 'rules' => $passedRules,
  2920. 'path' => $input->getArgument('path'),
  2921. 'path-mode' => $input->getOption('path-mode'),
  2922. 'using-cache' => $input->getOption('using-cache'),
  2923. 'cache-file' => $input->getOption('cache-file'),
  2924. 'format' => $input->getOption('format'),
  2925. 'diff' => $input->getOption('diff'),
  2926. 'diff-format' => $input->getOption('diff-format'),
  2927. 'stop-on-violation' => $input->getOption('stop-on-violation'),
  2928. 'verbosity' => $verbosity,
  2929. 'show-progress' => $input->getOption('show-progress'),
  2930. ],
  2931. getcwd(),
  2932. $this->toolInfo
  2933. );
  2934. $reporter = $resolver->getReporter();
  2935. $stdErr = $output instanceof ConsoleOutputInterface
  2936. ? $output->getErrorOutput()
  2937. : ('txt' === $reporter->getFormat() ? $output : null)
  2938. ;
  2939. if (null !== $stdErr) {
  2940. if (null !== $passedConfig && null !== $passedRules) {
  2941. if (getenv('PHP_CS_FIXER_FUTURE_MODE')) {
  2942. throw new \RuntimeException('Passing both `config` and `rules` options is not possible. This check was performed as `PHP_CS_FIXER_FUTURE_MODE` env var is set.');
  2943. }
  2944. $stdErr->writeln([
  2945. sprintf($stdErr->isDecorated() ? '<bg=yellow;fg=black;>%s</>' : '%s', 'When passing both "--config" and "--rules" the rules within the configuration file are not used.'),
  2946. sprintf($stdErr->isDecorated() ? '<bg=yellow;fg=black;>%s</>' : '%s', 'Passing both options is deprecated; version v3.0 PHP-CS-Fixer will exit with a configuration error code.'),
  2947. ]);
  2948. }
  2949. $configFile = $resolver->getConfigFile();
  2950. $stdErr->writeln(sprintf('Loaded config <comment>%s</comment>%s.', $resolver->getConfig()->getName(), null === $configFile ? '' : ' from "'.$configFile.'"'));
  2951. if ($resolver->getUsingCache()) {
  2952. $cacheFile = $resolver->getCacheFile();
  2953. if (is_file($cacheFile)) {
  2954. $stdErr->writeln(sprintf('Using cache file "%s".', $cacheFile));
  2955. }
  2956. }
  2957. }
  2958. $progressType = $resolver->getProgress();
  2959. $finder = $resolver->getFinder();
  2960. if (null !== $stdErr && $resolver->configFinderIsOverridden()) {
  2961. $stdErr->writeln(
  2962. sprintf($stdErr->isDecorated() ? '<bg=yellow;fg=black;>%s</>' : '%s', 'Paths from configuration file have been overridden by paths provided as command arguments.')
  2963. );
  2964. }
  2965. if ('none' === $progressType || null === $stdErr) {
  2966. $progressOutput = new NullOutput();
  2967. } elseif ('run-in' === $progressType) {
  2968. $progressOutput = new ProcessOutput($stdErr, $this->eventDispatcher, null, null);
  2969. } else {
  2970. $finder = new \ArrayIterator(iterator_to_array($finder));
  2971. $progressOutput = new ProcessOutput(
  2972. $stdErr,
  2973. $this->eventDispatcher,
  2974. 'estimating' !== $progressType ? (new Terminal())->getWidth() : null,
  2975. \count($finder)
  2976. );
  2977. }
  2978. $runner = new Runner(
  2979. $finder,
  2980. $resolver->getFixers(),
  2981. $resolver->getDiffer(),
  2982. 'none' !== $progressType ? $this->eventDispatcher : null,
  2983. $this->errorsManager,
  2984. $resolver->getLinter(),
  2985. $resolver->isDryRun(),
  2986. $resolver->getCacheManager(),
  2987. $resolver->getDirectory(),
  2988. $resolver->shouldStopOnViolation()
  2989. );
  2990. $this->stopwatch->start('fixFiles');
  2991. $changed = $runner->fix();
  2992. $this->stopwatch->stop('fixFiles');
  2993. $progressOutput->printLegend();
  2994. $fixEvent = $this->stopwatch->getEvent('fixFiles');
  2995. $reportSummary = new ReportSummary(
  2996. $changed,
  2997. $fixEvent->getDuration(),
  2998. $fixEvent->getMemory(),
  2999. OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity(),
  3000. $resolver->isDryRun(),
  3001. $output->isDecorated()
  3002. );
  3003. $output->isDecorated()
  3004. ? $output->write($reporter->generate($reportSummary))
  3005. : $output->write($reporter->generate($reportSummary), false, OutputInterface::OUTPUT_RAW)
  3006. ;
  3007. $invalidErrors = $this->errorsManager->getInvalidErrors();
  3008. $exceptionErrors = $this->errorsManager->getExceptionErrors();
  3009. $lintErrors = $this->errorsManager->getLintErrors();
  3010. if (null !== $stdErr) {
  3011. $errorOutput = new ErrorOutput($stdErr);
  3012. if (\count($invalidErrors) > 0) {
  3013. $errorOutput->listErrors('linting before fixing', $invalidErrors);
  3014. }
  3015. if (\count($exceptionErrors) > 0) {
  3016. $errorOutput->listErrors('fixing', $exceptionErrors);
  3017. }
  3018. if (\count($lintErrors) > 0) {
  3019. $errorOutput->listErrors('linting after fixing', $lintErrors);
  3020. }
  3021. }
  3022. $exitStatusCalculator = new FixCommandExitStatusCalculator();
  3023. return $exitStatusCalculator->calculate(
  3024. $resolver->isDryRun(),
  3025. \count($changed) > 0,
  3026. \count($invalidErrors) > 0,
  3027. \count($exceptionErrors) > 0,
  3028. \count($lintErrors) > 0
  3029. );
  3030. }
  3031. }
  3032. <?php
  3033. namespace PhpCsFixer\Console\Command;
  3034. final class FixCommandExitStatusCalculator
  3035. {
  3036. const EXIT_STATUS_FLAG_HAS_INVALID_FILES = 4;
  3037. const EXIT_STATUS_FLAG_HAS_CHANGED_FILES = 8;
  3038. const EXIT_STATUS_FLAG_HAS_INVALID_CONFIG = 16;
  3039. const EXIT_STATUS_FLAG_HAS_INVALID_FIXER_CONFIG = 32;
  3040. const EXIT_STATUS_FLAG_EXCEPTION_IN_APP = 64;
  3041. public function calculate($isDryRun, $hasChangedFiles, $hasInvalidErrors, $hasExceptionErrors, $hasLintErrorsAfterFixing)
  3042. {
  3043. $exitStatus = 0;
  3044. if ($isDryRun) {
  3045. if ($hasChangedFiles) {
  3046. $exitStatus |= self::EXIT_STATUS_FLAG_HAS_CHANGED_FILES;
  3047. }
  3048. if ($hasInvalidErrors) {
  3049. $exitStatus |= self::EXIT_STATUS_FLAG_HAS_INVALID_FILES;
  3050. }
  3051. }
  3052. if ($hasExceptionErrors || $hasLintErrorsAfterFixing) {
  3053. $exitStatus |= self::EXIT_STATUS_FLAG_EXCEPTION_IN_APP;
  3054. }
  3055. return $exitStatus;
  3056. }
  3057. }
  3058. <?php
  3059. namespace PhpCsFixer\Console\Command;
  3060. use PhpCsFixer\Preg;
  3061. use Symfony\Component\Console\Command\Command;
  3062. use Symfony\Component\Console\Input\InputInterface;
  3063. use Symfony\Component\Console\Output\OutputInterface;
  3064. /**
  3065. @gmail
  3066. */
  3067. final class ReadmeCommand extends Command
  3068. {
  3069. protected static $defaultName = 'readme';
  3070. protected function configure()
  3071. {
  3072. $this->setDescription('Generates the README content, based on the fix command help.');
  3073. }
  3074. protected function execute(InputInterface $input, OutputInterface $output)
  3075. {
  3076. $header = <<<EOF
  3077. {$this->header('PHP Coding Standards Fixer', '=')}
  3078. The PHP Coding Standards Fixer (PHP CS Fixer) tool fixes your code to follow standards;
  3079. whether you want to follow PHP coding standards as defined in the PSR-1, PSR-2, etc.,
  3080. or other community driven ones like the Symfony one.
  3081. You can **also** define your (team's) style through configuration.
  3082. It can modernize your code (like converting the ``pow`` function to the ``**`` operator on PHP 5.6)
  3083. and (micro) optimize it.
  3084. If you are already using a linter to identify coding standards problems in your
  3085. code, you know that fixing them by hand is tedious, especially on large
  3086. projects. This tool does not only detect them, but also fixes them for you.
  3087. The PHP CS Fixer is maintained on GitHub at https://github.com/FriendsOfPHP/PHP-CS-Fixer.
  3088. Bug reports and ideas about new features are welcome there.
  3089. You can talk to us at https://gitter.im/PHP-CS-Fixer/Lobby about the project,
  3090. configuration, possible improvements, ideas and questions, please visit us!
  3091. {$this->header('Requirements', '-')}
  3092. PHP needs to be a minimum version of PHP 5.6.0.
  3093. {$this->header('Installation', '-')}
  3094. {$this->header('Locally', '~')}
  3095. Download the `php-cs-fixer.phar`_ file and store it somewhere on your computer.
  3096. {$this->header('Globally (manual)', '~')}
  3097. You can run these commands to easily access latest ``php-cs-fixer`` from anywhere on
  3098. your system:
  3099. .. code-block:: bash
  3100. $ wget %download.url% -O php-cs-fixer
  3101. or with specified version:
  3102. .. code-block:: bash
  3103. $ wget %download.version_url% -O php-cs-fixer
  3104. or with curl:
  3105. .. code-block:: bash
  3106. $ curl -L %download.url% -o php-cs-fixer
  3107. then:
  3108. .. code-block:: bash
  3109. $ sudo chmod a+x php-cs-fixer
  3110. $ sudo mv php-cs-fixer /usr/local/bin/php-cs-fixer
  3111. Then, just run ``php-cs-fixer``.
  3112. {$this->header('Globally (Composer)', '~')}
  3113. To install PHP CS Fixer, `install Composer <https://getcomposer.org/download/>`_ and issue the following command:
  3114. .. code-block:: bash
  3115. $ composer global require friendsofphp/php-cs-fixer
  3116. Then make sure you have the global Composer binaries directory in your ``PATH``. This directory is platform-dependent, see `Composer documentation <https://getcomposer.org/doc/03-cli.md#composer-home>`_ for details. Example for some Unix systems:
  3117. .. code-block:: bash
  3118. $ export PATH="\$PATH:\$HOME/.composer/vendor/bin"
  3119. {$this->header('Globally (homebrew)', '~')}
  3120. .. code-block:: bash
  3121. $ brew install php-cs-fixer
  3122. {$this->header('Locally (PHIVE)', '~')}
  3123. Install `PHIVE <https://phar.io>`_ and issue the following command:
  3124. .. code-block:: bash
  3125. $ phive install php-cs-fixer # use `--global` for global install
  3126. {$this->header('Update', '-')}
  3127. {$this->header('Locally', '~')}
  3128. The ``self-update`` command tries to update ``php-cs-fixer`` itself:
  3129. .. code-block:: bash
  3130. $ php php-cs-fixer.phar self-update
  3131. {$this->header('Globally (manual)', '~')}
  3132. You can update ``php-cs-fixer`` through this command:
  3133. .. code-block:: bash
  3134. $ sudo php-cs-fixer self-update
  3135. {$this->header('Globally (Composer)', '~')}
  3136. You can update ``php-cs-fixer`` through this command:
  3137. .. code-block:: bash
  3138. $ ./composer.phar global update friendsofphp/php-cs-fixer
  3139. {$this->header('Globally (homebrew)', '~')}
  3140. You can update ``php-cs-fixer`` through this command:
  3141. .. code-block:: bash
  3142. $ brew upgrade php-cs-fixer
  3143. {$this->header('Locally (PHIVE)', '~')}
  3144. .. code-block:: bash
  3145. $ phive update php-cs-fixer
  3146. {$this->header('Usage', '-')}
  3147. EOF;
  3148. $footer = <<<EOF
  3149. {$this->header('Helpers', '-')}
  3150. Dedicated plugins exist for:
  3151. * `Atom`_
  3152. * `NetBeans`_
  3153. * `PhpStorm`_
  3154. * `Sublime Text`_
  3155. * `Vim`_
  3156. * `VS Code`_
  3157. {$this->header('Contribute', '-')}
  3158. The tool comes with quite a few built-in fixers, but everyone is more than
  3159. welcome to `contribute`_ more of them.
  3160. {$this->header('Fixers', '~')}
  3161. A *fixer* is a class that tries to fix one CS issue (a ``Fixer`` class must
  3162. implement ``FixerInterface``).
  3163. {$this->header('Configs', '~')}
  3164. A *config* knows about the CS rules and the files and directories that must be
  3165. scanned by the tool when run in the directory of your project. It is useful for
  3166. projects that follow a well-known directory structures (like for Symfony
  3167. projects for instance).
  3168. .. _php-cs-fixer.phar: %download.url%
  3169. .. _Atom: https://github.com/Glavin001/atom-beautify
  3170. .. _NetBeans: http://plugins.netbeans.org/plugin/49042/php-cs-fixer
  3171. .. _PhpStorm: https://medium.com/@valeryan/how-to-configure-phpstorm-to-use-php-cs-fixer-1844991e521f
  3172. .. _Sublime Text: https://github.com/benmatselby/sublime-phpcs
  3173. .. _Vim: https://github.com/stephpy/vim-php-cs-fixer
  3174. .. _VS Code: https://github.com/junstyle/vscode-php-cs-fixer
  3175. .. _contribute: https://github.com/FriendsOfPHP/PHP-CS-Fixer/blob/master/CONTRIBUTING.md
  3176. EOF;
  3177. $command = $this->getApplication()->get('fix');
  3178. $help = $command->getHelp();
  3179. $help = str_replace('%command.full_name%', 'php-cs-fixer.phar '.$command->getName(), $help);
  3180. $help = str_replace('%command.name%', $command->getName(), $help);
  3181. $help = Preg::replace('#</?(comment|info)>#', '``', $help);
  3182. $help = Preg::replace('#`(``.+?``)`#', '$1', $help);
  3183. $help = Preg::replace('#^(\s+)``(.+)``$#m', '$1$2', $help);
  3184. $help = Preg::replace('#^ \* ``(.+)``(.*?\n)#m', "* **$1**$2\n", $help);
  3185. $help = Preg::replace('#^ \\| #m', ' ', $help);
  3186. $help = Preg::replace('#^ \\|#m', '', $help);
  3187. $help = Preg::replace('#^(?= \\*Risky rule: )#m', "\n", $help);
  3188. $help = Preg::replace("#^( Configuration options:\n)( - )#m", "$1\n$2", $help);
  3189. $help = Preg::replace("#^\n( +\\$ )#m", "\n.. code-block:: bash\n\n$1", $help);
  3190. $help = Preg::replace("#^\n( +<\\?php)#m", "\n.. code-block:: php\n\n$1", $help);
  3191. $help = Preg::replaceCallback(
  3192. '#^\s*<\?(\w+).*?\?>#ms',
  3193. static function ($matches) {
  3194. $result = Preg::replace("#^\\.\\. code-block:: bash\n\n#m", '', $matches[0]);
  3195. if ('php' !== $matches[1]) {
  3196. $result = Preg::replace("#<\\?{$matches[1]}\\s*#", '', $result);
  3197. }
  3198. return Preg::replace("#\n\n +\\?>#", '', $result);
  3199. },
  3200. $help
  3201. );
  3202. $help = Preg::replaceCallback(
  3203. '#`(.+)`\s?\(<url>(.+)<\/url>\)#',
  3204. static function (array $matches) {
  3205. return sprintf('`%s <%s>`_', str_replace('\\', '\\\\', $matches[1]), $matches[2]);
  3206. },
  3207. $help
  3208. );
  3209. $help = Preg::replace('#^ #m', ' ', $help);
  3210. $help = Preg::replace('#\*\* +\[#', '** [', $help);
  3211. $downloadLatestUrl = sprintf('https://github.com/FriendsOfPHP/PHP-CS-Fixer/releases/download/v%s/php-cs-fixer.phar', HelpCommand::getLatestReleaseVersionFromChangeLog());
  3212. $downloadUrl = 'https://cs.symfony.com/download/php-cs-fixer-v2.phar';
  3213. $header = str_replace('%download.version_url%', $downloadLatestUrl, $header);
  3214. $header = str_replace('%download.url%', $downloadUrl, $header);
  3215. $footer = str_replace('%download.version_url%', $downloadLatestUrl, $footer);
  3216. $footer = str_replace('%download.url%', $downloadUrl, $footer);
  3217. $output->write($header."\n".$help."\n".$footer);
  3218. return 0;
  3219. }
  3220. private function header($name, $underline)
  3221. {
  3222. return $name."\n".str_repeat($underline, \strlen($name));
  3223. }
  3224. }
  3225. <?php
  3226. namespace PhpCsFixer\Console\Command;
  3227. final class DescribeNameNotFoundException extends \InvalidArgumentException
  3228. {
  3229. private $name;
  3230. private $type;
  3231. public function __construct($name, $type)
  3232. {
  3233. $this->name = $name;
  3234. $this->type = $type;
  3235. parent::__construct();
  3236. }
  3237. public function getName()
  3238. {
  3239. return $this->name;
  3240. }
  3241. public function getType()
  3242. {
  3243. return $this->type;
  3244. }
  3245. }
  3246. <?php
  3247. namespace PhpCsFixer\Console\Command;
  3248. use PhpCsFixer\Differ\DiffConsoleFormatter;
  3249. use PhpCsFixer\Differ\FullDiffer;
  3250. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  3251. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  3252. use PhpCsFixer\Fixer\DefinedFixerInterface;
  3253. use PhpCsFixer\Fixer\DeprecatedFixerInterface;
  3254. use PhpCsFixer\Fixer\FixerInterface;
  3255. use PhpCsFixer\FixerConfiguration\AliasedFixerOption;
  3256. use PhpCsFixer\FixerConfiguration\AllowedValueSubset;
  3257. use PhpCsFixer\FixerConfiguration\DeprecatedFixerOption;
  3258. use PhpCsFixer\FixerDefinition\CodeSampleInterface;
  3259. use PhpCsFixer\FixerDefinition\FileSpecificCodeSampleInterface;
  3260. use PhpCsFixer\FixerDefinition\FixerDefinition;
  3261. use PhpCsFixer\FixerDefinition\VersionSpecificCodeSampleInterface;
  3262. use PhpCsFixer\FixerFactory;
  3263. use PhpCsFixer\Preg;
  3264. use PhpCsFixer\RuleSet;
  3265. use PhpCsFixer\StdinFileInfo;
  3266. use PhpCsFixer\Tokenizer\Tokens;
  3267. use PhpCsFixer\Utils;
  3268. use PhpCsFixer\WordMatcher;
  3269. use Symfony\Component\Console\Command\Command;
  3270. use Symfony\Component\Console\Formatter\OutputFormatter;
  3271. use Symfony\Component\Console\Input\InputArgument;
  3272. use Symfony\Component\Console\Input\InputInterface;
  3273. use Symfony\Component\Console\Output\OutputInterface;
  3274. final class DescribeCommand extends Command
  3275. {
  3276. protected static $defaultName = 'describe';
  3277. private $setNames;
  3278. private $fixerFactory;
  3279. private $fixers;
  3280. public function __construct(FixerFactory $fixerFactory = null)
  3281. {
  3282. parent::__construct();
  3283. if (null === $fixerFactory) {
  3284. $fixerFactory = new FixerFactory();
  3285. $fixerFactory->registerBuiltInFixers();
  3286. }
  3287. $this->fixerFactory = $fixerFactory;
  3288. }
  3289. protected function configure()
  3290. {
  3291. $this
  3292. ->setDefinition(
  3293. [
  3294. new InputArgument('name', InputArgument::REQUIRED, 'Name of rule / set.'),
  3295. ]
  3296. )
  3297. ->setDescription('Describe rule / ruleset.')
  3298. ;
  3299. }
  3300. protected function execute(InputInterface $input, OutputInterface $output)
  3301. {
  3302. $name = $input->getArgument('name');
  3303. try {
  3304. if ('@' === $name[0]) {
  3305. $this->describeSet($output, $name);
  3306. return 0;
  3307. }
  3308. $this->describeRule($output, $name);
  3309. } catch (DescribeNameNotFoundException $e) {
  3310. $matcher = new WordMatcher(
  3311. 'set' === $e->getType() ? $this->getSetNames() : array_keys($this->getFixers())
  3312. );
  3313. $alternative = $matcher->match($name);
  3314. $this->describeList($output, $e->getType());
  3315. throw new \InvalidArgumentException(sprintf(
  3316. '%s "%s" not found.%s',
  3317. ucfirst($e->getType()),
  3318. $name,
  3319. null === $alternative ? '' : ' Did you mean "'.$alternative.'"?'
  3320. ));
  3321. }
  3322. return 0;
  3323. }
  3324. private function describeRule(OutputInterface $output, $name)
  3325. {
  3326. $fixers = $this->getFixers();
  3327. if (!isset($fixers[$name])) {
  3328. throw new DescribeNameNotFoundException($name, 'rule');
  3329. }
  3330. $fixer = $fixers[$name];
  3331. if ($fixer instanceof DefinedFixerInterface) {
  3332. $definition = $fixer->getDefinition();
  3333. } else {
  3334. $definition = new FixerDefinition('Description is not available.', []);
  3335. }
  3336. $description = $definition->getSummary();
  3337. if ($fixer instanceof DeprecatedFixerInterface) {
  3338. $successors = $fixer->getSuccessorsNames();
  3339. $message = [] === $successors
  3340. ? 'will be removed on next major version'
  3341. : sprintf('use %s instead', Utils::naturalLanguageJoinWithBackticks($successors));
  3342. $message = Preg::replace('/(`.+?`)/', '<info>$1</info>', $message);
  3343. $description .= sprintf(' <error>DEPRECATED</error>: %s.', $message);
  3344. }
  3345. $output->writeln(sprintf('<info>Description of</info> %s <info>rule</info>.', $name));
  3346. if ($output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) {
  3347. $output->writeln(sprintf('Fixer class: <comment>%s</comment>.', \get_class($fixer)));
  3348. }
  3349. $output->writeln($description);
  3350. if ($definition->getDescription()) {
  3351. $output->writeln($definition->getDescription());
  3352. }
  3353. $output->writeln('');
  3354. if ($fixer->isRisky()) {
  3355. $output->writeln('<error>Fixer applying this rule is risky.</error>');
  3356. if ($definition->getRiskyDescription()) {
  3357. $output->writeln($definition->getRiskyDescription());
  3358. }
  3359. $output->writeln('');
  3360. }
  3361. if ($fixer instanceof ConfigurationDefinitionFixerInterface) {
  3362. $configurationDefinition = $fixer->getConfigurationDefinition();
  3363. $options = $configurationDefinition->getOptions();
  3364. $output->writeln(sprintf('Fixer is configurable using following option%s:', 1 === \count($options) ? '' : 's'));
  3365. foreach ($options as $option) {
  3366. $line = '* <info>'.OutputFormatter::escape($option->getName()).'</info>';
  3367. $allowed = HelpCommand::getDisplayableAllowedValues($option);
  3368. if (null !== $allowed) {
  3369. foreach ($allowed as &$value) {
  3370. if ($value instanceof AllowedValueSubset) {
  3371. $value = 'a subset of <comment>'.HelpCommand::toString($value->getAllowedValues()).'</comment>';
  3372. } else {
  3373. $value = '<comment>'.HelpCommand::toString($value).'</comment>';
  3374. }
  3375. }
  3376. } else {
  3377. $allowed = array_map(
  3378. static function ($type) {
  3379. return '<comment>'.$type.'</comment>';
  3380. },
  3381. $option->getAllowedTypes()
  3382. );
  3383. }
  3384. if (null !== $allowed) {
  3385. $line .= ' ('.implode(', ', $allowed).')';
  3386. }
  3387. $description = Preg::replace('/(`.+?`)/', '<info>$1</info>', OutputFormatter::escape($option->getDescription()));
  3388. $line .= ': '.lcfirst(Preg::replace('/\.$/', '', $description)).'; ';
  3389. if ($option->hasDefault()) {
  3390. $line .= sprintf(
  3391. 'defaults to <comment>%s</comment>',
  3392. HelpCommand::toString($option->getDefault())
  3393. );
  3394. } else {
  3395. $line .= '<comment>required</comment>';
  3396. }
  3397. if ($option instanceof DeprecatedFixerOption) {
  3398. $line .= '. <error>DEPRECATED</error>: '.Preg::replace(
  3399. '/(`.+?`)/',
  3400. '<info>$1</info>',
  3401. OutputFormatter::escape(lcfirst($option->getDeprecationMessage()))
  3402. );
  3403. }
  3404. if ($option instanceof AliasedFixerOption) {
  3405. $line .= '; <error>DEPRECATED</error> alias: <comment>'.$option->getAlias().'</comment>';
  3406. }
  3407. $output->writeln($line);
  3408. }
  3409. $output->writeln('');
  3410. } elseif ($fixer instanceof ConfigurableFixerInterface) {
  3411. $output->writeln('<comment>Fixer is configurable.</comment>');
  3412. if ($definition->getConfigurationDescription()) {
  3413. $output->writeln($definition->getConfigurationDescription());
  3414. }
  3415. if ($definition->getDefaultConfiguration()) {
  3416. $output->writeln(sprintf('Default configuration: <comment>%s</comment>.', HelpCommand::toString($definition->getDefaultConfiguration())));
  3417. }
  3418. $output->writeln('');
  3419. }
  3420. $codeSamples = array_filter($definition->getCodeSamples(), static function (CodeSampleInterface $codeSample) {
  3421. if ($codeSample instanceof VersionSpecificCodeSampleInterface) {
  3422. return $codeSample->isSuitableFor(\PHP_VERSION_ID);
  3423. }
  3424. return true;
  3425. });
  3426. if (!\count($codeSamples)) {
  3427. $output->writeln([
  3428. 'Fixing examples can not be demonstrated on the current PHP version.',
  3429. '',
  3430. ]);
  3431. } else {
  3432. $output->writeln('Fixing examples:');
  3433. $differ = new FullDiffer();
  3434. $diffFormatter = new DiffConsoleFormatter(
  3435. $output->isDecorated(),
  3436. sprintf(
  3437. '<comment> ---------- begin diff ----------</comment>%s%%s%s<comment> ----------- end diff -----------</comment>',
  3438. PHP_EOL,
  3439. PHP_EOL
  3440. )
  3441. );
  3442. foreach ($codeSamples as $index => $codeSample) {
  3443. $old = $codeSample->getCode();
  3444. $tokens = Tokens::fromCode($old);
  3445. $configuration = $codeSample->getConfiguration();
  3446. if ($fixer instanceof ConfigurableFixerInterface) {
  3447. $fixer->configure(null === $configuration ? [] : $configuration);
  3448. }
  3449. $file = $codeSample instanceof FileSpecificCodeSampleInterface
  3450. ? $codeSample->getSplFileInfo()
  3451. : new StdinFileInfo();
  3452. $fixer->fix($file, $tokens);
  3453. $diff = $differ->diff($old, $tokens->generateCode());
  3454. if ($fixer instanceof ConfigurableFixerInterface) {
  3455. if (null === $configuration) {
  3456. $output->writeln(sprintf(' * Example #%d. Fixing with the <comment>default</comment> configuration.', $index + 1));
  3457. } else {
  3458. $output->writeln(sprintf(' * Example #%d. Fixing with configuration: <comment>%s</comment>.', $index + 1, HelpCommand::toString($codeSample->getConfiguration())));
  3459. }
  3460. } else {
  3461. $output->writeln(sprintf(' * Example #%d.', $index + 1));
  3462. }
  3463. $output->writeln($diffFormatter->format($diff, ' %s'));
  3464. $output->writeln('');
  3465. }
  3466. }
  3467. }
  3468. private function describeSet(OutputInterface $output, $name)
  3469. {
  3470. if (!\in_array($name, $this->getSetNames(), true)) {
  3471. throw new DescribeNameNotFoundException($name, 'set');
  3472. }
  3473. $ruleSet = new RuleSet([$name => true]);
  3474. $rules = $ruleSet->getRules();
  3475. ksort($rules);
  3476. $fixers = $this->getFixers();
  3477. $output->writeln(sprintf('<info>Description of</info> %s <info>set.</info>', $name));
  3478. $output->writeln('');
  3479. $help = '';
  3480. foreach ($rules as $rule => $config) {
  3481. $fixer = $fixers[$rule];
  3482. if (!$fixer instanceof DefinedFixerInterface) {
  3483. throw new \RuntimeException(sprintf(
  3484. 'Cannot describe rule %s, the fixer does not implement %s',
  3485. $rule,
  3486. DefinedFixerInterface::class
  3487. ));
  3488. }
  3489. $definition = $fixer->getDefinition();
  3490. $help .= sprintf(
  3491. " * <info>%s</info>%s\n | %s\n%s\n",
  3492. $rule,
  3493. $fixer->isRisky() ? ' <error>risky</error>' : '',
  3494. $definition->getSummary(),
  3495. true !== $config ? sprintf(" <comment>| Configuration: %s</comment>\n", HelpCommand::toString($config)) : ''
  3496. );
  3497. }
  3498. $output->write($help);
  3499. }
  3500. private function getFixers()
  3501. {
  3502. if (null !== $this->fixers) {
  3503. return $this->fixers;
  3504. }
  3505. $fixers = [];
  3506. foreach ($this->fixerFactory->getFixers() as $fixer) {
  3507. $fixers[$fixer->getName()] = $fixer;
  3508. }
  3509. $this->fixers = $fixers;
  3510. ksort($this->fixers);
  3511. return $this->fixers;
  3512. }
  3513. private function getSetNames()
  3514. {
  3515. if (null !== $this->setNames) {
  3516. return $this->setNames;
  3517. }
  3518. $set = new RuleSet();
  3519. $this->setNames = $set->getSetDefinitionNames();
  3520. sort($this->setNames);
  3521. return $this->setNames;
  3522. }
  3523. private function describeList(OutputInterface $output, $type)
  3524. {
  3525. if ($output->getVerbosity() >= OutputInterface::VERBOSITY_VERY_VERBOSE) {
  3526. $describe = [
  3527. 'set' => $this->getSetNames(),
  3528. 'rules' => $this->getFixers(),
  3529. ];
  3530. } elseif ($output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) {
  3531. $describe = 'set' === $type ? ['set' => $this->getSetNames()] : ['rules' => $this->getFixers()];
  3532. } else {
  3533. return;
  3534. }
  3535. foreach ($describe as $list => $items) {
  3536. $output->writeln(sprintf('<comment>Defined %s:</comment>', $list));
  3537. foreach ($items as $name => $item) {
  3538. $output->writeln(sprintf('* <info>%s</info>', \is_string($name) ? $name : $item));
  3539. }
  3540. }
  3541. }
  3542. }
  3543. <?php
  3544. namespace PhpCsFixer\Console\SelfUpdate;
  3545. interface NewVersionCheckerInterface
  3546. {
  3547. public function getLatestVersion();
  3548. public function getLatestVersionOfMajor($majorVersion);
  3549. public function compareVersions($versionA, $versionB);
  3550. }
  3551. <?php
  3552. namespace PhpCsFixer\Console\SelfUpdate;
  3553. interface GithubClientInterface
  3554. {
  3555. public function getTags();
  3556. }
  3557. <?php
  3558. namespace PhpCsFixer\Console\SelfUpdate;
  3559. use Composer\Semver\Comparator;
  3560. use Composer\Semver\Semver;
  3561. use Composer\Semver\VersionParser;
  3562. final class NewVersionChecker implements NewVersionCheckerInterface
  3563. {
  3564. private $githubClient;
  3565. private $versionParser;
  3566. private $availableVersions;
  3567. public function __construct(GithubClientInterface $githubClient)
  3568. {
  3569. $this->githubClient = $githubClient;
  3570. $this->versionParser = new VersionParser();
  3571. }
  3572. public function getLatestVersion()
  3573. {
  3574. $this->retrieveAvailableVersions();
  3575. return $this->availableVersions[0];
  3576. }
  3577. public function getLatestVersionOfMajor($majorVersion)
  3578. {
  3579. $this->retrieveAvailableVersions();
  3580. $semverConstraint = '^'.$majorVersion;
  3581. foreach ($this->availableVersions as $availableVersion) {
  3582. if (Semver::satisfies($availableVersion, $semverConstraint)) {
  3583. return $availableVersion;
  3584. }
  3585. }
  3586. return null;
  3587. }
  3588. public function compareVersions($versionA, $versionB)
  3589. {
  3590. $versionA = $this->versionParser->normalize($versionA);
  3591. $versionB = $this->versionParser->normalize($versionB);
  3592. if (Comparator::lessThan($versionA, $versionB)) {
  3593. return -1;
  3594. }
  3595. if (Comparator::greaterThan($versionA, $versionB)) {
  3596. return 1;
  3597. }
  3598. return 0;
  3599. }
  3600. private function retrieveAvailableVersions()
  3601. {
  3602. if (null !== $this->availableVersions) {
  3603. return;
  3604. }
  3605. foreach ($this->githubClient->getTags() as $tag) {
  3606. $version = $tag['name'];
  3607. try {
  3608. $this->versionParser->normalize($version);
  3609. if ('stable' === VersionParser::parseStability($version)) {
  3610. $this->availableVersions[] = $version;
  3611. }
  3612. } catch (\UnexpectedValueException $exception) {
  3613. }
  3614. }
  3615. $this->availableVersions = Semver::rsort($this->availableVersions);
  3616. }
  3617. }
  3618. <?php
  3619. namespace PhpCsFixer\Console\SelfUpdate;
  3620. final class GithubClient implements GithubClientInterface
  3621. {
  3622. public function getTags()
  3623. {
  3624. $url = 'https://api.github.com/repos/FriendsOfPHP/PHP-CS-Fixer/tags';
  3625. $result = @file_get_contents(
  3626. $url,
  3627. false,
  3628. stream_context_create([
  3629. 'http' => [
  3630. 'header' => 'User-Agent: FriendsOfPHP/PHP-CS-Fixer',
  3631. ],
  3632. ])
  3633. );
  3634. if (false === $result) {
  3635. throw new \RuntimeException(sprintf('Failed to load tags at "%s".', $url));
  3636. }
  3637. $result = json_decode($result, true);
  3638. if (JSON_ERROR_NONE !== json_last_error()) {
  3639. throw new \RuntimeException(sprintf(
  3640. 'Failed to read response from "%s" as JSON: %s.',
  3641. $url,
  3642. json_last_error_msg()
  3643. ));
  3644. }
  3645. return $result;
  3646. }
  3647. }
  3648. <?php
  3649. namespace PhpCsFixer;
  3650. use PhpCsFixer\Fixer\FixerInterface;
  3651. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  3652. use PhpCsFixer\Tokenizer\Tokens;
  3653. abstract class AbstractProxyFixer extends AbstractFixer
  3654. {
  3655. protected $proxyFixers;
  3656. public function __construct()
  3657. {
  3658. foreach (Utils::sortFixers($this->createProxyFixers()) as $proxyFixer) {
  3659. $this->proxyFixers[$proxyFixer->getName()] = $proxyFixer;
  3660. }
  3661. parent::__construct();
  3662. }
  3663. public function isCandidate(Tokens $tokens)
  3664. {
  3665. foreach ($this->proxyFixers as $fixer) {
  3666. if ($fixer->isCandidate($tokens)) {
  3667. return true;
  3668. }
  3669. }
  3670. return false;
  3671. }
  3672. public function isRisky()
  3673. {
  3674. foreach ($this->proxyFixers as $fixer) {
  3675. if ($fixer->isRisky()) {
  3676. return true;
  3677. }
  3678. }
  3679. return false;
  3680. }
  3681. public function getPriority()
  3682. {
  3683. if (\count($this->proxyFixers) > 1) {
  3684. throw new \LogicException('You need to override this method to provide the priority of combined fixers.');
  3685. }
  3686. return reset($this->proxyFixers)->getPriority();
  3687. }
  3688. public function supports(\SplFileInfo $file)
  3689. {
  3690. foreach ($this->proxyFixers as $fixer) {
  3691. if ($fixer->supports($file)) {
  3692. return true;
  3693. }
  3694. }
  3695. return false;
  3696. }
  3697. public function setWhitespacesConfig(WhitespacesFixerConfig $config)
  3698. {
  3699. parent::setWhitespacesConfig($config);
  3700. foreach ($this->proxyFixers as $fixer) {
  3701. if ($fixer instanceof WhitespacesAwareFixerInterface) {
  3702. $fixer->setWhitespacesConfig($config);
  3703. }
  3704. }
  3705. }
  3706. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  3707. {
  3708. foreach ($this->proxyFixers as $fixer) {
  3709. $fixer->fix($file, $tokens);
  3710. }
  3711. }
  3712. abstract protected function createProxyFixers();
  3713. }
  3714. <?php
  3715. namespace PhpCsFixer;
  3716. use PhpCsFixer\Fixer\FunctionNotation\NativeFunctionInvocationFixer;
  3717. use PhpCsFixer\Fixer\PhpUnit\PhpUnitTargetVersion;
  3718. final class RuleSet implements RuleSetInterface
  3719. {
  3720. private $setDefinitions = [
  3721. '@PSR1' => [
  3722. 'encoding' => true,
  3723. 'full_opening_tag' => true,
  3724. ],
  3725. '@PSR2' => [
  3726. '@PSR1' => true,
  3727. 'blank_line_after_namespace' => true,
  3728. 'braces' => true,
  3729. 'class_definition' => true,
  3730. 'constant_case' => true,
  3731. 'elseif' => true,
  3732. 'function_declaration' => true,
  3733. 'indentation_type' => true,
  3734. 'line_ending' => true,
  3735. 'lowercase_keywords' => true,
  3736. 'method_argument_space' => ['on_multiline' => 'ensure_fully_multiline'],
  3737. 'no_break_comment' => true,
  3738. 'no_closing_tag' => true,
  3739. 'no_spaces_after_function_name' => true,
  3740. 'no_spaces_inside_parenthesis' => true,
  3741. 'no_trailing_whitespace' => true,
  3742. 'no_trailing_whitespace_in_comment' => true,
  3743. 'single_blank_line_at_eof' => true,
  3744. 'single_class_element_per_statement' => ['elements' => ['property']],
  3745. 'single_import_per_statement' => true,
  3746. 'single_line_after_imports' => true,
  3747. 'switch_case_semicolon_to_colon' => true,
  3748. 'switch_case_space' => true,
  3749. 'visibility_required' => true,
  3750. ],
  3751. '@Symfony' => [
  3752. '@PSR2' => true,
  3753. 'array_syntax' => ['syntax' => 'short'],
  3754. 'binary_operator_spaces' => true,
  3755. 'blank_line_after_opening_tag' => true,
  3756. 'blank_line_before_statement' => [
  3757. 'statements' => ['return'],
  3758. ],
  3759. 'braces' => [
  3760. 'allow_single_line_closure' => true,
  3761. ],
  3762. 'cast_spaces' => true,
  3763. 'class_attributes_separation' => ['elements' => ['method']],
  3764. 'class_definition' => ['single_line' => true],
  3765. 'concat_space' => true,
  3766. 'declare_equal_normalize' => true,
  3767. 'function_typehint_space' => true,
  3768. 'include' => true,
  3769. 'increment_style' => true,
  3770. 'lowercase_cast' => true,
  3771. 'lowercase_static_reference' => true,
  3772. 'magic_constant_casing' => true,
  3773. 'magic_method_casing' => true,
  3774. 'method_argument_space' => true,
  3775. 'native_function_casing' => true,
  3776. 'native_function_type_declaration_casing' => true,
  3777. 'new_with_braces' => true,
  3778. 'no_blank_lines_after_class_opening' => true,
  3779. 'no_blank_lines_after_phpdoc' => true,
  3780. 'no_empty_comment' => true,
  3781. 'no_empty_phpdoc' => true,
  3782. 'no_empty_statement' => true,
  3783. 'no_extra_blank_lines' => ['tokens' => [
  3784. 'curly_brace_block',
  3785. 'extra',
  3786. 'parenthesis_brace_block',
  3787. 'square_brace_block',
  3788. 'throw',
  3789. 'use',
  3790. ]],
  3791. 'no_leading_import_slash' => true,
  3792. 'no_leading_namespace_whitespace' => true,
  3793. 'no_mixed_echo_print' => true,
  3794. 'no_multiline_whitespace_around_double_arrow' => true,
  3795. 'no_short_bool_cast' => true,
  3796. 'no_singleline_whitespace_before_semicolons' => true,
  3797. 'no_spaces_around_offset' => true,
  3798. 'no_superfluous_phpdoc_tags' => ['allow_mixed' => true, 'allow_unused_params' => true],
  3799. 'no_trailing_comma_in_list_call' => true,
  3800. 'no_trailing_comma_in_singleline_array' => true,
  3801. 'no_unneeded_control_parentheses' => true,
  3802. 'no_unneeded_curly_braces' => ['namespaces' => true],
  3803. 'no_unused_imports' => true,
  3804. 'no_whitespace_before_comma_in_array' => true,
  3805. 'no_whitespace_in_blank_line' => true,
  3806. 'normalize_index_brace' => true,
  3807. 'object_operator_without_whitespace' => true,
  3808. 'ordered_imports' => true,
  3809. 'php_unit_fqcn_annotation' => true,
  3810. 'phpdoc_align' => [
  3811. 'tags' => [
  3812. 'method',
  3813. 'param',
  3814. 'property',
  3815. 'return',
  3816. 'throws',
  3817. 'type',
  3818. 'var',
  3819. ],
  3820. ],
  3821. 'phpdoc_annotation_without_dot' => true,
  3822. 'phpdoc_indent' => true,
  3823. 'phpdoc_inline_tag' => true,
  3824. 'phpdoc_no_access' => true,
  3825. 'phpdoc_no_alias_tag' => true,
  3826. 'phpdoc_no_package' => true,
  3827. 'phpdoc_no_useless_inheritdoc' => true,
  3828. 'phpdoc_return_self_reference' => true,
  3829. 'phpdoc_scalar' => true,
  3830. 'phpdoc_separation' => true,
  3831. 'phpdoc_single_line_var_spacing' => true,
  3832. 'phpdoc_summary' => true,
  3833. 'phpdoc_to_comment' => true,
  3834. 'phpdoc_trim' => true,
  3835. 'phpdoc_trim_consecutive_blank_line_separation' => true,
  3836. 'phpdoc_types' => true,
  3837. 'phpdoc_types_order' => [
  3838. 'null_adjustment' => 'always_last',
  3839. 'sort_algorithm' => 'none',
  3840. ],
  3841. 'phpdoc_var_without_name' => true,
  3842. 'return_type_declaration' => true,
  3843. 'semicolon_after_instruction' => true,
  3844. 'short_scalar_cast' => true,
  3845. 'single_blank_line_before_namespace' => true,
  3846. 'single_class_element_per_statement' => true,
  3847. 'single_line_comment_style' => [
  3848. 'comment_types' => ['hash'],
  3849. ],
  3850. 'single_line_throw' => true,
  3851. 'single_quote' => true,
  3852. 'single_trait_insert_per_statement' => true,
  3853. 'space_after_semicolon' => [
  3854. 'remove_in_empty_for_expressions' => true,
  3855. ],
  3856. 'standardize_increment' => true,
  3857. 'standardize_not_equals' => true,
  3858. 'ternary_operator_spaces' => true,
  3859. 'trailing_comma_in_multiline_array' => true,
  3860. 'trim_array_spaces' => true,
  3861. 'unary_operator_spaces' => true,
  3862. 'whitespace_after_comma_in_array' => true,
  3863. 'yoda_style' => true,
  3864. ],
  3865. '@Symfony:risky' => [
  3866. 'dir_constant' => true,
  3867. 'ereg_to_preg' => true,
  3868. 'error_suppression' => true,
  3869. 'fopen_flag_order' => true,
  3870. 'fopen_flags' => ['b_mode' => false],
  3871. 'function_to_constant' => [
  3872. 'functions' => [
  3873. 'get_called_class',
  3874. 'get_class',
  3875. 'get_class_this',
  3876. 'php_sapi_name',
  3877. 'phpversion',
  3878. 'pi',
  3879. ],
  3880. ],
  3881. 'implode_call' => true,
  3882. 'is_null' => true,
  3883. 'modernize_types_casting' => true,
  3884. 'native_constant_invocation' => [
  3885. 'fix_built_in' => false,
  3886. 'include' => [
  3887. 'DIRECTORY_SEPARATOR',
  3888. 'PHP_SAPI',
  3889. 'PHP_VERSION_ID',
  3890. ],
  3891. 'scope' => 'namespaced',
  3892. ],
  3893. 'native_function_invocation' => [
  3894. 'include' => [NativeFunctionInvocationFixer::SET_COMPILER_OPTIMIZED],
  3895. 'scope' => 'namespaced',
  3896. 'strict' => true,
  3897. ],
  3898. 'no_alias_functions' => true,
  3899. 'no_homoglyph_names' => true,
  3900. 'no_unneeded_final_method' => true,
  3901. 'non_printable_character' => true,
  3902. 'php_unit_construct' => true,
  3903. 'php_unit_mock_short_will_return' => true,
  3904. 'psr4' => true,
  3905. 'self_accessor' => true,
  3906. 'set_type_to_cast' => true,
  3907. ],
  3908. '@PhpCsFixer' => [
  3909. '@Symfony' => true,
  3910. 'align_multiline_comment' => true,
  3911. 'array_indentation' => true,
  3912. 'blank_line_before_statement' => true,
  3913. 'combine_consecutive_issets' => true,
  3914. 'combine_consecutive_unsets' => true,
  3915. 'compact_nullable_typehint' => true,
  3916. 'escape_implicit_backslashes' => true,
  3917. 'explicit_indirect_variable' => true,
  3918. 'explicit_string_variable' => true,
  3919. 'fully_qualified_strict_types' => true,
  3920. 'heredoc_to_nowdoc' => true,
  3921. 'method_argument_space' => ['on_multiline' => 'ensure_fully_multiline'],
  3922. 'method_chaining_indentation' => true,
  3923. 'multiline_comment_opening_closing' => true,
  3924. 'multiline_whitespace_before_semicolons' => ['strategy' => 'new_line_for_chained_calls'],
  3925. 'no_alternative_syntax' => true,
  3926. 'no_binary_string' => true,
  3927. 'no_extra_blank_lines' => ['tokens' => [
  3928. 'break',
  3929. 'continue',
  3930. 'curly_brace_block',
  3931. 'extra',
  3932. 'parenthesis_brace_block',
  3933. 'return',
  3934. 'square_brace_block',
  3935. 'throw',
  3936. 'use',
  3937. ]],
  3938. 'no_null_property_initialization' => true,
  3939. 'no_short_echo_tag' => true,
  3940. 'no_superfluous_elseif' => true,
  3941. 'no_unset_cast' => true,
  3942. 'no_useless_else' => true,
  3943. 'no_useless_return' => true,
  3944. 'ordered_class_elements' => true,
  3945. 'php_unit_internal_class' => true,
  3946. 'php_unit_method_casing' => true,
  3947. 'php_unit_ordered_covers' => true,
  3948. 'php_unit_test_class_requires_covers' => true,
  3949. 'phpdoc_add_missing_param_annotation' => true,
  3950. 'phpdoc_no_empty_return' => true,
  3951. 'phpdoc_order' => true,
  3952. 'phpdoc_types_order' => true,
  3953. 'phpdoc_var_annotation_correct_order' => true,
  3954. 'protected_to_private' => true,
  3955. 'return_assignment' => true,
  3956. 'simple_to_complex_string_variable' => true,
  3957. 'single_line_comment_style' => true,
  3958. 'single_line_throw' => false,
  3959. ],
  3960. '@PhpCsFixer:risky' => [
  3961. '@Symfony:risky' => true,
  3962. 'comment_to_phpdoc' => true,
  3963. 'final_internal_class' => true,
  3964. 'logical_operators' => true,
  3965. 'no_unreachable_default_argument_value' => true,
  3966. 'no_unset_on_property' => true,
  3967. 'php_unit_set_up_tear_down_visibility' => true,
  3968. 'php_unit_strict' => true,
  3969. 'php_unit_test_annotation' => true,
  3970. 'php_unit_test_case_static_method_calls' => true,
  3971. 'strict_comparison' => true,
  3972. 'strict_param' => true,
  3973. 'string_line_ending' => true,
  3974. ],
  3975. '@DoctrineAnnotation' => [
  3976. 'doctrine_annotation_array_assignment' => [
  3977. 'operator' => ':',
  3978. ],
  3979. 'doctrine_annotation_braces' => true,
  3980. 'doctrine_annotation_indentation' => true,
  3981. 'doctrine_annotation_spaces' => [
  3982. 'before_array_assignments_colon' => false,
  3983. ],
  3984. ],
  3985. '@PHP56Migration' => [],
  3986. '@PHP56Migration:risky' => [
  3987. 'pow_to_exponentiation' => true,
  3988. ],
  3989. '@PHP70Migration' => [
  3990. '@PHP56Migration' => true,
  3991. 'ternary_to_null_coalescing' => true,
  3992. ],
  3993. '@PHP70Migration:risky' => [
  3994. '@PHP56Migration:risky' => true,
  3995. 'combine_nested_dirname' => true,
  3996. 'declare_strict_types' => true,
  3997. 'non_printable_character' => [
  3998. 'use_escape_sequences_in_strings' => true,
  3999. ],
  4000. 'random_api_migration' => ['replacements' => [
  4001. 'mt_rand' => 'random_int',
  4002. 'rand' => 'random_int',
  4003. ]],
  4004. ],
  4005. '@PHP71Migration' => [
  4006. '@PHP70Migration' => true,
  4007. 'visibility_required' => ['elements' => [
  4008. 'const',
  4009. 'method',
  4010. 'property',
  4011. ]],
  4012. ],
  4013. '@PHP71Migration:risky' => [
  4014. '@PHP70Migration:risky' => true,
  4015. 'void_return' => true,
  4016. ],
  4017. '@PHP73Migration' => [
  4018. '@PHP71Migration' => true,
  4019. 'heredoc_indentation' => true,
  4020. ],
  4021. '@PHPUnit30Migration:risky' => [
  4022. 'php_unit_dedicate_assert' => ['target' => PhpUnitTargetVersion::VERSION_3_0],
  4023. ],
  4024. '@PHPUnit32Migration:risky' => [
  4025. '@PHPUnit30Migration:risky' => true,
  4026. 'php_unit_no_expectation_annotation' => ['target' => PhpUnitTargetVersion::VERSION_3_2],
  4027. ],
  4028. '@PHPUnit35Migration:risky' => [
  4029. '@PHPUnit32Migration:risky' => true,
  4030. 'php_unit_dedicate_assert' => ['target' => PhpUnitTargetVersion::VERSION_3_5],
  4031. ],
  4032. '@PHPUnit43Migration:risky' => [
  4033. '@PHPUnit35Migration:risky' => true,
  4034. 'php_unit_no_expectation_annotation' => ['target' => PhpUnitTargetVersion::VERSION_4_3],
  4035. ],
  4036. '@PHPUnit48Migration:risky' => [
  4037. '@PHPUnit43Migration:risky' => true,
  4038. 'php_unit_namespaced' => ['target' => PhpUnitTargetVersion::VERSION_4_8],
  4039. ],
  4040. '@PHPUnit50Migration:risky' => [
  4041. '@PHPUnit48Migration:risky' => true,
  4042. 'php_unit_dedicate_assert' => true,
  4043. ],
  4044. '@PHPUnit52Migration:risky' => [
  4045. '@PHPUnit50Migration:risky' => true,
  4046. 'php_unit_expectation' => ['target' => PhpUnitTargetVersion::VERSION_5_2],
  4047. ],
  4048. '@PHPUnit54Migration:risky' => [
  4049. '@PHPUnit52Migration:risky' => true,
  4050. 'php_unit_mock' => ['target' => PhpUnitTargetVersion::VERSION_5_4],
  4051. ],
  4052. '@PHPUnit55Migration:risky' => [
  4053. '@PHPUnit54Migration:risky' => true,
  4054. 'php_unit_mock' => ['target' => PhpUnitTargetVersion::VERSION_5_5],
  4055. ],
  4056. '@PHPUnit56Migration:risky' => [
  4057. '@PHPUnit55Migration:risky' => true,
  4058. 'php_unit_dedicate_assert' => ['target' => PhpUnitTargetVersion::VERSION_5_6],
  4059. 'php_unit_expectation' => ['target' => PhpUnitTargetVersion::VERSION_5_6],
  4060. ],
  4061. '@PHPUnit57Migration:risky' => [
  4062. '@PHPUnit56Migration:risky' => true,
  4063. 'php_unit_namespaced' => ['target' => PhpUnitTargetVersion::VERSION_5_7],
  4064. ],
  4065. '@PHPUnit60Migration:risky' => [
  4066. '@PHPUnit57Migration:risky' => true,
  4067. 'php_unit_namespaced' => ['target' => PhpUnitTargetVersion::VERSION_6_0],
  4068. ],
  4069. '@PHPUnit75Migration:risky' => [
  4070. '@PHPUnit60Migration:risky' => true,
  4071. 'php_unit_dedicate_assert_internal_type' => ['target' => PhpUnitTargetVersion::VERSION_7_5],
  4072. ],
  4073. ];
  4074. private $set;
  4075. private $rules;
  4076. public function __construct(array $set = [])
  4077. {
  4078. foreach ($set as $key => $value) {
  4079. if (\is_int($key)) {
  4080. throw new \InvalidArgumentException(sprintf('Missing value for "%s" rule/set.', $value));
  4081. }
  4082. }
  4083. $this->set = $set;
  4084. $this->resolveSet();
  4085. }
  4086. public static function create(array $set = [])
  4087. {
  4088. return new self($set);
  4089. }
  4090. public function hasRule($rule)
  4091. {
  4092. return \array_key_exists($rule, $this->rules);
  4093. }
  4094. public function getRuleConfiguration($rule)
  4095. {
  4096. if (!$this->hasRule($rule)) {
  4097. throw new \InvalidArgumentException(sprintf('Rule "%s" is not in the set.', $rule));
  4098. }
  4099. if (true === $this->rules[$rule]) {
  4100. return null;
  4101. }
  4102. return $this->rules[$rule];
  4103. }
  4104. public function getRules()
  4105. {
  4106. return $this->rules;
  4107. }
  4108. public function getSetDefinitionNames()
  4109. {
  4110. return array_keys($this->setDefinitions);
  4111. }
  4112. private function getSetDefinition($name)
  4113. {
  4114. if (!isset($this->setDefinitions[$name])) {
  4115. throw new \InvalidArgumentException(sprintf('Set "%s" does not exist.', $name));
  4116. }
  4117. return $this->setDefinitions[$name];
  4118. }
  4119. private function resolveSet()
  4120. {
  4121. $rules = $this->set;
  4122. $resolvedRules = [];
  4123. foreach ($rules as $name => $value) {
  4124. if ('@' === $name[0]) {
  4125. if (!\is_bool($value)) {
  4126. throw new \UnexpectedValueException(sprintf('Nested rule set "%s" configuration must be a boolean.', $name));
  4127. }
  4128. $set = $this->resolveSubset($name, $value);
  4129. $resolvedRules = array_merge($resolvedRules, $set);
  4130. } else {
  4131. $resolvedRules[$name] = $value;
  4132. }
  4133. }
  4134. $resolvedRules = array_filter($resolvedRules);
  4135. $this->rules = $resolvedRules;
  4136. return $this;
  4137. }
  4138. private function resolveSubset($setName, $setValue)
  4139. {
  4140. $rules = $this->getSetDefinition($setName);
  4141. foreach ($rules as $name => $value) {
  4142. if ('@' === $name[0]) {
  4143. $set = $this->resolveSubset($name, $setValue);
  4144. unset($rules[$name]);
  4145. $rules = array_merge($rules, $set);
  4146. } elseif (!$setValue) {
  4147. $rules[$name] = false;
  4148. } else {
  4149. $rules[$name] = $value;
  4150. }
  4151. }
  4152. return $rules;
  4153. }
  4154. }
  4155. <?php
  4156. namespace PhpCsFixer;
  4157. use PhpCsFixer\ConfigurationException\InvalidFixerConfigurationException;
  4158. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  4159. use PhpCsFixer\Fixer\FixerInterface;
  4160. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  4161. use Symfony\Component\Finder\Finder as SymfonyFinder;
  4162. use Symfony\Component\Finder\SplFileInfo;
  4163. final class FixerFactory
  4164. {
  4165. private $nameValidator;
  4166. private $fixers = [];
  4167. private $fixersByName = [];
  4168. public function __construct()
  4169. {
  4170. $this->nameValidator = new FixerNameValidator();
  4171. }
  4172. public static function create()
  4173. {
  4174. return new self();
  4175. }
  4176. public function setWhitespacesConfig(WhitespacesFixerConfig $config)
  4177. {
  4178. foreach ($this->fixers as $fixer) {
  4179. if ($fixer instanceof WhitespacesAwareFixerInterface) {
  4180. $fixer->setWhitespacesConfig($config);
  4181. }
  4182. }
  4183. return $this;
  4184. }
  4185. public function getFixers()
  4186. {
  4187. $this->fixers = Utils::sortFixers($this->fixers);
  4188. return $this->fixers;
  4189. }
  4190. public function registerBuiltInFixers()
  4191. {
  4192. static $builtInFixers = null;
  4193. if (null === $builtInFixers) {
  4194. $builtInFixers = [];
  4195. foreach (SymfonyFinder::create()->files()->in(__DIR__.'/Fixer') as $file) {
  4196. $relativeNamespace = $file->getRelativePath();
  4197. $fixerClass = 'PhpCsFixer\\Fixer\\'.($relativeNamespace ? $relativeNamespace.'\\' : '').$file->getBasename('.php');
  4198. if ('Fixer' === substr($fixerClass, -5)) {
  4199. $builtInFixers[] = $fixerClass;
  4200. }
  4201. }
  4202. }
  4203. foreach ($builtInFixers as $class) {
  4204. $this->registerFixer(new $class(), false);
  4205. }
  4206. return $this;
  4207. }
  4208. public function registerCustomFixers(array $fixers)
  4209. {
  4210. foreach ($fixers as $fixer) {
  4211. $this->registerFixer($fixer, true);
  4212. }
  4213. return $this;
  4214. }
  4215. public function registerFixer(FixerInterface $fixer, $isCustom)
  4216. {
  4217. $name = $fixer->getName();
  4218. if (isset($this->fixersByName[$name])) {
  4219. throw new \UnexpectedValueException(sprintf('Fixer named "%s" is already registered.', $name));
  4220. }
  4221. if (!$this->nameValidator->isValid($name, $isCustom)) {
  4222. throw new \UnexpectedValueException(sprintf('Fixer named "%s" has invalid name.', $name));
  4223. }
  4224. $this->fixers[] = $fixer;
  4225. $this->fixersByName[$name] = $fixer;
  4226. return $this;
  4227. }
  4228. public function useRuleSet(RuleSetInterface $ruleSet)
  4229. {
  4230. $fixers = [];
  4231. $fixersByName = [];
  4232. $fixerConflicts = [];
  4233. $fixerNames = array_keys($ruleSet->getRules());
  4234. foreach ($fixerNames as $name) {
  4235. if (!\array_key_exists($name, $this->fixersByName)) {
  4236. throw new \UnexpectedValueException(sprintf('Rule "%s" does not exist.', $name));
  4237. }
  4238. $fixer = $this->fixersByName[$name];
  4239. $config = $ruleSet->getRuleConfiguration($name);
  4240. if (null !== $config) {
  4241. if ($fixer instanceof ConfigurableFixerInterface) {
  4242. if (!\is_array($config) || !\count($config)) {
  4243. throw new InvalidFixerConfigurationException($fixer->getName(), 'Configuration must be an array and may not be empty.');
  4244. }
  4245. $fixer->configure($config);
  4246. } else {
  4247. throw new InvalidFixerConfigurationException($fixer->getName(), 'Is not configurable.');
  4248. }
  4249. }
  4250. $fixers[] = $fixer;
  4251. $fixersByName[$name] = $fixer;
  4252. $conflicts = array_intersect($this->getFixersConflicts($fixer), $fixerNames);
  4253. if (\count($conflicts) > 0) {
  4254. $fixerConflicts[$name] = $conflicts;
  4255. }
  4256. }
  4257. if (\count($fixerConflicts) > 0) {
  4258. throw new \UnexpectedValueException($this->generateConflictMessage($fixerConflicts));
  4259. }
  4260. $this->fixers = $fixers;
  4261. $this->fixersByName = $fixersByName;
  4262. return $this;
  4263. }
  4264. public function hasRule($name)
  4265. {
  4266. return isset($this->fixersByName[$name]);
  4267. }
  4268. private function getFixersConflicts(FixerInterface $fixer)
  4269. {
  4270. static $conflictMap = [
  4271. 'no_blank_lines_before_namespace' => ['single_blank_line_before_namespace'],
  4272. ];
  4273. $fixerName = $fixer->getName();
  4274. return \array_key_exists($fixerName, $conflictMap) ? $conflictMap[$fixerName] : [];
  4275. }
  4276. private function generateConflictMessage(array $fixerConflicts)
  4277. {
  4278. $message = 'Rule contains conflicting fixers:';
  4279. $report = [];
  4280. foreach ($fixerConflicts as $fixer => $fixers) {
  4281. $report[$fixer] = array_filter(
  4282. $fixers,
  4283. static function ($candidate) use ($report, $fixer) {
  4284. return !\array_key_exists($candidate, $report) || !\in_array($fixer, $report[$candidate], true);
  4285. }
  4286. );
  4287. if (\count($report[$fixer]) > 0) {
  4288. $message .= sprintf("\n- \"%s\" with \"%s\"", $fixer, implode('", "', $report[$fixer]));
  4289. }
  4290. }
  4291. return $message;
  4292. }
  4293. }
  4294. <?php
  4295. namespace PhpCsFixer;
  4296. final class PharChecker implements PharCheckerInterface
  4297. {
  4298. public function checkFileValidity($filename)
  4299. {
  4300. try {
  4301. $phar = new \Phar($filename);
  4302. unset($phar);
  4303. } catch (\Exception $e) {
  4304. if (!$e instanceof \UnexpectedValueException && !$e instanceof \PharException) {
  4305. throw $e;
  4306. }
  4307. return 'Failed to create Phar instance. '.$e->getMessage();
  4308. }
  4309. return null;
  4310. }
  4311. }
  4312. <?php
  4313. namespace PhpCsFixer\Runner;
  4314. use PhpCsFixer\Linter\LinterInterface;
  4315. use PhpCsFixer\Linter\LintingResultInterface;
  4316. final class FileCachingLintingIterator extends \CachingIterator
  4317. {
  4318. private $currentResult;
  4319. private $linter;
  4320. private $nextResult;
  4321. public function __construct(\Iterator $iterator, LinterInterface $linter)
  4322. {
  4323. parent::__construct($iterator);
  4324. $this->linter = $linter;
  4325. }
  4326. public function currentLintingResult()
  4327. {
  4328. return $this->currentResult;
  4329. }
  4330. public function next()
  4331. {
  4332. parent::next();
  4333. $this->currentResult = $this->nextResult;
  4334. if ($this->hasNext()) {
  4335. $this->nextResult = $this->handleItem($this->getInnerIterator()->current());
  4336. }
  4337. }
  4338. public function rewind()
  4339. {
  4340. parent::rewind();
  4341. if ($this->valid()) {
  4342. $this->currentResult = $this->handleItem($this->current());
  4343. }
  4344. if ($this->hasNext()) {
  4345. $this->nextResult = $this->handleItem($this->getInnerIterator()->current());
  4346. }
  4347. }
  4348. private function handleItem(\SplFileInfo $file)
  4349. {
  4350. return $this->linter->lintFile($file->getRealPath());
  4351. }
  4352. }
  4353. <?php
  4354. namespace PhpCsFixer\Runner;
  4355. use PhpCsFixer\AbstractFixer;
  4356. use PhpCsFixer\Cache\CacheManagerInterface;
  4357. use PhpCsFixer\Cache\Directory;
  4358. use PhpCsFixer\Cache\DirectoryInterface;
  4359. use PhpCsFixer\Differ\DifferInterface;
  4360. use PhpCsFixer\Error\Error;
  4361. use PhpCsFixer\Error\ErrorsManager;
  4362. use PhpCsFixer\Event\Event;
  4363. use PhpCsFixer\FileReader;
  4364. use PhpCsFixer\Fixer\FixerInterface;
  4365. use PhpCsFixer\FixerFileProcessedEvent;
  4366. use PhpCsFixer\Linter\LinterInterface;
  4367. use PhpCsFixer\Linter\LintingException;
  4368. use PhpCsFixer\Linter\LintingResultInterface;
  4369. use PhpCsFixer\Tokenizer\Tokens;
  4370. use Symfony\Component\EventDispatcher\EventDispatcherInterface;
  4371. use Symfony\Component\Filesystem\Exception\IOException;
  4372. final class Runner
  4373. {
  4374. private $differ;
  4375. private $directory;
  4376. private $eventDispatcher;
  4377. private $errorsManager;
  4378. private $cacheManager;
  4379. private $isDryRun;
  4380. private $linter;
  4381. private $finder;
  4382. private $fixers;
  4383. private $stopOnViolation;
  4384. public function __construct(
  4385. $finder,
  4386. array $fixers,
  4387. DifferInterface $differ,
  4388. EventDispatcherInterface $eventDispatcher = null,
  4389. ErrorsManager $errorsManager,
  4390. LinterInterface $linter,
  4391. $isDryRun,
  4392. CacheManagerInterface $cacheManager,
  4393. DirectoryInterface $directory = null,
  4394. $stopOnViolation = false
  4395. ) {
  4396. $this->finder = $finder;
  4397. $this->fixers = $fixers;
  4398. $this->differ = $differ;
  4399. $this->eventDispatcher = $eventDispatcher;
  4400. $this->errorsManager = $errorsManager;
  4401. $this->linter = $linter;
  4402. $this->isDryRun = $isDryRun;
  4403. $this->cacheManager = $cacheManager;
  4404. $this->directory = $directory ?: new Directory('');
  4405. $this->stopOnViolation = $stopOnViolation;
  4406. }
  4407. public function fix()
  4408. {
  4409. $changed = [];
  4410. $finder = $this->finder;
  4411. $finderIterator = $finder instanceof \IteratorAggregate ? $finder->getIterator() : $finder;
  4412. $fileFilteredFileIterator = new FileFilterIterator(
  4413. $finderIterator,
  4414. $this->eventDispatcher,
  4415. $this->cacheManager
  4416. );
  4417. $collection = $this->linter->isAsync()
  4418. ? new FileCachingLintingIterator($fileFilteredFileIterator, $this->linter)
  4419. : new FileLintingIterator($fileFilteredFileIterator, $this->linter);
  4420. foreach ($collection as $file) {
  4421. $fixInfo = $this->fixFile($file, $collection->currentLintingResult());
  4422. Tokens::clearCache();
  4423. if ($fixInfo) {
  4424. $name = $this->directory->getRelativePathTo($file);
  4425. $changed[$name] = $fixInfo;
  4426. if ($this->stopOnViolation) {
  4427. break;
  4428. }
  4429. }
  4430. }
  4431. return $changed;
  4432. }
  4433. private function fixFile(\SplFileInfo $file, LintingResultInterface $lintingResult)
  4434. {
  4435. $name = $file->getPathname();
  4436. try {
  4437. $lintingResult->check();
  4438. } catch (LintingException $e) {
  4439. $this->dispatchEvent(
  4440. FixerFileProcessedEvent::NAME,
  4441. new FixerFileProcessedEvent(FixerFileProcessedEvent::STATUS_INVALID)
  4442. );
  4443. $this->errorsManager->report(new Error(Error::TYPE_INVALID, $name, $e));
  4444. return;
  4445. }
  4446. $old = FileReader::createSingleton()->read($file->getRealPath());
  4447. Tokens::setLegacyMode(false);
  4448. $tokens = Tokens::fromCode($old);
  4449. $oldHash = $tokens->getCodeHash();
  4450. $newHash = $oldHash;
  4451. $new = $old;
  4452. $appliedFixers = [];
  4453. try {
  4454. foreach ($this->fixers as $fixer) {
  4455. if (
  4456. !$fixer instanceof AbstractFixer &&
  4457. (!$fixer->supports($file) || !$fixer->isCandidate($tokens))
  4458. ) {
  4459. continue;
  4460. }
  4461. $fixer->fix($file, $tokens);
  4462. if ($tokens->isChanged()) {
  4463. $tokens->clearEmptyTokens();
  4464. $tokens->clearChanged();
  4465. $appliedFixers[] = $fixer->getName();
  4466. }
  4467. }
  4468. } catch (\Exception $e) {
  4469. $this->processException($name, $e);
  4470. return;
  4471. } catch (\ParseError $e) {
  4472. $this->dispatchEvent(
  4473. FixerFileProcessedEvent::NAME,
  4474. new FixerFileProcessedEvent(FixerFileProcessedEvent::STATUS_LINT)
  4475. );
  4476. $this->errorsManager->report(new Error(Error::TYPE_LINT, $name, $e));
  4477. return;
  4478. } catch (\Throwable $e) {
  4479. $this->processException($name, $e);
  4480. return;
  4481. }
  4482. $fixInfo = null;
  4483. if (!empty($appliedFixers)) {
  4484. $new = $tokens->generateCode();
  4485. $newHash = $tokens->getCodeHash();
  4486. }
  4487. if ($oldHash !== $newHash) {
  4488. $fixInfo = [
  4489. 'appliedFixers' => $appliedFixers,
  4490. 'diff' => $this->differ->diff($old, $new),
  4491. ];
  4492. try {
  4493. $this->linter->lintSource($new)->check();
  4494. } catch (LintingException $e) {
  4495. $this->dispatchEvent(
  4496. FixerFileProcessedEvent::NAME,
  4497. new FixerFileProcessedEvent(FixerFileProcessedEvent::STATUS_LINT)
  4498. );
  4499. $this->errorsManager->report(new Error(Error::TYPE_LINT, $name, $e, $fixInfo['appliedFixers'], $fixInfo['diff']));
  4500. return;
  4501. }
  4502. if (!$this->isDryRun) {
  4503. if (false === @file_put_contents($file->getRealPath(), $new)) {
  4504. $error = error_get_last();
  4505. throw new IOException(
  4506. sprintf('Failed to write file "%s", "%s".', $file->getPathname(), $error ? $error['message'] : 'no reason available'),
  4507. 0,
  4508. null,
  4509. $file->getRealPath()
  4510. );
  4511. }
  4512. }
  4513. }
  4514. $this->cacheManager->setFile($name, $new);
  4515. $this->dispatchEvent(
  4516. FixerFileProcessedEvent::NAME,
  4517. new FixerFileProcessedEvent($fixInfo ? FixerFileProcessedEvent::STATUS_FIXED : FixerFileProcessedEvent::STATUS_NO_CHANGES)
  4518. );
  4519. return $fixInfo;
  4520. }
  4521. private function processException($name, $e)
  4522. {
  4523. $this->dispatchEvent(
  4524. FixerFileProcessedEvent::NAME,
  4525. new FixerFileProcessedEvent(FixerFileProcessedEvent::STATUS_EXCEPTION)
  4526. );
  4527. $this->errorsManager->report(new Error(Error::TYPE_EXCEPTION, $name, $e));
  4528. }
  4529. private function dispatchEvent($name, Event $event)
  4530. {
  4531. if (null === $this->eventDispatcher) {
  4532. return;
  4533. }
  4534. if (
  4535. !$this->eventDispatcher instanceof \Symfony\Contracts\EventDispatcher\EventDispatcherInterface
  4536. ) {
  4537. $this->eventDispatcher->dispatch($name, $event);
  4538. return;
  4539. }
  4540. $this->eventDispatcher->dispatch($event, $name);
  4541. }
  4542. }
  4543. <?php
  4544. namespace PhpCsFixer\Runner;
  4545. use PhpCsFixer\Linter\LinterInterface;
  4546. use PhpCsFixer\Linter\LintingResultInterface;
  4547. final class FileLintingIterator extends \IteratorIterator
  4548. {
  4549. private $currentResult;
  4550. private $linter;
  4551. public function __construct(\Iterator $iterator, LinterInterface $linter)
  4552. {
  4553. parent::__construct($iterator);
  4554. $this->linter = $linter;
  4555. }
  4556. public function currentLintingResult()
  4557. {
  4558. return $this->currentResult;
  4559. }
  4560. public function next()
  4561. {
  4562. parent::next();
  4563. $this->currentResult = $this->valid() ? $this->handleItem($this->current()) : null;
  4564. }
  4565. public function rewind()
  4566. {
  4567. parent::rewind();
  4568. $this->currentResult = $this->valid() ? $this->handleItem($this->current()) : null;
  4569. }
  4570. private function handleItem(\SplFileInfo $file)
  4571. {
  4572. return $this->linter->lintFile($file->getRealPath());
  4573. }
  4574. }
  4575. <?php
  4576. namespace PhpCsFixer\Runner;
  4577. use PhpCsFixer\Cache\CacheManagerInterface;
  4578. use PhpCsFixer\Event\Event;
  4579. use PhpCsFixer\FileReader;
  4580. use PhpCsFixer\FixerFileProcessedEvent;
  4581. use Symfony\Component\EventDispatcher\EventDispatcherInterface;
  4582. final class FileFilterIterator extends \FilterIterator
  4583. {
  4584. private $eventDispatcher;
  4585. private $cacheManager;
  4586. private $visitedElements = [];
  4587. public function __construct(
  4588. \Traversable $iterator,
  4589. EventDispatcherInterface $eventDispatcher = null,
  4590. CacheManagerInterface $cacheManager
  4591. ) {
  4592. if (!$iterator instanceof \Iterator) {
  4593. $iterator = new \IteratorIterator($iterator);
  4594. }
  4595. parent::__construct($iterator);
  4596. $this->eventDispatcher = $eventDispatcher;
  4597. $this->cacheManager = $cacheManager;
  4598. }
  4599. public function accept()
  4600. {
  4601. $file = $this->current();
  4602. if (!$file instanceof \SplFileInfo) {
  4603. throw new \RuntimeException(
  4604. sprintf(
  4605. 'Expected instance of "\SplFileInfo", got "%s".',
  4606. \is_object($file) ? \get_class($file) : \gettype($file)
  4607. )
  4608. );
  4609. }
  4610. $path = $file->isLink() ? $file->getPathname() : $file->getRealPath();
  4611. if (isset($this->visitedElements[$path])) {
  4612. return false;
  4613. }
  4614. $this->visitedElements[$path] = true;
  4615. if (!$file->isFile() || $file->isLink()) {
  4616. return false;
  4617. }
  4618. $content = FileReader::createSingleton()->read($path);
  4619. if (
  4620. '' === $content
  4621. || !$this->cacheManager->needFixing($file->getPathname(), $content)
  4622. ) {
  4623. $this->dispatchEvent(
  4624. FixerFileProcessedEvent::NAME,
  4625. new FixerFileProcessedEvent(FixerFileProcessedEvent::STATUS_SKIPPED)
  4626. );
  4627. return false;
  4628. }
  4629. return true;
  4630. }
  4631. private function dispatchEvent($name, Event $event)
  4632. {
  4633. if (null === $this->eventDispatcher) {
  4634. return;
  4635. }
  4636. if (
  4637. !$this->eventDispatcher instanceof \Symfony\Contracts\EventDispatcher\EventDispatcherInterface
  4638. ) {
  4639. $this->eventDispatcher->dispatch($name, $event);
  4640. return;
  4641. }
  4642. $this->eventDispatcher->dispatch($event, $name);
  4643. }
  4644. }
  4645. <?php
  4646. namespace PhpCsFixer;
  4647. /**
  4648. @PSR2
  4649. @PSR1
  4650. */
  4651. interface RuleSetInterface
  4652. {
  4653. public function __construct(array $set = []);
  4654. public static function create(array $set = []);
  4655. public function getRuleConfiguration($rule);
  4656. public function getRules();
  4657. public function getSetDefinitionNames();
  4658. public function hasRule($rule);
  4659. }
  4660. <?php
  4661. namespace PhpCsFixer\Linter;
  4662. use PhpCsFixer\FileReader;
  4663. use PhpCsFixer\FileRemoval;
  4664. use Symfony\Component\Filesystem\Exception\IOException;
  4665. use Symfony\Component\Process\PhpExecutableFinder;
  4666. use Symfony\Component\Process\Process;
  4667. final class ProcessLinter implements LinterInterface
  4668. {
  4669. private $fileRemoval;
  4670. private $processBuilder;
  4671. private $temporaryFile;
  4672. public function __construct($executable = null)
  4673. {
  4674. if (null === $executable) {
  4675. $executableFinder = new PhpExecutableFinder();
  4676. $executable = $executableFinder->find(false);
  4677. if (false === $executable) {
  4678. throw new UnavailableLinterException('Cannot find PHP executable.');
  4679. }
  4680. if ('phpdbg' === \PHP_SAPI) {
  4681. if (false === strpos($executable, 'phpdbg')) {
  4682. throw new UnavailableLinterException('Automatically found PHP executable is non-standard phpdbg. Could not find proper PHP executable.');
  4683. }
  4684. $executable = str_replace('phpdbg', 'php', $executable);
  4685. if (!is_executable($executable)) {
  4686. throw new UnavailableLinterException('Automatically found PHP executable is phpdbg. Could not find proper PHP executable.');
  4687. }
  4688. }
  4689. }
  4690. $this->processBuilder = new ProcessLinterProcessBuilder($executable);
  4691. $this->fileRemoval = new FileRemoval();
  4692. }
  4693. public function __destruct()
  4694. {
  4695. if (null !== $this->temporaryFile) {
  4696. $this->fileRemoval->delete($this->temporaryFile);
  4697. }
  4698. }
  4699. public function isAsync()
  4700. {
  4701. return true;
  4702. }
  4703. public function lintFile($path)
  4704. {
  4705. return new ProcessLintingResult($this->createProcessForFile($path));
  4706. }
  4707. public function lintSource($source)
  4708. {
  4709. return new ProcessLintingResult($this->createProcessForSource($source));
  4710. }
  4711. private function createProcessForFile($path)
  4712. {
  4713. if (!is_file($path)) {
  4714. return $this->createProcessForSource(FileReader::createSingleton()->read($path));
  4715. }
  4716. $process = $this->processBuilder->build($path);
  4717. $process->setTimeout(10);
  4718. $process->start();
  4719. return $process;
  4720. }
  4721. private function createProcessForSource($source)
  4722. {
  4723. if (null === $this->temporaryFile) {
  4724. $this->temporaryFile = tempnam('.', 'cs_fixer_tmp_');
  4725. $this->fileRemoval->observe($this->temporaryFile);
  4726. }
  4727. if (false === @file_put_contents($this->temporaryFile, $source)) {
  4728. throw new IOException(sprintf('Failed to write file "%s".', $this->temporaryFile), 0, null, $this->temporaryFile);
  4729. }
  4730. return $this->createProcessForFile($this->temporaryFile);
  4731. }
  4732. }
  4733. <?php
  4734. namespace PhpCsFixer\Linter;
  4735. use Symfony\Component\Process\Process;
  4736. final class ProcessLintingResult implements LintingResultInterface
  4737. {
  4738. private $isSuccessful;
  4739. private $process;
  4740. public function __construct(Process $process)
  4741. {
  4742. $this->process = $process;
  4743. }
  4744. public function check()
  4745. {
  4746. if (!$this->isSuccessful()) {
  4747. throw new LintingException($this->process->getErrorOutput() ?: $this->process->getOutput(), $this->process->getExitCode());
  4748. }
  4749. }
  4750. private function isSuccessful()
  4751. {
  4752. if (null === $this->isSuccessful) {
  4753. $this->process->wait();
  4754. $this->isSuccessful = $this->process->isSuccessful();
  4755. }
  4756. return $this->isSuccessful;
  4757. }
  4758. }
  4759. <?php
  4760. namespace PhpCsFixer\Linter;
  4761. interface LintingResultInterface
  4762. {
  4763. public function check();
  4764. }
  4765. <?php
  4766. namespace PhpCsFixer\Linter;
  4767. class LintingException extends \RuntimeException
  4768. {
  4769. }
  4770. <?php
  4771. namespace PhpCsFixer\Linter;
  4772. use Symfony\Component\Process\Process;
  4773. final class ProcessLinterProcessBuilder
  4774. {
  4775. private $executable;
  4776. public function __construct($executable)
  4777. {
  4778. $this->executable = $executable;
  4779. }
  4780. public function build($path)
  4781. {
  4782. return new Process([
  4783. $this->executable,
  4784. '-l',
  4785. $path,
  4786. ]);
  4787. }
  4788. }
  4789. <?php
  4790. namespace PhpCsFixer\Linter;
  4791. use PhpCsFixer\FileReader;
  4792. use PhpCsFixer\Tokenizer\CodeHasher;
  4793. use PhpCsFixer\Tokenizer\Tokens;
  4794. final class TokenizerLinter implements LinterInterface
  4795. {
  4796. public function __construct()
  4797. {
  4798. if (false === \defined('TOKEN_PARSE')) {
  4799. throw new UnavailableLinterException('Cannot use tokenizer as linter.');
  4800. }
  4801. }
  4802. public function isAsync()
  4803. {
  4804. return false;
  4805. }
  4806. public function lintFile($path)
  4807. {
  4808. return $this->lintSource(FileReader::createSingleton()->read($path));
  4809. }
  4810. public function lintSource($source)
  4811. {
  4812. try {
  4813. $codeHash = CodeHasher::calculateCodeHash($source);
  4814. Tokens::clearCache($codeHash);
  4815. Tokens::fromCode($source);
  4816. return new TokenizerLintingResult();
  4817. } catch (\ParseError $e) {
  4818. return new TokenizerLintingResult($e);
  4819. }
  4820. }
  4821. }
  4822. <?php
  4823. namespace PhpCsFixer\Linter;
  4824. class UnavailableLinterException extends \RuntimeException
  4825. {
  4826. }
  4827. <?php
  4828. namespace PhpCsFixer\Linter;
  4829. final class Linter implements LinterInterface
  4830. {
  4831. private $sublinter;
  4832. public function __construct($executable = null)
  4833. {
  4834. try {
  4835. $this->sublinter = new TokenizerLinter();
  4836. } catch (UnavailableLinterException $e) {
  4837. $this->sublinter = new ProcessLinter($executable);
  4838. }
  4839. }
  4840. public function isAsync()
  4841. {
  4842. return $this->sublinter->isAsync();
  4843. }
  4844. public function lintFile($path)
  4845. {
  4846. return $this->sublinter->lintFile($path);
  4847. }
  4848. public function lintSource($source)
  4849. {
  4850. return $this->sublinter->lintSource($source);
  4851. }
  4852. }
  4853. <?php
  4854. namespace PhpCsFixer\Linter;
  4855. final class TokenizerLintingResult implements LintingResultInterface
  4856. {
  4857. private $error;
  4858. public function __construct(\ParseError $error = null)
  4859. {
  4860. $this->error = $error;
  4861. }
  4862. public function check()
  4863. {
  4864. if (null !== $this->error) {
  4865. throw new LintingException(
  4866. sprintf('PHP Parse error: %s on line %d.', $this->error->getMessage(), $this->error->getLine()),
  4867. $this->error->getCode(),
  4868. $this->error
  4869. );
  4870. }
  4871. }
  4872. }
  4873. <?php
  4874. namespace PhpCsFixer\Linter;
  4875. final class CachingLinter implements LinterInterface
  4876. {
  4877. private $sublinter;
  4878. private $cache = [];
  4879. public function __construct(LinterInterface $linter)
  4880. {
  4881. $this->sublinter = $linter;
  4882. }
  4883. public function isAsync()
  4884. {
  4885. return $this->sublinter->isAsync();
  4886. }
  4887. public function lintFile($path)
  4888. {
  4889. $checksum = crc32(file_get_contents($path));
  4890. if (!isset($this->cache[$checksum])) {
  4891. $this->cache[$checksum] = $this->sublinter->lintFile($path);
  4892. }
  4893. return $this->cache[$checksum];
  4894. }
  4895. public function lintSource($source)
  4896. {
  4897. $checksum = crc32($source);
  4898. if (!isset($this->cache[$checksum])) {
  4899. $this->cache[$checksum] = $this->sublinter->lintSource($source);
  4900. }
  4901. return $this->cache[$checksum];
  4902. }
  4903. }
  4904. <?php
  4905. namespace PhpCsFixer\Linter;
  4906. interface LinterInterface
  4907. {
  4908. public function isAsync();
  4909. public function lintFile($path);
  4910. public function lintSource($source);
  4911. }
  4912. <?php
  4913. namespace PhpCsFixer;
  4914. use PhpCsFixer\Tokenizer\Tokens;
  4915. abstract class AbstractNoUselessElseFixer extends AbstractFixer
  4916. {
  4917. public function getPriority()
  4918. {
  4919. return 25;
  4920. }
  4921. protected function isSuperfluousElse(Tokens $tokens, $index)
  4922. {
  4923. $previousBlockStart = $index;
  4924. do {
  4925. list($previousBlockStart, $previousBlockEnd) = $this->getPreviousBlock($tokens, $previousBlockStart);
  4926. $previous = $previousBlockEnd;
  4927. if ($tokens[$previous]->equals('}')) {
  4928. $previous = $tokens->getPrevMeaningfulToken($previous);
  4929. }
  4930. if (
  4931. !$tokens[$previous]->equals(';') ||
  4932. $tokens[$tokens->getPrevMeaningfulToken($previous)]->equals('{')
  4933. ) {
  4934. return false;
  4935. }
  4936. $candidateIndex = $tokens->getPrevTokenOfKind(
  4937. $previous,
  4938. [
  4939. ';',
  4940. [T_BREAK],
  4941. [T_CLOSE_TAG],
  4942. [T_CONTINUE],
  4943. [T_EXIT],
  4944. [T_GOTO],
  4945. [T_IF],
  4946. [T_RETURN],
  4947. [T_THROW],
  4948. ]
  4949. );
  4950. if (
  4951. null === $candidateIndex
  4952. || $tokens[$candidateIndex]->equalsAny([';', [T_CLOSE_TAG], [T_IF]])
  4953. || $this->isInConditional($tokens, $candidateIndex, $previousBlockStart)
  4954. || $this->isInConditionWithoutBraces($tokens, $candidateIndex, $previousBlockStart)
  4955. ) {
  4956. return false;
  4957. }
  4958. } while (!$tokens[$previousBlockStart]->isGivenKind(T_IF));
  4959. return true;
  4960. }
  4961. private function getPreviousBlock(Tokens $tokens, $index)
  4962. {
  4963. $close = $previous = $tokens->getPrevMeaningfulToken($index);
  4964. if ($tokens[$close]->equals('}')) {
  4965. $previous = $tokens->findBlockStart(Tokens::BLOCK_TYPE_CURLY_BRACE, $close);
  4966. }
  4967. $open = $tokens->getPrevTokenOfKind($previous, [[T_IF], [T_ELSE], [T_ELSEIF]]);
  4968. if ($tokens[$open]->isGivenKind(T_IF)) {
  4969. $elseCandidate = $tokens->getPrevMeaningfulToken($open);
  4970. if ($tokens[$elseCandidate]->isGivenKind(T_ELSE)) {
  4971. $open = $elseCandidate;
  4972. }
  4973. }
  4974. return [$open, $close];
  4975. }
  4976. private function isInConditional(Tokens $tokens, $index, $lowerLimitIndex)
  4977. {
  4978. $candidateIndex = $tokens->getPrevTokenOfKind($index, [')', ';', ':']);
  4979. if ($tokens[$candidateIndex]->equals(':')) {
  4980. return true;
  4981. }
  4982. if (!$tokens[$candidateIndex]->equals(')')) {
  4983. return false;
  4984. }
  4985. $open = $tokens->findBlockStart(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $candidateIndex);
  4986. return $tokens->getPrevMeaningfulToken($open) > $lowerLimitIndex;
  4987. }
  4988. private function isInConditionWithoutBraces(Tokens $tokens, $index, $lowerLimitIndex)
  4989. {
  4990. do {
  4991. if ($tokens[$index]->isComment() || $tokens[$index]->isWhitespace()) {
  4992. $index = $tokens->getPrevMeaningfulToken($index);
  4993. }
  4994. $token = $tokens[$index];
  4995. if ($token->isGivenKind([T_IF, T_ELSEIF, T_ELSE])) {
  4996. return true;
  4997. }
  4998. if ($token->equals(';')) {
  4999. return false;
  5000. }
  5001. if ($token->equals('{')) {
  5002. $index = $tokens->getPrevMeaningfulToken($index);
  5003. if ($tokens[$index]->isGivenKind(T_DO)) {
  5004. --$index;
  5005. continue;
  5006. }
  5007. if (!$tokens[$index]->equals(')')) {
  5008. return false;
  5009. }
  5010. $index = $tokens->findBlockStart(
  5011. Tokens::BLOCK_TYPE_PARENTHESIS_BRACE,
  5012. $index
  5013. );
  5014. $index = $tokens->getPrevMeaningfulToken($index);
  5015. if ($tokens[$index]->isGivenKind([T_IF, T_ELSEIF])) {
  5016. return false;
  5017. }
  5018. } elseif ($token->equals(')')) {
  5019. $type = Tokens::detectBlockType($token);
  5020. $index = $tokens->findBlockStart(
  5021. $type['type'],
  5022. $index
  5023. );
  5024. $index = $tokens->getPrevMeaningfulToken($index);
  5025. } else {
  5026. --$index;
  5027. }
  5028. } while ($index > $lowerLimitIndex);
  5029. return false;
  5030. }
  5031. }
  5032. <?php
  5033. namespace PhpCsFixer\DocBlock;
  5034. use PhpCsFixer\Preg;
  5035. class DocBlock
  5036. {
  5037. private $lines = [];
  5038. private $annotations;
  5039. public function __construct($content)
  5040. {
  5041. foreach (Preg::split('/([^\n\r]+\R*)/', $content, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE) as $line) {
  5042. $this->lines[] = new Line($line);
  5043. }
  5044. }
  5045. public function __toString()
  5046. {
  5047. return $this->getContent();
  5048. }
  5049. public function getLines()
  5050. {
  5051. return $this->lines;
  5052. }
  5053. public function getLine($pos)
  5054. {
  5055. return isset($this->lines[$pos]) ? $this->lines[$pos] : null;
  5056. }
  5057. public function getAnnotations()
  5058. {
  5059. if (null !== $this->annotations) {
  5060. return $this->annotations;
  5061. }
  5062. $this->annotations = [];
  5063. $total = \count($this->lines);
  5064. for ($index = 0; $index < $total; ++$index) {
  5065. if ($this->lines[$index]->containsATag()) {
  5066. $lines = \array_slice($this->lines, $index, $this->findAnnotationLength($index), true);
  5067. $annotation = new Annotation($lines);
  5068. $index = $annotation->getEnd();
  5069. $this->annotations[] = $annotation;
  5070. }
  5071. }
  5072. return $this->annotations;
  5073. }
  5074. public function isMultiLine()
  5075. {
  5076. return 1 !== \count($this->lines);
  5077. }
  5078. public function makeMultiLine($indent, $lineEnd)
  5079. {
  5080. if ($this->isMultiLine()) {
  5081. return;
  5082. }
  5083. $lineContent = $this->getSingleLineDocBlockEntry($this->lines[0]);
  5084. if ('' === $lineContent) {
  5085. $this->lines = [
  5086. new Line('/**'.$lineEnd),
  5087. new Line($indent.' *'.$lineEnd),
  5088. new Line($indent.' */'),
  5089. ];
  5090. return;
  5091. }
  5092. $this->lines = [
  5093. new Line('/**'.$lineEnd),
  5094. new Line($indent.' * '.$lineContent.$lineEnd),
  5095. new Line($indent.' */'),
  5096. ];
  5097. }
  5098. public function makeSingleLine()
  5099. {
  5100. if (!$this->isMultiLine()) {
  5101. return;
  5102. }
  5103. $usefulLines = array_filter(
  5104. $this->lines,
  5105. static function (Line $line) {
  5106. return $line->containsUsefulContent();
  5107. }
  5108. );
  5109. if (1 < \count($usefulLines)) {
  5110. return;
  5111. }
  5112. $lineContent = '';
  5113. if (\count($usefulLines)) {
  5114. $lineContent = $this->getSingleLineDocBlockEntry(array_shift($usefulLines));
  5115. }
  5116. $this->lines = [new Line('/** '.$lineContent.' */')];
  5117. }
  5118. public function getAnnotation($pos)
  5119. {
  5120. $annotations = $this->getAnnotations();
  5121. return isset($annotations[$pos]) ? $annotations[$pos] : null;
  5122. }
  5123. public function getAnnotationsOfType($types)
  5124. {
  5125. $annotations = [];
  5126. $types = (array) $types;
  5127. foreach ($this->getAnnotations() as $annotation) {
  5128. $tag = $annotation->getTag()->getName();
  5129. foreach ($types as $type) {
  5130. if ($type === $tag) {
  5131. $annotations[] = $annotation;
  5132. }
  5133. }
  5134. }
  5135. return $annotations;
  5136. }
  5137. public function getContent()
  5138. {
  5139. return implode('', $this->lines);
  5140. }
  5141. private function findAnnotationLength($start)
  5142. {
  5143. $index = $start;
  5144. while ($line = $this->getLine(++$index)) {
  5145. if ($line->containsATag()) {
  5146. break;
  5147. }
  5148. if (!$line->containsUsefulContent()) {
  5149. $next = $this->getLine($index + 1);
  5150. if (null === $next || !$next->containsUsefulContent() || $next->containsATag()) {
  5151. break;
  5152. }
  5153. }
  5154. }
  5155. return $index - $start;
  5156. }
  5157. private function getSingleLineDocBlockEntry(Line $line)
  5158. {
  5159. $lineString = $line->getContent();
  5160. if (0 === \strlen($lineString)) {
  5161. return $lineString;
  5162. }
  5163. $lineString = str_replace('*/', '', $lineString);
  5164. $lineString = trim($lineString);
  5165. if ('/**' === substr($lineString, 0, 3)) {
  5166. $lineString = substr($lineString, 3);
  5167. } elseif ('*' === substr($lineString, 0, 1)) {
  5168. $lineString = substr($lineString, 1);
  5169. }
  5170. return trim($lineString);
  5171. }
  5172. }
  5173. <?php
  5174. namespace PhpCsFixer\DocBlock;
  5175. class TagComparator
  5176. {
  5177. private static $groups = [
  5178. ['deprecated', 'link', 'see', 'since'],
  5179. ['author', 'copyright', 'license'],
  5180. ['category', 'package', 'subpackage'],
  5181. ['property', 'property-read', 'property-write'],
  5182. ];
  5183. public static function shouldBeTogether(Tag $first, Tag $second)
  5184. {
  5185. $firstName = $first->getName();
  5186. $secondName = $second->getName();
  5187. if ($firstName === $secondName) {
  5188. return true;
  5189. }
  5190. foreach (self::$groups as $group) {
  5191. if (\in_array($firstName, $group, true) && \in_array($secondName, $group, true)) {
  5192. return true;
  5193. }
  5194. }
  5195. return false;
  5196. }
  5197. }
  5198. <?php
  5199. namespace PhpCsFixer\DocBlock;
  5200. use PhpCsFixer\Preg;
  5201. class Line
  5202. {
  5203. private $content;
  5204. public function __construct($content)
  5205. {
  5206. $this->content = $content;
  5207. }
  5208. public function __toString()
  5209. {
  5210. return $this->content;
  5211. }
  5212. public function getContent()
  5213. {
  5214. return $this->content;
  5215. }
  5216. public function containsUsefulContent()
  5217. {
  5218. return 0 !== Preg::match('/\\*\s*\S+/', $this->content) && '' !== trim(str_replace(['/', '*'], ' ', $this->content));
  5219. }
  5220. public function containsATag()
  5221. {
  5222. return 0 !== Preg::match('/\\*\s*@/', $this->content);
  5223. }
  5224. public function isTheStart()
  5225. {
  5226. return false !== strpos($this->content, '/**');
  5227. }
  5228. public function isTheEnd()
  5229. {
  5230. return false !== strpos($this->content, '*/');
  5231. }
  5232. public function setContent($content)
  5233. {
  5234. $this->content = $content;
  5235. }
  5236. public function remove()
  5237. {
  5238. $this->content = '';
  5239. }
  5240. public function addBlank()
  5241. {
  5242. $matched = Preg::match('/^(\h*\*)[^\r\n]*(\r?\n)$/', $this->content, $matches);
  5243. if (1 !== $matched) {
  5244. return;
  5245. }
  5246. $this->content .= $matches[1].$matches[2];
  5247. }
  5248. }
  5249. <?php
  5250. namespace PhpCsFixer\DocBlock;
  5251. use PhpCsFixer\Preg;
  5252. class Tag
  5253. {
  5254. private static $tags = [
  5255. 'api', 'author', 'category', 'copyright', 'deprecated', 'example',
  5256. 'global', 'internal', 'license', 'link', 'method', 'package', 'param',
  5257. 'property', 'property-read', 'property-write', 'return', 'see',
  5258. 'since', 'subpackage', 'throws', 'todo', 'uses', 'var', 'version',
  5259. ];
  5260. private $line;
  5261. private $name;
  5262. public function __construct(Line $line)
  5263. {
  5264. $this->line = $line;
  5265. }
  5266. public function getName()
  5267. {
  5268. if (null === $this->name) {
  5269. Preg::matchAll('/@[a-zA-Z0-9_-]+(?=\s|$)/', $this->line->getContent(), $matches);
  5270. if (isset($matches[0][0])) {
  5271. $this->name = ltrim($matches[0][0], '@');
  5272. } else {
  5273. $this->name = 'other';
  5274. }
  5275. }
  5276. return $this->name;
  5277. }
  5278. public function setName($name)
  5279. {
  5280. $current = $this->getName();
  5281. if ('other' === $current) {
  5282. throw new \RuntimeException('Cannot set name on unknown tag.');
  5283. }
  5284. $this->line->setContent(Preg::replace("/@{$current}/", "@{$name}", $this->line->getContent(), 1));
  5285. $this->name = $name;
  5286. }
  5287. public function valid()
  5288. {
  5289. return \in_array($this->getName(), self::$tags, true);
  5290. }
  5291. }
  5292. <?php
  5293. namespace PhpCsFixer\DocBlock;
  5294. final class ShortDescription
  5295. {
  5296. private $doc;
  5297. public function __construct(DocBlock $doc)
  5298. {
  5299. $this->doc = $doc;
  5300. }
  5301. public function getEnd()
  5302. {
  5303. $reachedContent = false;
  5304. foreach ($this->doc->getLines() as $index => $line) {
  5305. if ($reachedContent && ($line->containsATag() || !$line->containsUsefulContent())) {
  5306. return $index - 1;
  5307. }
  5308. if ($line->containsATag()) {
  5309. return null;
  5310. }
  5311. if ($line->containsUsefulContent()) {
  5312. $reachedContent = true;
  5313. }
  5314. }
  5315. return null;
  5316. }
  5317. }
  5318. <?php
  5319. namespace PhpCsFixer\DocBlock;
  5320. use PhpCsFixer\Preg;
  5321. /**
  5322. @gmail
  5323. */
  5324. class Annotation
  5325. {
  5326. const REGEX_TYPES = '
  5327. # <simple> is any non-array, non-generic, non-alternated type, eg `int` or `\Foo`
  5328. # <array> is array of <simple>, eg `int[]` or `\Foo[]`
  5329. # <generic> is generic collection type, like `array<string, int>`, `Collection<Item>` and more complex like `Collection<int, \null|SubCollection<string>>`
  5330. # <type> is <simple>, <array> or <generic> type, like `int`, `bool[]` or `Collection<ItemKey, ItemVal>`
  5331. # <types> is one or more types alternated via `|`, like `int|bool[]|Collection<ItemKey, ItemVal>`
  5332. (?<types>
  5333. (?<type>
  5334. (?<array>
  5335. (?&simple)(\[\])*
  5336. )
  5337. |
  5338. (?<simple>
  5339. [@$?]?[\\\\\w]+
  5340. )
  5341. |
  5342. (?<generic>
  5343. (?&simple)
  5344. <
  5345. (?:(?&types),\s*)?(?:(?&types)|(?&generic))
  5346. >
  5347. )
  5348. )
  5349. (?:
  5350. \|
  5351. (?:(?&simple)|(?&array)|(?&generic))
  5352. )*
  5353. )
  5354. ';
  5355. private static $tags = [
  5356. 'method',
  5357. 'param',
  5358. 'property',
  5359. 'property-read',
  5360. 'property-write',
  5361. 'return',
  5362. 'throws',
  5363. 'type',
  5364. 'var',
  5365. ];
  5366. private $lines;
  5367. private $start;
  5368. private $end;
  5369. private $tag;
  5370. private $typesContent;
  5371. private $types;
  5372. public function __construct(array $lines)
  5373. {
  5374. $this->lines = array_values($lines);
  5375. $keys = array_keys($lines);
  5376. $this->start = $keys[0];
  5377. $this->end = end($keys);
  5378. }
  5379. public function __toString()
  5380. {
  5381. return $this->getContent();
  5382. }
  5383. public static function getTagsWithTypes()
  5384. {
  5385. return self::$tags;
  5386. }
  5387. public function getStart()
  5388. {
  5389. return $this->start;
  5390. }
  5391. public function getEnd()
  5392. {
  5393. return $this->end;
  5394. }
  5395. public function getTag()
  5396. {
  5397. if (null === $this->tag) {
  5398. $this->tag = new Tag($this->lines[0]);
  5399. }
  5400. return $this->tag;
  5401. }
  5402. public function getTypes()
  5403. {
  5404. if (null === $this->types) {
  5405. $this->types = [];
  5406. $content = $this->getTypesContent();
  5407. while ('' !== $content && false !== $content) {
  5408. Preg::match(
  5409. '{^'.self::REGEX_TYPES.'$}x',
  5410. $content,
  5411. $matches
  5412. );
  5413. $this->types[] = $matches['type'];
  5414. $content = substr($content, \strlen($matches['type']) + 1);
  5415. }
  5416. }
  5417. return $this->types;
  5418. }
  5419. public function setTypes(array $types)
  5420. {
  5421. $pattern = '/'.preg_quote($this->getTypesContent(), '/').'/';
  5422. $this->lines[0]->setContent(Preg::replace($pattern, implode('|', $types), $this->lines[0]->getContent(), 1));
  5423. $this->clearCache();
  5424. }
  5425. public function getNormalizedTypes()
  5426. {
  5427. $normalized = array_map(static function ($type) {
  5428. return strtolower($type);
  5429. }, $this->getTypes());
  5430. sort($normalized);
  5431. return $normalized;
  5432. }
  5433. public function remove()
  5434. {
  5435. foreach ($this->lines as $line) {
  5436. if ($line->isTheStart() && $line->isTheEnd()) {
  5437. $line->remove();
  5438. } elseif ($line->isTheStart()) {
  5439. $content = Preg::replace('#(\s*/\*\*).*#', '$1', $line->getContent());
  5440. $line->setContent($content);
  5441. } elseif ($line->isTheEnd()) {
  5442. $content = Preg::replace('#(\s*)\S.*(\*/.*)#', '$1$2', $line->getContent());
  5443. $line->setContent($content);
  5444. } else {
  5445. $line->remove();
  5446. }
  5447. }
  5448. $this->clearCache();
  5449. }
  5450. public function getContent()
  5451. {
  5452. return implode('', $this->lines);
  5453. }
  5454. public function supportTypes()
  5455. {
  5456. return \in_array($this->getTag()->getName(), self::$tags, true);
  5457. }
  5458. private function getTypesContent()
  5459. {
  5460. if (null === $this->typesContent) {
  5461. $name = $this->getTag()->getName();
  5462. if (!$this->supportTypes()) {
  5463. throw new \RuntimeException('This tag does not support types.');
  5464. }
  5465. $matchingResult = Preg::match(
  5466. '{^(?:\s*\*|/\*\*)\s*@'.$name.'\s+'.self::REGEX_TYPES.'(?:[*\h\v].*)?$}sx',
  5467. $this->lines[0]->getContent(),
  5468. $matches
  5469. );
  5470. $this->typesContent = 1 === $matchingResult
  5471. ? $matches['types']
  5472. : '';
  5473. }
  5474. return $this->typesContent;
  5475. }
  5476. private function clearCache()
  5477. {
  5478. $this->types = null;
  5479. $this->typesContent = null;
  5480. }
  5481. }
  5482. <?php
  5483. namespace PhpCsFixer;
  5484. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  5485. use PhpCsFixer\Tokenizer\Token;
  5486. use PhpCsFixer\Tokenizer\Tokens;
  5487. abstract class AbstractLinesBeforeNamespaceFixer extends AbstractFixer implements WhitespacesAwareFixerInterface
  5488. {
  5489. protected function fixLinesBeforeNamespace(Tokens $tokens, $index, $expectedMin, $expectedMax)
  5490. {
  5491. $openingTokenIndex = null;
  5492. $precedingNewlines = 0;
  5493. $newlineInOpening = false;
  5494. $openingToken = null;
  5495. for ($i = 1; $i <= 2; ++$i) {
  5496. if (isset($tokens[$index - $i])) {
  5497. $token = $tokens[$index - $i];
  5498. if ($token->isGivenKind(T_OPEN_TAG)) {
  5499. $openingToken = $token;
  5500. $openingTokenIndex = $index - $i;
  5501. $newlineInOpening = false !== strpos($token->getContent(), "\n");
  5502. if ($newlineInOpening) {
  5503. ++$precedingNewlines;
  5504. }
  5505. break;
  5506. }
  5507. if (false === $token->isGivenKind(T_WHITESPACE)) {
  5508. break;
  5509. }
  5510. $precedingNewlines += substr_count($token->getContent(), "\n");
  5511. }
  5512. }
  5513. if ($precedingNewlines >= $expectedMin && $precedingNewlines <= $expectedMax) {
  5514. return;
  5515. }
  5516. $previousIndex = $index - 1;
  5517. $previous = $tokens[$previousIndex];
  5518. if (0 === $expectedMax) {
  5519. if ($previous->isWhitespace()) {
  5520. $tokens->clearAt($previousIndex);
  5521. }
  5522. if ($newlineInOpening) {
  5523. $tokens[$openingTokenIndex] = new Token([T_OPEN_TAG, rtrim($openingToken->getContent()).' ']);
  5524. }
  5525. return;
  5526. }
  5527. $lineEnding = $this->whitespacesConfig->getLineEnding();
  5528. $newlinesForWhitespaceToken = $expectedMax;
  5529. if (null !== $openingToken) {
  5530. $content = rtrim($openingToken->getContent());
  5531. $newContent = $content.$lineEnding;
  5532. $tokens[$openingTokenIndex] = new Token([T_OPEN_TAG, $newContent]);
  5533. --$newlinesForWhitespaceToken;
  5534. }
  5535. if (0 === $newlinesForWhitespaceToken) {
  5536. if ($previous->isWhitespace()) {
  5537. $tokens->clearAt($previousIndex);
  5538. }
  5539. return;
  5540. }
  5541. if ($previous->isWhitespace()) {
  5542. $tokens[$previousIndex] = new Token([T_WHITESPACE, str_repeat($lineEnding, $newlinesForWhitespaceToken).substr($previous->getContent(), strrpos($previous->getContent(), "\n") + 1)]);
  5543. } else {
  5544. $tokens->insertAt($index, new Token([T_WHITESPACE, str_repeat($lineEnding, $newlinesForWhitespaceToken)]));
  5545. }
  5546. }
  5547. }
  5548. <?php
  5549. namespace PhpCsFixer\FixerConfiguration;
  5550. final class FixerConfigurationResolverRootless implements FixerConfigurationResolverInterface
  5551. {
  5552. private $resolver;
  5553. private $root;
  5554. private $fixerName;
  5555. public function __construct($root, $options, $fixerName)
  5556. {
  5557. $this->resolver = new FixerConfigurationResolver($options);
  5558. $this->fixerName = $fixerName;
  5559. $names = array_map(
  5560. static function (FixerOptionInterface $option) {
  5561. return $option->getName();
  5562. },
  5563. $this->resolver->getOptions()
  5564. );
  5565. if (!\in_array($root, $names, true)) {
  5566. throw new \LogicException(sprintf('The "%s" option is not defined.', $root));
  5567. }
  5568. $this->root = $root;
  5569. }
  5570. public function getOptions()
  5571. {
  5572. return $this->resolver->getOptions();
  5573. }
  5574. public function resolve(array $options)
  5575. {
  5576. if (!empty($options) && !\array_key_exists($this->root, $options)) {
  5577. $names = array_map(
  5578. static function (FixerOptionInterface $option) {
  5579. return $option->getName();
  5580. },
  5581. $this->resolver->getOptions()
  5582. );
  5583. $passedNames = array_keys($options);
  5584. if (!empty(array_diff($passedNames, $names))) {
  5585. $message = "Passing \"{$this->root}\" at the root of the configuration for rule \"{$this->fixerName}\" is deprecated and will not be supported in 3.0, use \"{$this->root}\" => array(...) option instead.";
  5586. if (getenv('PHP_CS_FIXER_FUTURE_MODE')) {
  5587. throw new \RuntimeException("{$message}. This check was performed as `PHP_CS_FIXER_FUTURE_MODE` env var is set.");
  5588. }
  5589. @trigger_error($message, E_USER_DEPRECATED);
  5590. $options = [$this->root => $options];
  5591. }
  5592. }
  5593. return $this->resolver->resolve($options);
  5594. }
  5595. }
  5596. <?php
  5597. namespace PhpCsFixer\FixerConfiguration;
  5598. final class DeprecatedFixerOption implements DeprecatedFixerOptionInterface
  5599. {
  5600. private $option;
  5601. private $deprecationMessage;
  5602. public function __construct(FixerOptionInterface $option, $deprecationMessage)
  5603. {
  5604. $this->option = $option;
  5605. $this->deprecationMessage = $deprecationMessage;
  5606. }
  5607. public function getName()
  5608. {
  5609. return $this->option->getName();
  5610. }
  5611. public function getDescription()
  5612. {
  5613. return $this->option->getDescription();
  5614. }
  5615. public function hasDefault()
  5616. {
  5617. return $this->option->hasDefault();
  5618. }
  5619. public function getDefault()
  5620. {
  5621. return $this->option->getDefault();
  5622. }
  5623. public function getAllowedTypes()
  5624. {
  5625. return $this->option->getAllowedTypes();
  5626. }
  5627. public function getAllowedValues()
  5628. {
  5629. return $this->option->getAllowedValues();
  5630. }
  5631. public function getNormalizer()
  5632. {
  5633. return $this->option->getNormalizer();
  5634. }
  5635. public function getDeprecationMessage()
  5636. {
  5637. return $this->deprecationMessage;
  5638. }
  5639. }
  5640. <?php
  5641. namespace PhpCsFixer\FixerConfiguration;
  5642. final class FixerOption implements FixerOptionInterface
  5643. {
  5644. private $name;
  5645. private $description;
  5646. private $default;
  5647. private $isRequired;
  5648. private $allowedTypes;
  5649. private $allowedValues;
  5650. private $normalizer;
  5651. public function __construct(
  5652. $name,
  5653. $description,
  5654. $isRequired = true,
  5655. $default = null,
  5656. array $allowedTypes = null,
  5657. array $allowedValues = null,
  5658. \Closure $normalizer = null
  5659. ) {
  5660. if ($isRequired && null !== $default) {
  5661. throw new \LogicException('Required options cannot have a default value.');
  5662. }
  5663. if (null !== $allowedValues) {
  5664. foreach ($allowedValues as &$allowedValue) {
  5665. if ($allowedValue instanceof \Closure) {
  5666. $allowedValue = $this->unbind($allowedValue);
  5667. }
  5668. }
  5669. }
  5670. $this->name = $name;
  5671. $this->description = $description;
  5672. $this->isRequired = $isRequired;
  5673. $this->default = $default;
  5674. $this->allowedTypes = $allowedTypes;
  5675. $this->allowedValues = $allowedValues;
  5676. if (null !== $normalizer) {
  5677. $this->normalizer = $this->unbind($normalizer);
  5678. }
  5679. }
  5680. public function getName()
  5681. {
  5682. return $this->name;
  5683. }
  5684. public function getDescription()
  5685. {
  5686. return $this->description;
  5687. }
  5688. public function hasDefault()
  5689. {
  5690. return !$this->isRequired;
  5691. }
  5692. public function getDefault()
  5693. {
  5694. if (!$this->hasDefault()) {
  5695. throw new \LogicException('No default value defined.');
  5696. }
  5697. return $this->default;
  5698. }
  5699. public function getAllowedTypes()
  5700. {
  5701. return $this->allowedTypes;
  5702. }
  5703. public function getAllowedValues()
  5704. {
  5705. return $this->allowedValues;
  5706. }
  5707. public function getNormalizer()
  5708. {
  5709. return $this->normalizer;
  5710. }
  5711. private function unbind(\Closure $closure)
  5712. {
  5713. return $closure->bindTo(null);
  5714. }
  5715. }
  5716. <?php
  5717. namespace PhpCsFixer\FixerConfiguration;
  5718. final class FixerOptionBuilder
  5719. {
  5720. private $name;
  5721. private $description;
  5722. private $default;
  5723. private $isRequired = true;
  5724. private $allowedTypes;
  5725. private $allowedValues;
  5726. private $normalizer;
  5727. private $deprecationMessage;
  5728. public function __construct($name, $description)
  5729. {
  5730. $this->name = $name;
  5731. $this->description = $description;
  5732. }
  5733. public function setDefault($default)
  5734. {
  5735. $this->default = $default;
  5736. $this->isRequired = false;
  5737. return $this;
  5738. }
  5739. public function setAllowedTypes(array $allowedTypes)
  5740. {
  5741. $this->allowedTypes = $allowedTypes;
  5742. return $this;
  5743. }
  5744. public function setAllowedValues(array $allowedValues)
  5745. {
  5746. $this->allowedValues = $allowedValues;
  5747. return $this;
  5748. }
  5749. public function setNormalizer(\Closure $normalizer)
  5750. {
  5751. $this->normalizer = $normalizer;
  5752. return $this;
  5753. }
  5754. public function setDeprecationMessage($deprecationMessage)
  5755. {
  5756. $this->deprecationMessage = $deprecationMessage;
  5757. return $this;
  5758. }
  5759. public function getOption()
  5760. {
  5761. $option = new FixerOption(
  5762. $this->name,
  5763. $this->description,
  5764. $this->isRequired,
  5765. $this->default,
  5766. $this->allowedTypes,
  5767. $this->allowedValues,
  5768. $this->normalizer
  5769. );
  5770. if (null !== $this->deprecationMessage) {
  5771. $option = new DeprecatedFixerOption($option, $this->deprecationMessage);
  5772. }
  5773. return $option;
  5774. }
  5775. }
  5776. <?php
  5777. namespace PhpCsFixer\FixerConfiguration;
  5778. interface FixerConfigurationResolverInterface
  5779. {
  5780. public function getOptions();
  5781. public function resolve(array $configuration);
  5782. }
  5783. <?php
  5784. namespace PhpCsFixer\FixerConfiguration;
  5785. interface FixerOptionInterface
  5786. {
  5787. public function getName();
  5788. public function getDescription();
  5789. public function hasDefault();
  5790. public function getDefault();
  5791. public function getAllowedTypes();
  5792. public function getAllowedValues();
  5793. public function getNormalizer();
  5794. }
  5795. <?php
  5796. namespace PhpCsFixer\FixerConfiguration;
  5797. use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException;
  5798. use Symfony\Component\OptionsResolver\OptionsResolver;
  5799. final class FixerConfigurationResolver implements FixerConfigurationResolverInterface
  5800. {
  5801. private $options = [];
  5802. private $registeredNames = [];
  5803. public function __construct($options)
  5804. {
  5805. foreach ($options as $option) {
  5806. $this->addOption($option);
  5807. }
  5808. if (empty($this->registeredNames)) {
  5809. throw new \LogicException('Options cannot be empty.');
  5810. }
  5811. }
  5812. public function getOptions()
  5813. {
  5814. return $this->options;
  5815. }
  5816. public function resolve(array $options)
  5817. {
  5818. $resolver = new OptionsResolver();
  5819. foreach ($this->options as $option) {
  5820. $name = $option->getName();
  5821. if ($option instanceof AliasedFixerOption) {
  5822. $alias = $option->getAlias();
  5823. if (\array_key_exists($alias, $options)) {
  5824. if (\array_key_exists($name, $options)) {
  5825. throw new InvalidOptionsException(sprintf('Aliased option %s/%s is passed multiple times.', $name, $alias));
  5826. }
  5827. @trigger_error(sprintf('Option "%s" is deprecated, use "%s" instead.', $alias, $name), E_USER_DEPRECATED);
  5828. $options[$name] = $options[$alias];
  5829. unset($options[$alias]);
  5830. }
  5831. }
  5832. if ($option->hasDefault()) {
  5833. $resolver->setDefault($name, $option->getDefault());
  5834. } else {
  5835. $resolver->setRequired($name);
  5836. }
  5837. $allowedValues = $option->getAllowedValues();
  5838. if (null !== $allowedValues) {
  5839. foreach ($allowedValues as &$allowedValue) {
  5840. if (\is_object($allowedValue) && \is_callable($allowedValue)) {
  5841. $allowedValue = static function ($values) use ($allowedValue) {
  5842. return $allowedValue($values);
  5843. };
  5844. }
  5845. }
  5846. $resolver->setAllowedValues($name, $allowedValues);
  5847. }
  5848. $allowedTypes = $option->getAllowedTypes();
  5849. if (null !== $allowedTypes) {
  5850. $resolver->setAllowedTypes($name, $allowedTypes);
  5851. }
  5852. $normalizer = $option->getNormalizer();
  5853. if (null !== $normalizer) {
  5854. $resolver->setNormalizer($name, $normalizer);
  5855. }
  5856. }
  5857. return $resolver->resolve($options);
  5858. }
  5859. private function addOption(FixerOptionInterface $option)
  5860. {
  5861. $name = $option->getName();
  5862. if (\in_array($name, $this->registeredNames, true)) {
  5863. throw new \LogicException(sprintf('The "%s" option is defined multiple times.', $name));
  5864. }
  5865. $this->options[] = $option;
  5866. $this->registeredNames[] = $name;
  5867. return $this;
  5868. }
  5869. }
  5870. <?php
  5871. namespace PhpCsFixer\FixerConfiguration;
  5872. final class AliasedFixerOptionBuilder
  5873. {
  5874. private $optionBuilder;
  5875. private $alias;
  5876. public function __construct(FixerOptionBuilder $optionBuilder, $alias)
  5877. {
  5878. $this->optionBuilder = $optionBuilder;
  5879. $this->alias = $alias;
  5880. }
  5881. public function setDefault($default)
  5882. {
  5883. $this->optionBuilder->setDefault($default);
  5884. return $this;
  5885. }
  5886. public function setAllowedTypes(array $allowedTypes)
  5887. {
  5888. $this->optionBuilder->setAllowedTypes($allowedTypes);
  5889. return $this;
  5890. }
  5891. public function setAllowedValues(array $allowedValues)
  5892. {
  5893. $this->optionBuilder->setAllowedValues($allowedValues);
  5894. return $this;
  5895. }
  5896. public function setNormalizer(\Closure $normalizer)
  5897. {
  5898. $this->optionBuilder->setNormalizer($normalizer);
  5899. return $this;
  5900. }
  5901. public function getOption()
  5902. {
  5903. return new AliasedFixerOption(
  5904. $this->optionBuilder->getOption(),
  5905. $this->alias
  5906. );
  5907. }
  5908. }
  5909. <?php
  5910. namespace PhpCsFixer\FixerConfiguration;
  5911. final class AllowedValueSubset
  5912. {
  5913. private $allowedValues;
  5914. public function __construct(array $allowedValues)
  5915. {
  5916. $this->allowedValues = $allowedValues;
  5917. }
  5918. public function __invoke($values)
  5919. {
  5920. if (!\is_array($values)) {
  5921. return false;
  5922. }
  5923. foreach ($values as $value) {
  5924. if (!\in_array($value, $this->allowedValues, true)) {
  5925. return false;
  5926. }
  5927. }
  5928. return true;
  5929. }
  5930. public function getAllowedValues()
  5931. {
  5932. return $this->allowedValues;
  5933. }
  5934. }
  5935. <?php
  5936. namespace PhpCsFixer\FixerConfiguration;
  5937. interface DeprecatedFixerOptionInterface extends FixerOptionInterface
  5938. {
  5939. public function getDeprecationMessage();
  5940. }
  5941. <?php
  5942. namespace PhpCsFixer\FixerConfiguration;
  5943. use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException;
  5944. final class InvalidOptionsForEnvException extends InvalidOptionsException
  5945. {
  5946. }
  5947. <?php
  5948. namespace PhpCsFixer\FixerConfiguration;
  5949. final class AliasedFixerOption implements FixerOptionInterface
  5950. {
  5951. private $fixerOption;
  5952. private $alias;
  5953. public function __construct(FixerOptionInterface $fixerOption, $alias)
  5954. {
  5955. $this->fixerOption = $fixerOption;
  5956. $this->alias = $alias;
  5957. }
  5958. public function getAlias()
  5959. {
  5960. return $this->alias;
  5961. }
  5962. public function getName()
  5963. {
  5964. return $this->fixerOption->getName();
  5965. }
  5966. public function getDescription()
  5967. {
  5968. return $this->fixerOption->getDescription();
  5969. }
  5970. public function hasDefault()
  5971. {
  5972. return $this->fixerOption->hasDefault();
  5973. }
  5974. public function getDefault()
  5975. {
  5976. return $this->fixerOption->getDefault();
  5977. }
  5978. public function getAllowedTypes()
  5979. {
  5980. return $this->fixerOption->getAllowedTypes();
  5981. }
  5982. public function getAllowedValues()
  5983. {
  5984. return $this->fixerOption->getAllowedValues();
  5985. }
  5986. public function getNormalizer()
  5987. {
  5988. return $this->fixerOption->getNormalizer();
  5989. }
  5990. }
  5991. <?php
  5992. namespace PhpCsFixer;
  5993. use PhpCsFixer\Tokenizer\Token;
  5994. use PhpCsFixer\Tokenizer\Tokens;
  5995. /**
  5996. @gmail
  5997. @gotink
  5998. @alt
  5999. */
  6000. abstract class AbstractPsrAutoloadingFixer extends AbstractFixer
  6001. {
  6002. public function isCandidate(Tokens $tokens)
  6003. {
  6004. return $tokens->isAnyTokenKindsFound(Token::getClassyTokenKinds());
  6005. }
  6006. public function isRisky()
  6007. {
  6008. return true;
  6009. }
  6010. public function getPriority()
  6011. {
  6012. return -10;
  6013. }
  6014. public function supports(\SplFileInfo $file)
  6015. {
  6016. if ($file instanceof StdinFileInfo) {
  6017. return false;
  6018. }
  6019. $filenameParts = explode('.', $file->getBasename(), 2);
  6020. if (
  6021. (!isset($filenameParts[1]) || 'php' !== $filenameParts[1])
  6022. || 0 === Preg::match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/', $filenameParts[0])
  6023. ) {
  6024. return false;
  6025. }
  6026. try {
  6027. $tokens = Tokens::fromCode(sprintf('<?php class %s {}', $filenameParts[0]));
  6028. if ($tokens[3]->isKeyword() || $tokens[3]->isMagicConstant()) {
  6029. return false;
  6030. }
  6031. } catch (\ParseError $e) {
  6032. return false;
  6033. }
  6034. return !Preg::match('{[/\\\\](stub|fixture)s?[/\\\\]}i', $file->getRealPath());
  6035. }
  6036. }
  6037. <?php
  6038. namespace PhpCsFixer\Differ;
  6039. final class NullDiffer implements DifferInterface
  6040. {
  6041. public function diff($old, $new)
  6042. {
  6043. return '';
  6044. }
  6045. }
  6046. <?php
  6047. namespace PhpCsFixer\Differ;
  6048. use PhpCsFixer\Diff\v3_0\Differ;
  6049. use PhpCsFixer\Diff\v3_0\Output\StrictUnifiedDiffOutputBuilder;
  6050. final class UnifiedDiffer implements DifferInterface
  6051. {
  6052. private $differ;
  6053. public function __construct()
  6054. {
  6055. $this->differ = new Differ(new StrictUnifiedDiffOutputBuilder([
  6056. 'fromFile' => 'Original',
  6057. 'toFile' => 'New',
  6058. ]));
  6059. }
  6060. public function diff($old, $new)
  6061. {
  6062. return $this->differ->diff($old, $new);
  6063. }
  6064. }
  6065. <?php
  6066. namespace PhpCsFixer\Differ;
  6067. use PhpCsFixer\Diff\v3_0\Differ;
  6068. use PhpCsFixer\Diff\v3_0\Output\StrictUnifiedDiffOutputBuilder;
  6069. final class FullDiffer implements DifferInterface
  6070. {
  6071. private $differ;
  6072. public function __construct()
  6073. {
  6074. $this->differ = new Differ(new StrictUnifiedDiffOutputBuilder([
  6075. 'collapseRanges' => false,
  6076. 'commonLineThreshold' => 100,
  6077. 'contextLines' => 100,
  6078. 'fromFile' => 'Original',
  6079. 'toFile' => 'New',
  6080. ]));
  6081. }
  6082. public function diff($old, $new)
  6083. {
  6084. return $this->differ->diff($old, $new);
  6085. }
  6086. }
  6087. <?php
  6088. namespace PhpCsFixer\Differ;
  6089. use PhpCsFixer\Diff\v1_4\Differ;
  6090. final class SebastianBergmannDiffer implements DifferInterface
  6091. {
  6092. private $differ;
  6093. public function __construct()
  6094. {
  6095. $this->differ = new Differ();
  6096. }
  6097. public function diff($old, $new)
  6098. {
  6099. return $this->differ->diff($old, $new);
  6100. }
  6101. }
  6102. <?php
  6103. namespace PhpCsFixer\Differ;
  6104. use PhpCsFixer\Preg;
  6105. use Symfony\Component\Console\Formatter\OutputFormatter;
  6106. final class DiffConsoleFormatter
  6107. {
  6108. private $isDecoratedOutput;
  6109. private $template;
  6110. public function __construct($isDecoratedOutput, $template = '%s')
  6111. {
  6112. $this->isDecoratedOutput = $isDecoratedOutput;
  6113. $this->template = $template;
  6114. }
  6115. public function format($diff, $lineTemplate = '%s')
  6116. {
  6117. $isDecorated = $this->isDecoratedOutput;
  6118. $template = $isDecorated
  6119. ? $this->template
  6120. : Preg::replace('/<[^<>]+>/', '', $this->template)
  6121. ;
  6122. return sprintf(
  6123. $template,
  6124. implode(
  6125. PHP_EOL,
  6126. array_map(
  6127. static function ($line) use ($isDecorated, $lineTemplate) {
  6128. if ($isDecorated) {
  6129. $count = 0;
  6130. $line = Preg::replaceCallback(
  6131. [
  6132. '/^(\+.*)/',
  6133. '/^(\-.*)/',
  6134. '/^(@.*)/',
  6135. ],
  6136. static function ($matches) {
  6137. if ('+' === $matches[0][0]) {
  6138. $colour = 'green';
  6139. } elseif ('-' === $matches[0][0]) {
  6140. $colour = 'red';
  6141. } else {
  6142. $colour = 'cyan';
  6143. }
  6144. return sprintf('<fg=%s>%s</fg=%s>', $colour, OutputFormatter::escape($matches[0]), $colour);
  6145. },
  6146. $line,
  6147. 1,
  6148. $count
  6149. );
  6150. if (0 === $count) {
  6151. $line = OutputFormatter::escape($line);
  6152. }
  6153. }
  6154. return sprintf($lineTemplate, $line);
  6155. },
  6156. Preg::split('#\R#u', $diff)
  6157. )
  6158. )
  6159. );
  6160. }
  6161. }
  6162. <?php
  6163. namespace PhpCsFixer\Differ;
  6164. use PhpCsFixer\Diff\v1_4\Differ;
  6165. final class SebastianBergmannShortDiffer implements DifferInterface
  6166. {
  6167. private $differ;
  6168. public function __construct()
  6169. {
  6170. $this->differ = new Differ("--- Original\n+++ New\n", false);
  6171. }
  6172. public function diff($old, $new)
  6173. {
  6174. return $this->differ->diff($old, $new);
  6175. }
  6176. }
  6177. <?php
  6178. namespace PhpCsFixer\Differ;
  6179. interface DifferInterface
  6180. {
  6181. public function diff($old, $new);
  6182. }
  6183. <?php
  6184. namespace PhpCsFixer\Event;
  6185. use Symfony\Component\EventDispatcher\EventDispatcher;
  6186. use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
  6187. if (is_subclass_of(EventDispatcher::class, EventDispatcherInterface::class)) {
  6188. class Event extends \Symfony\Contracts\EventDispatcher\Event
  6189. {
  6190. }
  6191. } else {
  6192. class Event extends \Symfony\Component\EventDispatcher\Event
  6193. {
  6194. }
  6195. }
  6196. <?php
  6197. namespace PhpCsFixer;
  6198. interface ToolInfoInterface
  6199. {
  6200. public function getComposerInstallationDetails();
  6201. public function getComposerVersion();
  6202. public function getVersion();
  6203. public function isInstalledAsPhar();
  6204. public function isInstalledByComposer();
  6205. public function getPharDownloadUri($version);
  6206. }
  6207. <?php
  6208. namespace PhpCsFixer;
  6209. use PhpCsFixer\Fixer\FixerInterface;
  6210. /**
  6211. @gmail
  6212. */
  6213. interface ConfigInterface
  6214. {
  6215. public function getCacheFile();
  6216. public function getCustomFixers();
  6217. public function getFinder();
  6218. public function getFormat();
  6219. public function getHideProgress();
  6220. public function getIndent();
  6221. public function getLineEnding();
  6222. public function getName();
  6223. public function getPhpExecutable();
  6224. public function getRiskyAllowed();
  6225. public function getRules();
  6226. public function getUsingCache();
  6227. public function registerCustomFixers($fixers);
  6228. public function setCacheFile($cacheFile);
  6229. public function setFinder($finder);
  6230. public function setFormat($format);
  6231. public function setHideProgress($hideProgress);
  6232. public function setIndent($indent);
  6233. public function setLineEnding($lineEnding);
  6234. public function setPhpExecutable($phpExecutable);
  6235. public function setRiskyAllowed($isRiskyAllowed);
  6236. public function setRules(array $rules);
  6237. public function setUsingCache($usingCache);
  6238. }
  6239. <?php
  6240. namespace PhpCsFixer;
  6241. interface PharCheckerInterface
  6242. {
  6243. public function checkFileValidity($filename);
  6244. }
  6245. <?php
  6246. namespace PhpCsFixer;
  6247. use PhpCsFixer\Console\Application;
  6248. final class ToolInfo implements ToolInfoInterface
  6249. {
  6250. const COMPOSER_PACKAGE_NAME = 'friendsofphp/php-cs-fixer';
  6251. const COMPOSER_LEGACY_PACKAGE_NAME = 'fabpot/php-cs-fixer';
  6252. private $composerInstallationDetails;
  6253. private $isInstalledByComposer;
  6254. public function getComposerInstallationDetails()
  6255. {
  6256. if (!$this->isInstalledByComposer()) {
  6257. throw new \LogicException('Cannot get composer version for tool not installed by composer.');
  6258. }
  6259. if (null === $this->composerInstallationDetails) {
  6260. $composerInstalled = json_decode(file_get_contents($this->getComposerInstalledFile()), true);
  6261. $packages = isset($composerInstalled['packages']) ? $composerInstalled['packages'] : $composerInstalled;
  6262. foreach ($packages as $package) {
  6263. if (\in_array($package['name'], [self::COMPOSER_PACKAGE_NAME, self::COMPOSER_LEGACY_PACKAGE_NAME], true)) {
  6264. $this->composerInstallationDetails = $package;
  6265. break;
  6266. }
  6267. }
  6268. }
  6269. return $this->composerInstallationDetails;
  6270. }
  6271. public function getComposerVersion()
  6272. {
  6273. $package = $this->getComposerInstallationDetails();
  6274. $versionSuffix = '';
  6275. if (isset($package['dist']['reference'])) {
  6276. $versionSuffix = '#'.$package['dist']['reference'];
  6277. }
  6278. return $package['version'].$versionSuffix;
  6279. }
  6280. public function getVersion()
  6281. {
  6282. if ($this->isInstalledByComposer()) {
  6283. return Application::VERSION.':'.$this->getComposerVersion();
  6284. }
  6285. return Application::VERSION;
  6286. }
  6287. public function isInstalledAsPhar()
  6288. {
  6289. return 'phar://' === substr(__DIR__, 0, 7);
  6290. }
  6291. public function isInstalledByComposer()
  6292. {
  6293. if (null === $this->isInstalledByComposer) {
  6294. $this->isInstalledByComposer = !$this->isInstalledAsPhar() && file_exists($this->getComposerInstalledFile());
  6295. }
  6296. return $this->isInstalledByComposer;
  6297. }
  6298. public function getPharDownloadUri($version)
  6299. {
  6300. return sprintf(
  6301. 'https://github.com/FriendsOfPHP/PHP-CS-Fixer/releases/download/%s/php-cs-fixer.phar',
  6302. $version
  6303. );
  6304. }
  6305. private function getComposerInstalledFile()
  6306. {
  6307. return __DIR__.'/../../../composer/installed.json';
  6308. }
  6309. }
  6310. <?php
  6311. namespace PhpCsFixer;
  6312. use PhpCsFixer\Tokenizer\Tokens;
  6313. abstract class AbstractAlignFixerHelper
  6314. {
  6315. /**
  6316. @const
  6317. */
  6318. const ALIGNABLE_PLACEHOLDER = "\x2 ALIGNABLE%d \x3";
  6319. protected $deepestLevel = 0;
  6320. public function fix(Tokens $tokens)
  6321. {
  6322. $tokensClone = clone $tokens;
  6323. $this->injectAlignmentPlaceholders($tokensClone, 0, \count($tokens));
  6324. $content = $this->replacePlaceholder($tokensClone);
  6325. $tokens->setCode($content);
  6326. }
  6327. abstract protected function injectAlignmentPlaceholders(Tokens $tokens, $startAt, $endAt);
  6328. protected function replacePlaceholder(Tokens $tokens)
  6329. {
  6330. $tmpCode = $tokens->generateCode();
  6331. for ($j = 0; $j <= $this->deepestLevel; ++$j) {
  6332. $placeholder = sprintf(self::ALIGNABLE_PLACEHOLDER, $j);
  6333. if (false === strpos($tmpCode, $placeholder)) {
  6334. continue;
  6335. }
  6336. $lines = explode("\n", $tmpCode);
  6337. $linesWithPlaceholder = [];
  6338. $blockSize = 0;
  6339. $linesWithPlaceholder[$blockSize] = [];
  6340. foreach ($lines as $index => $line) {
  6341. if (substr_count($line, $placeholder) > 0) {
  6342. $linesWithPlaceholder[$blockSize][] = $index;
  6343. } else {
  6344. ++$blockSize;
  6345. $linesWithPlaceholder[$blockSize] = [];
  6346. }
  6347. }
  6348. foreach ($linesWithPlaceholder as $group) {
  6349. if (\count($group) < 1) {
  6350. continue;
  6351. }
  6352. $rightmostSymbol = 0;
  6353. foreach ($group as $index) {
  6354. $rightmostSymbol = max($rightmostSymbol, strpos(utf8_decode($lines[$index]), $placeholder));
  6355. }
  6356. foreach ($group as $index) {
  6357. $line = $lines[$index];
  6358. $currentSymbol = strpos(utf8_decode($line), $placeholder);
  6359. $delta = abs($rightmostSymbol - $currentSymbol);
  6360. if ($delta > 0) {
  6361. $line = str_replace($placeholder, str_repeat(' ', $delta).$placeholder, $line);
  6362. $lines[$index] = $line;
  6363. }
  6364. }
  6365. }
  6366. $tmpCode = str_replace($placeholder, '', implode("\n", $lines));
  6367. }
  6368. return $tmpCode;
  6369. }
  6370. }
  6371. <?php
  6372. namespace PhpCsFixer;
  6373. use Symfony\Component\Finder\Finder as BaseFinder;
  6374. /**
  6375. @gmail
  6376. */
  6377. class Finder extends BaseFinder
  6378. {
  6379. public function __construct()
  6380. {
  6381. parent::__construct();
  6382. $this
  6383. ->files()
  6384. ->name('*.php')
  6385. ->ignoreDotFiles(true)
  6386. ->ignoreVCS(true)
  6387. ->exclude('vendor')
  6388. ;
  6389. }
  6390. }
  6391. <?php
  6392. namespace PhpCsFixer;
  6393. final class WordMatcher
  6394. {
  6395. private $candidates;
  6396. public function __construct(array $candidates)
  6397. {
  6398. $this->candidates = $candidates;
  6399. }
  6400. public function match($needle)
  6401. {
  6402. $word = null;
  6403. $distance = ceil(\strlen($needle) * 0.35);
  6404. foreach ($this->candidates as $candidate) {
  6405. $candidateDistance = levenshtein($needle, $candidate);
  6406. if ($candidateDistance < $distance) {
  6407. $word = $candidate;
  6408. $distance = $candidateDistance;
  6409. }
  6410. }
  6411. return $word;
  6412. }
  6413. }
  6414. <?php
  6415. namespace PhpCsFixer;
  6416. use PhpCsFixer\Tokenizer\Analyzer\ArgumentsAnalyzer;
  6417. use PhpCsFixer\Tokenizer\Tokens;
  6418. abstract class AbstractFopenFlagFixer extends AbstractFunctionReferenceFixer
  6419. {
  6420. public function isCandidate(Tokens $tokens)
  6421. {
  6422. return $tokens->isAllTokenKindsFound([T_STRING, T_CONSTANT_ENCAPSED_STRING]);
  6423. }
  6424. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  6425. {
  6426. $argumentsAnalyzer = new ArgumentsAnalyzer();
  6427. $index = 0;
  6428. $end = $tokens->count() - 1;
  6429. while (true) {
  6430. $candidate = $this->find('fopen', $tokens, $index, $end);
  6431. if (null === $candidate) {
  6432. break;
  6433. }
  6434. $index = $candidate[1];
  6435. $arguments = $argumentsAnalyzer->getArguments(
  6436. $tokens,
  6437. $index,
  6438. $candidate[2]
  6439. );
  6440. $argumentsCount = \count($arguments);
  6441. if ($argumentsCount < 2 || $argumentsCount > 4) {
  6442. continue;
  6443. }
  6444. $argumentStartIndex = array_keys($arguments)[1];
  6445. $this->fixFopenFlagToken(
  6446. $tokens,
  6447. $argumentStartIndex,
  6448. $arguments[$argumentStartIndex]
  6449. );
  6450. }
  6451. }
  6452. abstract protected function fixFopenFlagToken(Tokens $tokens, $argumentStartIndex, $argumentEndIndex);
  6453. protected function isValidModeString($mode)
  6454. {
  6455. $modeLength = \strlen($mode);
  6456. if ($modeLength < 1 || $modeLength > 13) {
  6457. return false;
  6458. }
  6459. $validFlags = [
  6460. 'a' => true,
  6461. 'b' => true,
  6462. 'c' => true,
  6463. 'e' => true,
  6464. 'r' => true,
  6465. 't' => true,
  6466. 'w' => true,
  6467. 'x' => true,
  6468. ];
  6469. if (!isset($validFlags[$mode[0]])) {
  6470. return false;
  6471. }
  6472. unset($validFlags[$mode[0]]);
  6473. for ($i = 1; $i < $modeLength; ++$i) {
  6474. if (isset($validFlags[$mode[$i]])) {
  6475. unset($validFlags[$mode[$i]]);
  6476. continue;
  6477. }
  6478. if ('+' !== $mode[$i]
  6479. || (
  6480. 'a' !== $mode[$i - 1]
  6481. && 'c' !== $mode[$i - 1]
  6482. && 'r' !== $mode[$i - 1]
  6483. && 'w' !== $mode[$i - 1]
  6484. && 'x' !== $mode[$i - 1]
  6485. )
  6486. ) {
  6487. return false;
  6488. }
  6489. }
  6490. return true;
  6491. }
  6492. }
  6493. <?php
  6494. namespace PhpCsFixer;
  6495. final class StdinFileInfo extends \SplFileInfo
  6496. {
  6497. public function __construct()
  6498. {
  6499. }
  6500. public function __toString()
  6501. {
  6502. return $this->getRealPath();
  6503. }
  6504. public function getRealPath()
  6505. {
  6506. return 'php://stdin';
  6507. }
  6508. public function getATime()
  6509. {
  6510. return 0;
  6511. }
  6512. public function getBasename($suffix = null)
  6513. {
  6514. return $this->getFilename();
  6515. }
  6516. public function getCTime()
  6517. {
  6518. return 0;
  6519. }
  6520. public function getExtension()
  6521. {
  6522. return '.php';
  6523. }
  6524. public function getFileInfo($className = null)
  6525. {
  6526. throw new \BadMethodCallException(sprintf('Method "%s" is not implemented.', __METHOD__));
  6527. }
  6528. public function getFilename()
  6529. {
  6530. return 'stdin.php';
  6531. }
  6532. public function getGroup()
  6533. {
  6534. return 0;
  6535. }
  6536. public function getInode()
  6537. {
  6538. return 0;
  6539. }
  6540. public function getLinkTarget()
  6541. {
  6542. return '';
  6543. }
  6544. public function getMTime()
  6545. {
  6546. return 0;
  6547. }
  6548. public function getOwner()
  6549. {
  6550. return 0;
  6551. }
  6552. public function getPath()
  6553. {
  6554. return '';
  6555. }
  6556. public function getPathInfo($className = null)
  6557. {
  6558. throw new \BadMethodCallException(sprintf('Method "%s" is not implemented.', __METHOD__));
  6559. }
  6560. public function getPathname()
  6561. {
  6562. return $this->getFilename();
  6563. }
  6564. public function getPerms()
  6565. {
  6566. return 0;
  6567. }
  6568. public function getSize()
  6569. {
  6570. return 0;
  6571. }
  6572. public function getType()
  6573. {
  6574. return 'file';
  6575. }
  6576. public function isDir()
  6577. {
  6578. return false;
  6579. }
  6580. public function isExecutable()
  6581. {
  6582. return false;
  6583. }
  6584. public function isFile()
  6585. {
  6586. return true;
  6587. }
  6588. public function isLink()
  6589. {
  6590. return false;
  6591. }
  6592. public function isReadable()
  6593. {
  6594. return true;
  6595. }
  6596. public function isWritable()
  6597. {
  6598. return false;
  6599. }
  6600. public function openFile($openMode = 'r', $useIncludePath = false, $context = null)
  6601. {
  6602. throw new \BadMethodCallException(sprintf('Method "%s" is not implemented.', __METHOD__));
  6603. }
  6604. public function setFileClass($className = null)
  6605. {
  6606. }
  6607. public function setInfoClass($className = null)
  6608. {
  6609. }
  6610. }
  6611. <?php
  6612. namespace PhpCsFixer\Error;
  6613. final class ErrorsManager
  6614. {
  6615. private $errors = [];
  6616. public function getInvalidErrors()
  6617. {
  6618. return array_filter($this->errors, static function (Error $error) {
  6619. return Error::TYPE_INVALID === $error->getType();
  6620. });
  6621. }
  6622. public function getExceptionErrors()
  6623. {
  6624. return array_filter($this->errors, static function (Error $error) {
  6625. return Error::TYPE_EXCEPTION === $error->getType();
  6626. });
  6627. }
  6628. public function getLintErrors()
  6629. {
  6630. return array_filter($this->errors, static function (Error $error) {
  6631. return Error::TYPE_LINT === $error->getType();
  6632. });
  6633. }
  6634. public function isEmpty()
  6635. {
  6636. return empty($this->errors);
  6637. }
  6638. public function report(Error $error)
  6639. {
  6640. $this->errors[] = $error;
  6641. }
  6642. }
  6643. <?php
  6644. namespace PhpCsFixer\Error;
  6645. final class Error
  6646. {
  6647. const TYPE_INVALID = 1;
  6648. const TYPE_EXCEPTION = 2;
  6649. const TYPE_LINT = 3;
  6650. private $type;
  6651. private $filePath;
  6652. private $source;
  6653. private $appliedFixers;
  6654. private $diff;
  6655. public function __construct($type, $filePath, $source = null, array $appliedFixers = [], $diff = null)
  6656. {
  6657. $this->type = $type;
  6658. $this->filePath = $filePath;
  6659. $this->source = $source;
  6660. $this->appliedFixers = $appliedFixers;
  6661. $this->diff = $diff;
  6662. }
  6663. public function getFilePath()
  6664. {
  6665. return $this->filePath;
  6666. }
  6667. public function getSource()
  6668. {
  6669. return $this->source;
  6670. }
  6671. public function getType()
  6672. {
  6673. return $this->type;
  6674. }
  6675. public function getAppliedFixers()
  6676. {
  6677. return $this->appliedFixers;
  6678. }
  6679. public function getDiff()
  6680. {
  6681. return $this->diff;
  6682. }
  6683. }
  6684. <?php
  6685. namespace PhpCsFixer;
  6686. /**
  6687. @gmail
  6688. */
  6689. final class FileRemoval
  6690. {
  6691. private $files = [];
  6692. public function __construct()
  6693. {
  6694. register_shutdown_function([$this, 'clean']);
  6695. }
  6696. public function __destruct()
  6697. {
  6698. $this->clean();
  6699. }
  6700. public function observe($path)
  6701. {
  6702. $this->files[$path] = true;
  6703. }
  6704. public function delete($path)
  6705. {
  6706. if (isset($this->files[$path])) {
  6707. unset($this->files[$path]);
  6708. }
  6709. $this->unlink($path);
  6710. }
  6711. public function clean()
  6712. {
  6713. foreach ($this->files as $file => $value) {
  6714. $this->unlink($file);
  6715. }
  6716. $this->files = [];
  6717. }
  6718. private function unlink($path)
  6719. {
  6720. @unlink($path);
  6721. }
  6722. }
  6723. <?php
  6724. namespace PhpCsFixer;
  6725. use PhpCsFixer\Fixer\FixerInterface;
  6726. /**
  6727. @gmail
  6728. @gmail
  6729. */
  6730. class Config implements ConfigInterface
  6731. {
  6732. private $cacheFile = '.php_cs.cache';
  6733. private $customFixers = [];
  6734. private $finder;
  6735. private $format = 'txt';
  6736. private $hideProgress = false;
  6737. private $indent = ' ';
  6738. private $isRiskyAllowed = false;
  6739. private $lineEnding = "\n";
  6740. private $name;
  6741. private $phpExecutable;
  6742. private $rules = ['@PSR2' => true];
  6743. private $usingCache = true;
  6744. public function __construct($name = 'default')
  6745. {
  6746. $this->name = $name;
  6747. }
  6748. public static function create()
  6749. {
  6750. return new static();
  6751. }
  6752. public function getCacheFile()
  6753. {
  6754. return $this->cacheFile;
  6755. }
  6756. public function getCustomFixers()
  6757. {
  6758. return $this->customFixers;
  6759. }
  6760. public function getFinder()
  6761. {
  6762. if (null === $this->finder) {
  6763. $this->finder = new Finder();
  6764. }
  6765. return $this->finder;
  6766. }
  6767. public function getFormat()
  6768. {
  6769. return $this->format;
  6770. }
  6771. public function getHideProgress()
  6772. {
  6773. return $this->hideProgress;
  6774. }
  6775. public function getIndent()
  6776. {
  6777. return $this->indent;
  6778. }
  6779. public function getLineEnding()
  6780. {
  6781. return $this->lineEnding;
  6782. }
  6783. public function getName()
  6784. {
  6785. return $this->name;
  6786. }
  6787. public function getPhpExecutable()
  6788. {
  6789. return $this->phpExecutable;
  6790. }
  6791. public function getRiskyAllowed()
  6792. {
  6793. return $this->isRiskyAllowed;
  6794. }
  6795. public function getRules()
  6796. {
  6797. return $this->rules;
  6798. }
  6799. public function getUsingCache()
  6800. {
  6801. return $this->usingCache;
  6802. }
  6803. public function registerCustomFixers($fixers)
  6804. {
  6805. if (false === \is_array($fixers) && false === $fixers instanceof \Traversable) {
  6806. throw new \InvalidArgumentException(sprintf(
  6807. 'Argument must be an array or a Traversable, got "%s".',
  6808. \is_object($fixers) ? \get_class($fixers) : \gettype($fixers)
  6809. ));
  6810. }
  6811. foreach ($fixers as $fixer) {
  6812. $this->addCustomFixer($fixer);
  6813. }
  6814. return $this;
  6815. }
  6816. public function setCacheFile($cacheFile)
  6817. {
  6818. $this->cacheFile = $cacheFile;
  6819. return $this;
  6820. }
  6821. public function setFinder($finder)
  6822. {
  6823. if (false === \is_array($finder) && false === $finder instanceof \Traversable) {
  6824. throw new \InvalidArgumentException(sprintf(
  6825. 'Argument must be an array or a Traversable, got "%s".',
  6826. \is_object($finder) ? \get_class($finder) : \gettype($finder)
  6827. ));
  6828. }
  6829. $this->finder = $finder;
  6830. return $this;
  6831. }
  6832. public function setFormat($format)
  6833. {
  6834. $this->format = $format;
  6835. return $this;
  6836. }
  6837. public function setHideProgress($hideProgress)
  6838. {
  6839. $this->hideProgress = $hideProgress;
  6840. return $this;
  6841. }
  6842. public function setIndent($indent)
  6843. {
  6844. $this->indent = $indent;
  6845. return $this;
  6846. }
  6847. public function setLineEnding($lineEnding)
  6848. {
  6849. $this->lineEnding = $lineEnding;
  6850. return $this;
  6851. }
  6852. public function setPhpExecutable($phpExecutable)
  6853. {
  6854. $this->phpExecutable = $phpExecutable;
  6855. return $this;
  6856. }
  6857. public function setRiskyAllowed($isRiskyAllowed)
  6858. {
  6859. $this->isRiskyAllowed = $isRiskyAllowed;
  6860. return $this;
  6861. }
  6862. public function setRules(array $rules)
  6863. {
  6864. $this->rules = $rules;
  6865. return $this;
  6866. }
  6867. public function setUsingCache($usingCache)
  6868. {
  6869. $this->usingCache = $usingCache;
  6870. return $this;
  6871. }
  6872. private function addCustomFixer(FixerInterface $fixer)
  6873. {
  6874. $this->customFixers[] = $fixer;
  6875. }
  6876. }
  6877. <?php
  6878. namespace PhpCsFixer;
  6879. use PhpCsFixer\DocBlock\Annotation;
  6880. use PhpCsFixer\DocBlock\DocBlock;
  6881. use PhpCsFixer\Tokenizer\Token;
  6882. use PhpCsFixer\Tokenizer\Tokens;
  6883. abstract class AbstractPhpdocTypesFixer extends AbstractFixer
  6884. {
  6885. protected $tags;
  6886. public function __construct()
  6887. {
  6888. parent::__construct();
  6889. $this->tags = Annotation::getTagsWithTypes();
  6890. }
  6891. public function isCandidate(Tokens $tokens)
  6892. {
  6893. return $tokens->isTokenKindFound(T_DOC_COMMENT);
  6894. }
  6895. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  6896. {
  6897. foreach ($tokens as $index => $token) {
  6898. if (!$token->isGivenKind(T_DOC_COMMENT)) {
  6899. continue;
  6900. }
  6901. $doc = new DocBlock($token->getContent());
  6902. $annotations = $doc->getAnnotationsOfType($this->tags);
  6903. if (empty($annotations)) {
  6904. continue;
  6905. }
  6906. foreach ($annotations as $annotation) {
  6907. $this->fixTypes($annotation);
  6908. }
  6909. $tokens[$index] = new Token([T_DOC_COMMENT, $doc->getContent()]);
  6910. }
  6911. }
  6912. abstract protected function normalize($type);
  6913. private function fixTypes(Annotation $annotation)
  6914. {
  6915. $types = $annotation->getTypes();
  6916. $new = $this->normalizeTypes($types);
  6917. if ($types !== $new) {
  6918. $annotation->setTypes($new);
  6919. }
  6920. }
  6921. private function normalizeTypes(array $types)
  6922. {
  6923. foreach ($types as $index => $type) {
  6924. $types[$index] = $this->normalizeType($type);
  6925. }
  6926. return $types;
  6927. }
  6928. private function normalizeType($type)
  6929. {
  6930. if ('[]' === substr($type, -2)) {
  6931. return $this->normalize(substr($type, 0, -2)).'[]';
  6932. }
  6933. return $this->normalize($type);
  6934. }
  6935. }
  6936. <?php
  6937. namespace PhpCsFixer;
  6938. final class WhitespacesFixerConfig
  6939. {
  6940. private $indent;
  6941. private $lineEnding;
  6942. public function __construct($indent = ' ', $lineEnding = "\n")
  6943. {
  6944. if (!\in_array($indent, [' ', ' ', "\t"], true)) {
  6945. throw new \InvalidArgumentException('Invalid "indent" param, expected tab or two or four spaces.');
  6946. }
  6947. if (!\in_array($lineEnding, ["\n", "\r\n"], true)) {
  6948. throw new \InvalidArgumentException('Invalid "lineEnding" param, expected "\n" or "\r\n".');
  6949. }
  6950. $this->indent = $indent;
  6951. $this->lineEnding = $lineEnding;
  6952. }
  6953. public function getIndent()
  6954. {
  6955. return $this->indent;
  6956. }
  6957. public function getLineEnding()
  6958. {
  6959. return $this->lineEnding;
  6960. }
  6961. }
  6962. <?php
  6963. namespace PhpCsFixer;
  6964. use PhpCsFixer\Tokenizer\Analyzer\FunctionsAnalyzer;
  6965. use PhpCsFixer\Tokenizer\Tokens;
  6966. abstract class AbstractFunctionReferenceFixer extends AbstractFixer
  6967. {
  6968. public function isRisky()
  6969. {
  6970. return true;
  6971. }
  6972. protected function find($functionNameToSearch, Tokens $tokens, $start = 0, $end = null)
  6973. {
  6974. $end = null === $end ? $tokens->count() : $end;
  6975. $candidateSequence = [[T_STRING, $functionNameToSearch], '('];
  6976. $matches = $tokens->findSequence($candidateSequence, $start, $end, false);
  6977. if (null === $matches) {
  6978. return null;
  6979. }
  6980. list($functionName, $openParenthesis) = array_keys($matches);
  6981. $functionsAnalyzer = new FunctionsAnalyzer();
  6982. if (!$functionsAnalyzer->isGlobalFunctionCall($tokens, $functionName)) {
  6983. return $this->find($functionNameToSearch, $tokens, $openParenthesis, $end);
  6984. }
  6985. return [$functionName, $openParenthesis, $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $openParenthesis)];
  6986. }
  6987. }
  6988. <?php
  6989. namespace PhpCsFixer\Fixer\Whitespace;
  6990. use PhpCsFixer\AbstractFixer;
  6991. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  6992. use PhpCsFixer\FixerDefinition\CodeSample;
  6993. use PhpCsFixer\FixerDefinition\FixerDefinition;
  6994. use PhpCsFixer\Tokenizer\Tokens;
  6995. /**
  6996. @gmail
  6997. */
  6998. final class SingleBlankLineAtEofFixer extends AbstractFixer implements WhitespacesAwareFixerInterface
  6999. {
  7000. public function getDefinition()
  7001. {
  7002. return new FixerDefinition(
  7003. 'A PHP file without end tag must always end with a single empty line feed.',
  7004. [
  7005. new CodeSample("<?php\n\$a = 1;"),
  7006. new CodeSample("<?php\n\$a = 1;\n\n"),
  7007. ]
  7008. );
  7009. }
  7010. public function getPriority()
  7011. {
  7012. return -50;
  7013. }
  7014. public function isCandidate(Tokens $tokens)
  7015. {
  7016. return true;
  7017. }
  7018. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  7019. {
  7020. $count = $tokens->count();
  7021. if ($count && !$tokens[$count - 1]->isGivenKind([T_INLINE_HTML, T_CLOSE_TAG, T_OPEN_TAG])) {
  7022. $tokens->ensureWhitespaceAtIndex($count - 1, 1, $this->whitespacesConfig->getLineEnding());
  7023. }
  7024. }
  7025. }
  7026. <?php
  7027. namespace PhpCsFixer\Fixer\Whitespace;
  7028. use PhpCsFixer\AbstractFixer;
  7029. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  7030. use PhpCsFixer\FixerConfiguration\AllowedValueSubset;
  7031. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverRootless;
  7032. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  7033. use PhpCsFixer\FixerDefinition\CodeSample;
  7034. use PhpCsFixer\FixerDefinition\FixerDefinition;
  7035. use PhpCsFixer\Tokenizer\CT;
  7036. use PhpCsFixer\Tokenizer\Tokens;
  7037. final class NoSpacesAroundOffsetFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface
  7038. {
  7039. public function getDefinition()
  7040. {
  7041. return new FixerDefinition(
  7042. 'There MUST NOT be spaces around offset braces.',
  7043. [
  7044. new CodeSample("<?php\n\$sample = \$b [ 'a' ] [ 'b' ];\n"),
  7045. new CodeSample("<?php\n\$sample = \$b [ 'a' ] [ 'b' ];\n", ['positions' => ['inside']]),
  7046. new CodeSample("<?php\n\$sample = \$b [ 'a' ] [ 'b' ];\n", ['positions' => ['outside']]),
  7047. ]
  7048. );
  7049. }
  7050. public function isCandidate(Tokens $tokens)
  7051. {
  7052. return $tokens->isAnyTokenKindsFound(['[', CT::T_ARRAY_INDEX_CURLY_BRACE_OPEN]);
  7053. }
  7054. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  7055. {
  7056. foreach ($tokens as $index => $token) {
  7057. if (!$token->equalsAny(['[', [CT::T_ARRAY_INDEX_CURLY_BRACE_OPEN]])) {
  7058. continue;
  7059. }
  7060. if (\in_array('inside', $this->configuration['positions'], true)) {
  7061. if ($token->equals('[')) {
  7062. $endIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_INDEX_SQUARE_BRACE, $index);
  7063. } else {
  7064. $endIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_ARRAY_INDEX_CURLY_BRACE, $index);
  7065. }
  7066. if ($tokens[$index + 1]->isWhitespace(" \t")) {
  7067. $tokens->clearAt($index + 1);
  7068. }
  7069. if ($tokens[$endIndex - 1]->isWhitespace(" \t")) {
  7070. $tokens->clearAt($endIndex - 1);
  7071. }
  7072. }
  7073. if (\in_array('outside', $this->configuration['positions'], true)) {
  7074. $prevNonWhitespaceIndex = $tokens->getPrevNonWhitespace($index);
  7075. if ($tokens[$prevNonWhitespaceIndex]->isComment()) {
  7076. continue;
  7077. }
  7078. $tokens->removeLeadingWhitespace($index);
  7079. }
  7080. }
  7081. }
  7082. protected function createConfigurationDefinition()
  7083. {
  7084. $values = ['inside', 'outside'];
  7085. return new FixerConfigurationResolverRootless('positions', [
  7086. (new FixerOptionBuilder('positions', 'Whether spacing should be fixed inside and/or outside the offset braces.'))
  7087. ->setAllowedTypes(['array'])
  7088. ->setAllowedValues([new AllowedValueSubset($values)])
  7089. ->setDefault($values)
  7090. ->getOption(),
  7091. ], $this->getName());
  7092. }
  7093. }
  7094. <?php
  7095. namespace PhpCsFixer\Fixer\Whitespace;
  7096. use PhpCsFixer\AbstractFixer;
  7097. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  7098. use PhpCsFixer\FixerDefinition\CodeSample;
  7099. use PhpCsFixer\FixerDefinition\FixerDefinition;
  7100. use PhpCsFixer\Preg;
  7101. use PhpCsFixer\Tokenizer\CT;
  7102. use PhpCsFixer\Tokenizer\Token;
  7103. use PhpCsFixer\Tokenizer\Tokens;
  7104. final class MethodChainingIndentationFixer extends AbstractFixer implements WhitespacesAwareFixerInterface
  7105. {
  7106. public function getDefinition()
  7107. {
  7108. return new FixerDefinition(
  7109. 'Method chaining MUST be properly indented. Method chaining with different levels of indentation is not supported.',
  7110. [new CodeSample("<?php\n\$user->setEmail('voff.web@gmail.com')\n ->setPassword('233434');\n")]
  7111. );
  7112. }
  7113. public function getPriority()
  7114. {
  7115. return -29;
  7116. }
  7117. public function isCandidate(Tokens $tokens)
  7118. {
  7119. return $tokens->isTokenKindFound(T_OBJECT_OPERATOR);
  7120. }
  7121. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  7122. {
  7123. $lineEnding = $this->whitespacesConfig->getLineEnding();
  7124. for ($index = 1, $count = \count($tokens); $index < $count; ++$index) {
  7125. if (!$tokens[$index]->isGivenKind(T_OBJECT_OPERATOR)) {
  7126. continue;
  7127. }
  7128. if ($this->canBeMovedToNextLine($index, $tokens)) {
  7129. $newline = new Token([T_WHITESPACE, $lineEnding]);
  7130. if ($tokens[$index - 1]->isWhitespace()) {
  7131. $tokens[$index - 1] = $newline;
  7132. } else {
  7133. $tokens->insertAt($index, $newline);
  7134. ++$index;
  7135. }
  7136. }
  7137. $currentIndent = $this->getIndentAt($tokens, $index - 1);
  7138. if (null === $currentIndent) {
  7139. continue;
  7140. }
  7141. $expectedIndent = $this->getExpectedIndentAt($tokens, $index);
  7142. if ($currentIndent !== $expectedIndent) {
  7143. $tokens[$index - 1] = new Token([T_WHITESPACE, $lineEnding.$expectedIndent]);
  7144. }
  7145. }
  7146. }
  7147. private function getExpectedIndentAt(Tokens $tokens, $index)
  7148. {
  7149. $index = $tokens->getPrevMeaningfulToken($index);
  7150. $indent = $this->whitespacesConfig->getIndent();
  7151. for ($i = $index; $i >= 0; --$i) {
  7152. if ($tokens[$i]->equals(')')) {
  7153. $i = $tokens->findBlockStart(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $i);
  7154. }
  7155. $currentIndent = $this->getIndentAt($tokens, $i);
  7156. if (null === $currentIndent) {
  7157. continue;
  7158. }
  7159. if ($this->currentLineRequiresExtraIndentLevel($tokens, $i, $index)) {
  7160. return $currentIndent.$indent;
  7161. }
  7162. return $currentIndent;
  7163. }
  7164. return $indent;
  7165. }
  7166. private function canBeMovedToNextLine($index, Tokens $tokens)
  7167. {
  7168. $prevMeaningful = $tokens->getPrevMeaningfulToken($index);
  7169. $hasCommentBefore = false;
  7170. for ($i = $index - 1; $i > $prevMeaningful; --$i) {
  7171. if ($tokens[$i]->isComment()) {
  7172. $hasCommentBefore = true;
  7173. continue;
  7174. }
  7175. if ($tokens[$i]->isWhitespace() && 1 === Preg::match('/\R/', $tokens[$i]->getContent())) {
  7176. return $hasCommentBefore;
  7177. }
  7178. }
  7179. return false;
  7180. }
  7181. private function getIndentAt(Tokens $tokens, $index)
  7182. {
  7183. if (1 === Preg::match('/\R{1}(\h*)$/', $this->getIndentContentAt($tokens, $index), $matches)) {
  7184. return $matches[1];
  7185. }
  7186. return null;
  7187. }
  7188. private function getIndentContentAt(Tokens $tokens, $index)
  7189. {
  7190. if (!$tokens[$index]->isGivenKind([T_WHITESPACE, T_INLINE_HTML])) {
  7191. return '';
  7192. }
  7193. $content = $tokens[$index]->getContent();
  7194. if ($tokens[$index]->isWhitespace() && $tokens[$index - 1]->isGivenKind(T_OPEN_TAG)) {
  7195. $content = $tokens[$index - 1]->getContent().$content;
  7196. }
  7197. if (Preg::match('/\R/', $content)) {
  7198. return $content;
  7199. }
  7200. return '';
  7201. }
  7202. private function currentLineRequiresExtraIndentLevel(Tokens $tokens, $start, $end)
  7203. {
  7204. if ($tokens[$start + 1]->isGivenKind(T_OBJECT_OPERATOR)) {
  7205. return false;
  7206. }
  7207. if ($tokens[$end]->isGivenKind(CT::T_BRACE_CLASS_INSTANTIATION_CLOSE)) {
  7208. return true;
  7209. }
  7210. return
  7211. !$tokens[$end]->equals(')')
  7212. || $tokens->findBlockStart(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $end) >= $start
  7213. ;
  7214. }
  7215. }
  7216. <?php
  7217. namespace PhpCsFixer\Fixer\Whitespace;
  7218. use PhpCsFixer\AbstractFixer;
  7219. use PhpCsFixer\FixerDefinition\CodeSample;
  7220. use PhpCsFixer\FixerDefinition\FixerDefinition;
  7221. use PhpCsFixer\Preg;
  7222. use PhpCsFixer\Tokenizer\Token;
  7223. use PhpCsFixer\Tokenizer\Tokens;
  7224. /**
  7225. @gmail
  7226. */
  7227. final class NoTrailingWhitespaceFixer extends AbstractFixer
  7228. {
  7229. public function getDefinition()
  7230. {
  7231. return new FixerDefinition(
  7232. 'Remove trailing whitespace at the end of non-blank lines.',
  7233. [new CodeSample("<?php\n\$a = 1; \n")]
  7234. );
  7235. }
  7236. public function getPriority()
  7237. {
  7238. return 0;
  7239. }
  7240. public function isCandidate(Tokens $tokens)
  7241. {
  7242. return true;
  7243. }
  7244. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  7245. {
  7246. for ($index = \count($tokens) - 1; $index >= 0; --$index) {
  7247. $token = $tokens[$index];
  7248. if (
  7249. $token->isGivenKind(T_OPEN_TAG)
  7250. && $tokens->offsetExists($index + 1)
  7251. && $tokens[$index + 1]->isWhitespace()
  7252. && 1 === Preg::match('/(.*)\h$/', $token->getContent(), $openTagMatches)
  7253. && 1 === Preg::match('/^(\R)(.*)$/s', $tokens[$index + 1]->getContent(), $whitespaceMatches)
  7254. ) {
  7255. $tokens[$index] = new Token([T_OPEN_TAG, $openTagMatches[1].$whitespaceMatches[1]]);
  7256. if ('' === $whitespaceMatches[2]) {
  7257. $tokens->clearAt($index + 1);
  7258. } else {
  7259. $tokens[$index + 1] = new Token([T_WHITESPACE, $whitespaceMatches[2]]);
  7260. }
  7261. continue;
  7262. }
  7263. if (!$token->isWhitespace()) {
  7264. continue;
  7265. }
  7266. $lines = Preg::split('/(\\R+)/', $token->getContent(), -1, PREG_SPLIT_DELIM_CAPTURE);
  7267. $linesSize = \count($lines);
  7268. if ($linesSize > 1 || !isset($tokens[$index + 1])) {
  7269. if (!$tokens[$index - 1]->isGivenKind(T_OPEN_TAG) || 1 !== Preg::match('/(.*)\R$/', $tokens[$index - 1]->getContent())) {
  7270. $lines[0] = rtrim($lines[0], " \t");
  7271. }
  7272. for ($i = 1; $i < $linesSize; ++$i) {
  7273. $trimmedLine = rtrim($lines[$i], " \t");
  7274. if ('' !== $trimmedLine) {
  7275. $lines[$i] = $trimmedLine;
  7276. }
  7277. }
  7278. $content = implode('', $lines);
  7279. if ('' !== $content) {
  7280. $tokens[$index] = new Token([$token->getId(), $content]);
  7281. } else {
  7282. $tokens->clearAt($index);
  7283. }
  7284. }
  7285. }
  7286. }
  7287. }
  7288. <?php
  7289. namespace PhpCsFixer\Fixer\Whitespace;
  7290. use PhpCsFixer\AbstractFixer;
  7291. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  7292. use PhpCsFixer\FixerDefinition\CodeSample;
  7293. use PhpCsFixer\FixerDefinition\FixerDefinition;
  7294. use PhpCsFixer\Preg;
  7295. use PhpCsFixer\Tokenizer\Token;
  7296. use PhpCsFixer\Tokenizer\Tokens;
  7297. final class IndentationTypeFixer extends AbstractFixer implements WhitespacesAwareFixerInterface
  7298. {
  7299. private $indent;
  7300. public function getDefinition()
  7301. {
  7302. return new FixerDefinition(
  7303. 'Code MUST use configured indentation type.',
  7304. [
  7305. new CodeSample("<?php\n\nif (true) {\n\techo 'Hello!';\n}\n"),
  7306. ]
  7307. );
  7308. }
  7309. public function getPriority()
  7310. {
  7311. return 50;
  7312. }
  7313. public function isCandidate(Tokens $tokens)
  7314. {
  7315. return $tokens->isAnyTokenKindsFound([T_COMMENT, T_DOC_COMMENT, T_WHITESPACE]);
  7316. }
  7317. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  7318. {
  7319. $this->indent = $this->whitespacesConfig->getIndent();
  7320. foreach ($tokens as $index => $token) {
  7321. if ($token->isComment()) {
  7322. $tokens[$index] = $this->fixIndentInComment($tokens, $index);
  7323. continue;
  7324. }
  7325. if ($token->isWhitespace()) {
  7326. $tokens[$index] = $this->fixIndentToken($tokens, $index);
  7327. continue;
  7328. }
  7329. }
  7330. }
  7331. private function fixIndentInComment(Tokens $tokens, $index)
  7332. {
  7333. $content = Preg::replace('/^(?:(?<! ) {1,3})?\t/m', '\1 ', $tokens[$index]->getContent(), -1, $count);
  7334. while (0 !== $count) {
  7335. $content = Preg::replace('/^(\ +)?\t/m', '\1 ', $content, -1, $count);
  7336. }
  7337. $indent = $this->indent;
  7338. $content = Preg::replaceCallback('/^(?: )+/m', function ($matches) use ($indent) {
  7339. return $this->getExpectedIndent($matches[0], $indent);
  7340. }, $content);
  7341. return new Token([$tokens[$index]->getId(), $content]);
  7342. }
  7343. private function fixIndentToken(Tokens $tokens, $index)
  7344. {
  7345. $content = $tokens[$index]->getContent();
  7346. $previousTokenHasTrailingLinebreak = false;
  7347. if (false !== strpos($tokens[$index - 1]->getContent(), "\n")) {
  7348. $content = "\n".$content;
  7349. $previousTokenHasTrailingLinebreak = true;
  7350. }
  7351. $indent = $this->indent;
  7352. $newContent = Preg::replaceCallback(
  7353. '/(\R)(\h+)/',
  7354. function (array $matches) use ($indent) {
  7355. $content = Preg::replace('/(?:(?<! ) {1,3})?\t/', ' ', $matches[2]);
  7356. return $matches[1].$this->getExpectedIndent($content, $indent);
  7357. },
  7358. $content
  7359. );
  7360. if ($previousTokenHasTrailingLinebreak) {
  7361. $newContent = substr($newContent, 1);
  7362. }
  7363. return new Token([T_WHITESPACE, $newContent]);
  7364. }
  7365. private function getExpectedIndent($content, $indent)
  7366. {
  7367. if ("\t" === $indent) {
  7368. $content = str_replace(' ', $indent, $content);
  7369. }
  7370. return $content;
  7371. }
  7372. }
  7373. <?php
  7374. namespace PhpCsFixer\Fixer\Whitespace;
  7375. use PhpCsFixer\AbstractFixer;
  7376. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  7377. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  7378. use PhpCsFixer\FixerConfiguration\AllowedValueSubset;
  7379. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  7380. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  7381. use PhpCsFixer\FixerDefinition\CodeSample;
  7382. use PhpCsFixer\FixerDefinition\FixerDefinition;
  7383. use PhpCsFixer\Tokenizer\Token;
  7384. use PhpCsFixer\Tokenizer\Tokens;
  7385. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  7386. /**
  7387. @localheinz
  7388. */
  7389. final class BlankLineBeforeStatementFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface, WhitespacesAwareFixerInterface
  7390. {
  7391. private static $tokenMap = [
  7392. 'break' => T_BREAK,
  7393. 'case' => T_CASE,
  7394. 'continue' => T_CONTINUE,
  7395. 'declare' => T_DECLARE,
  7396. 'default' => T_DEFAULT,
  7397. 'die' => T_EXIT,
  7398. 'do' => T_DO,
  7399. 'exit' => T_EXIT,
  7400. 'for' => T_FOR,
  7401. 'foreach' => T_FOREACH,
  7402. 'goto' => T_GOTO,
  7403. 'if' => T_IF,
  7404. 'include' => T_INCLUDE,
  7405. 'include_once' => T_INCLUDE_ONCE,
  7406. 'require' => T_REQUIRE,
  7407. 'require_once' => T_REQUIRE_ONCE,
  7408. 'return' => T_RETURN,
  7409. 'switch' => T_SWITCH,
  7410. 'throw' => T_THROW,
  7411. 'try' => T_TRY,
  7412. 'while' => T_WHILE,
  7413. 'yield' => T_YIELD,
  7414. ];
  7415. private $fixTokenMap = [];
  7416. public function configure(array $configuration = null)
  7417. {
  7418. parent::configure($configuration);
  7419. $this->fixTokenMap = [];
  7420. foreach ($this->configuration['statements'] as $key) {
  7421. $this->fixTokenMap[$key] = self::$tokenMap[$key];
  7422. }
  7423. $this->fixTokenMap = array_values($this->fixTokenMap);
  7424. }
  7425. public function getDefinition()
  7426. {
  7427. return new FixerDefinition(
  7428. 'An empty line feed must precede any configured statement.',
  7429. [
  7430. new CodeSample(
  7431. '<?php
  7432. function A() {
  7433. echo 1;
  7434. return 1;
  7435. }
  7436. '
  7437. ),
  7438. new CodeSample(
  7439. '<?php
  7440. switch ($foo) {
  7441. case 42:
  7442. $bar->process();
  7443. break;
  7444. case 44:
  7445. break;
  7446. }
  7447. ',
  7448. [
  7449. 'statements' => ['break'],
  7450. ]
  7451. ),
  7452. new CodeSample(
  7453. '<?php
  7454. foreach ($foo as $bar) {
  7455. if ($bar->isTired()) {
  7456. $bar->sleep();
  7457. continue;
  7458. }
  7459. }
  7460. ',
  7461. [
  7462. 'statements' => ['continue'],
  7463. ]
  7464. ),
  7465. new CodeSample(
  7466. '<?php
  7467. if ($foo === false) {
  7468. die(0);
  7469. } else {
  7470. $bar = 9000;
  7471. die(1);
  7472. }
  7473. ',
  7474. [
  7475. 'statements' => ['die'],
  7476. ]
  7477. ),
  7478. new CodeSample(
  7479. '<?php
  7480. $i = 0;
  7481. do {
  7482. echo $i;
  7483. } while ($i > 0);
  7484. ',
  7485. [
  7486. 'statements' => ['do'],
  7487. ]
  7488. ),
  7489. new CodeSample(
  7490. '<?php
  7491. if ($foo === false) {
  7492. exit(0);
  7493. } else {
  7494. $bar = 9000;
  7495. exit(1);
  7496. }
  7497. ',
  7498. [
  7499. 'statements' => ['exit'],
  7500. ]
  7501. ),
  7502. new CodeSample(
  7503. '<?php
  7504. a:
  7505. if ($foo === false) {
  7506. goto a;
  7507. } else {
  7508. $bar = 9000;
  7509. goto b;
  7510. }
  7511. ',
  7512. [
  7513. 'statements' => ['goto'],
  7514. ]
  7515. ),
  7516. new CodeSample(
  7517. '<?php
  7518. $a = 9000;
  7519. if (true) {
  7520. $foo = $bar;
  7521. }
  7522. ',
  7523. [
  7524. 'statements' => ['if'],
  7525. ]
  7526. ),
  7527. new CodeSample(
  7528. '<?php
  7529. if (true) {
  7530. $foo = $bar;
  7531. return;
  7532. }
  7533. ',
  7534. [
  7535. 'statements' => ['return'],
  7536. ]
  7537. ),
  7538. new CodeSample(
  7539. '<?php
  7540. $a = 9000;
  7541. switch ($a) {
  7542. case 42:
  7543. break;
  7544. }
  7545. ',
  7546. [
  7547. 'statements' => ['switch'],
  7548. ]
  7549. ),
  7550. new CodeSample(
  7551. '<?php
  7552. if (null === $a) {
  7553. $foo->bar();
  7554. throw new \UnexpectedValueException("A cannot be null.");
  7555. }
  7556. ',
  7557. [
  7558. 'statements' => ['throw'],
  7559. ]
  7560. ),
  7561. new CodeSample(
  7562. '<?php
  7563. $a = 9000;
  7564. try {
  7565. $foo->bar();
  7566. } catch (\Exception $exception) {
  7567. $a = -1;
  7568. }
  7569. ',
  7570. [
  7571. 'statements' => ['try'],
  7572. ]
  7573. ),
  7574. new CodeSample(
  7575. '<?php
  7576. if (true) {
  7577. $foo = $bar;
  7578. yield $foo;
  7579. }
  7580. ',
  7581. [
  7582. 'statements' => ['yield'],
  7583. ]
  7584. ),
  7585. ]
  7586. );
  7587. }
  7588. public function getPriority()
  7589. {
  7590. return -21;
  7591. }
  7592. public function isCandidate(Tokens $tokens)
  7593. {
  7594. return $tokens->isAnyTokenKindsFound($this->fixTokenMap);
  7595. }
  7596. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  7597. {
  7598. $analyzer = new TokensAnalyzer($tokens);
  7599. for ($index = $tokens->count() - 1; $index > 0; --$index) {
  7600. $token = $tokens[$index];
  7601. if (!$token->isGivenKind($this->fixTokenMap)) {
  7602. continue;
  7603. }
  7604. if ($token->isGivenKind(T_WHILE) && $analyzer->isWhilePartOfDoWhile($index)) {
  7605. continue;
  7606. }
  7607. $prevNonWhitespace = $tokens->getPrevNonWhitespace($index);
  7608. if ($this->shouldAddBlankLine($tokens, $prevNonWhitespace)) {
  7609. $this->insertBlankLine($tokens, $index);
  7610. }
  7611. $index = $prevNonWhitespace;
  7612. }
  7613. }
  7614. protected function createConfigurationDefinition()
  7615. {
  7616. return new FixerConfigurationResolver([
  7617. (new FixerOptionBuilder('statements', 'List of statements which must be preceded by an empty line.'))
  7618. ->setAllowedTypes(['array'])
  7619. ->setAllowedValues([new AllowedValueSubset(array_keys(self::$tokenMap))])
  7620. ->setDefault([
  7621. 'break',
  7622. 'continue',
  7623. 'declare',
  7624. 'return',
  7625. 'throw',
  7626. 'try',
  7627. ])
  7628. ->getOption(),
  7629. ]);
  7630. }
  7631. private function shouldAddBlankLine(Tokens $tokens, $prevNonWhitespace)
  7632. {
  7633. $prevNonWhitespaceToken = $tokens[$prevNonWhitespace];
  7634. if ($prevNonWhitespaceToken->isComment()) {
  7635. for ($j = $prevNonWhitespace - 1; $j >= 0; --$j) {
  7636. if (false !== strpos($tokens[$j]->getContent(), "\n")) {
  7637. return false;
  7638. }
  7639. if ($tokens[$j]->isWhitespace() || $tokens[$j]->isComment()) {
  7640. continue;
  7641. }
  7642. return $tokens[$j]->equalsAny([';', '}']);
  7643. }
  7644. }
  7645. return $prevNonWhitespaceToken->equalsAny([';', '}']);
  7646. }
  7647. private function insertBlankLine(Tokens $tokens, $index)
  7648. {
  7649. $prevIndex = $index - 1;
  7650. $prevToken = $tokens[$prevIndex];
  7651. $lineEnding = $this->whitespacesConfig->getLineEnding();
  7652. if ($prevToken->isWhitespace()) {
  7653. $newlinesCount = substr_count($prevToken->getContent(), "\n");
  7654. if (0 === $newlinesCount) {
  7655. $tokens[$prevIndex] = new Token([T_WHITESPACE, rtrim($prevToken->getContent(), " \t").$lineEnding.$lineEnding]);
  7656. } elseif (1 === $newlinesCount) {
  7657. $tokens[$prevIndex] = new Token([T_WHITESPACE, $lineEnding.$prevToken->getContent()]);
  7658. }
  7659. } else {
  7660. $tokens->insertAt($index, new Token([T_WHITESPACE, $lineEnding.$lineEnding]));
  7661. }
  7662. }
  7663. }
  7664. <?php
  7665. namespace PhpCsFixer\Fixer\Whitespace;
  7666. use PhpCsFixer\AbstractFixer;
  7667. use PhpCsFixer\FixerDefinition\CodeSample;
  7668. use PhpCsFixer\FixerDefinition\FixerDefinition;
  7669. use PhpCsFixer\Tokenizer\Tokens;
  7670. final class NoSpacesInsideParenthesisFixer extends AbstractFixer
  7671. {
  7672. public function getDefinition()
  7673. {
  7674. return new FixerDefinition(
  7675. 'There MUST NOT be a space after the opening parenthesis. There MUST NOT be a space before the closing parenthesis.',
  7676. [
  7677. new CodeSample("<?php\nif ( \$a ) {\n foo( );\n}\n"),
  7678. new CodeSample(
  7679. "<?php
  7680. function foo( \$bar, \$baz )
  7681. {
  7682. }\n"
  7683. ),
  7684. ]
  7685. );
  7686. }
  7687. public function getPriority()
  7688. {
  7689. return 2;
  7690. }
  7691. public function isCandidate(Tokens $tokens)
  7692. {
  7693. return $tokens->isTokenKindFound('(');
  7694. }
  7695. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  7696. {
  7697. foreach ($tokens as $index => $token) {
  7698. if (!$token->equals('(')) {
  7699. continue;
  7700. }
  7701. $prevIndex = $tokens->getPrevMeaningfulToken($index);
  7702. if (null !== $prevIndex && $tokens[$prevIndex]->isGivenKind(T_ARRAY)) {
  7703. continue;
  7704. }
  7705. $endIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $index);
  7706. if (!$tokens[$tokens->getNextNonWhitespace($index)]->isComment()) {
  7707. $this->removeSpaceAroundToken($tokens, $index + 1);
  7708. }
  7709. if (!$tokens[$tokens->getPrevMeaningfulToken($endIndex)]->equals(',')) {
  7710. $this->removeSpaceAroundToken($tokens, $endIndex - 1);
  7711. }
  7712. }
  7713. }
  7714. private function removeSpaceAroundToken(Tokens $tokens, $index)
  7715. {
  7716. $token = $tokens[$index];
  7717. if ($token->isWhitespace() && false === strpos($token->getContent(), "\n")) {
  7718. $tokens->clearAt($index);
  7719. }
  7720. }
  7721. }
  7722. <?php
  7723. namespace PhpCsFixer\Fixer\Whitespace;
  7724. use PhpCsFixer\AbstractFixer;
  7725. use PhpCsFixer\FixerDefinition\FixerDefinition;
  7726. use PhpCsFixer\FixerDefinition\VersionSpecification;
  7727. use PhpCsFixer\FixerDefinition\VersionSpecificCodeSample;
  7728. use PhpCsFixer\Tokenizer\CT;
  7729. use PhpCsFixer\Tokenizer\Tokens;
  7730. final class CompactNullableTypehintFixer extends AbstractFixer
  7731. {
  7732. public function getDefinition()
  7733. {
  7734. return new FixerDefinition(
  7735. 'Remove extra spaces in a nullable typehint.',
  7736. [
  7737. new VersionSpecificCodeSample(
  7738. "<?php\nfunction sample(? string \$str): ? string\n{}\n",
  7739. new VersionSpecification(70100)
  7740. ),
  7741. ],
  7742. 'Rule is applied only in a PHP 7.1+ environment.'
  7743. );
  7744. }
  7745. public function isCandidate(Tokens $tokens)
  7746. {
  7747. return \PHP_VERSION_ID >= 70100 && $tokens->isTokenKindFound(CT::T_NULLABLE_TYPE);
  7748. }
  7749. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  7750. {
  7751. static $typehintKinds = [
  7752. CT::T_ARRAY_TYPEHINT,
  7753. T_CALLABLE,
  7754. T_NS_SEPARATOR,
  7755. T_STRING,
  7756. ];
  7757. for ($index = $tokens->count() - 1; $index >= 0; --$index) {
  7758. if (!$tokens[$index]->isGivenKind(CT::T_NULLABLE_TYPE)) {
  7759. continue;
  7760. }
  7761. if (
  7762. $tokens[$index + 1]->isWhitespace() &&
  7763. $tokens[$index + 2]->isGivenKind($typehintKinds)
  7764. ) {
  7765. $tokens->removeTrailingWhitespace($index);
  7766. }
  7767. }
  7768. }
  7769. }
  7770. <?php
  7771. namespace PhpCsFixer\Fixer\Whitespace;
  7772. use PhpCsFixer\AbstractProxyFixer;
  7773. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  7774. use PhpCsFixer\Fixer\DeprecatedFixerInterface;
  7775. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  7776. final class NoExtraConsecutiveBlankLinesFixer extends AbstractProxyFixer implements ConfigurationDefinitionFixerInterface, DeprecatedFixerInterface, WhitespacesAwareFixerInterface
  7777. {
  7778. private $fixer;
  7779. public function getDefinition()
  7780. {
  7781. return $this->getFixer()->getDefinition();
  7782. }
  7783. public function configure(array $configuration = null)
  7784. {
  7785. $this->getFixer()->configure($configuration);
  7786. $this->configuration = $configuration;
  7787. }
  7788. public function getConfigurationDefinition()
  7789. {
  7790. return $this->getFixer()->getConfigurationDefinition();
  7791. }
  7792. public function getSuccessorsNames()
  7793. {
  7794. return array_keys($this->proxyFixers);
  7795. }
  7796. protected function createProxyFixers()
  7797. {
  7798. return [$this->getFixer()];
  7799. }
  7800. private function getFixer()
  7801. {
  7802. if (null === $this->fixer) {
  7803. $this->fixer = new NoExtraBlankLinesFixer();
  7804. }
  7805. return $this->fixer;
  7806. }
  7807. }
  7808. <?php
  7809. namespace PhpCsFixer\Fixer\Whitespace;
  7810. use PhpCsFixer\AbstractFixer;
  7811. use PhpCsFixer\ConfigurationException\InvalidConfigurationException;
  7812. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  7813. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  7814. use PhpCsFixer\FixerConfiguration\AllowedValueSubset;
  7815. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverRootless;
  7816. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  7817. use PhpCsFixer\FixerDefinition\CodeSample;
  7818. use PhpCsFixer\FixerDefinition\FixerDefinition;
  7819. use PhpCsFixer\Preg;
  7820. use PhpCsFixer\Tokenizer\CT;
  7821. use PhpCsFixer\Tokenizer\Token;
  7822. use PhpCsFixer\Tokenizer\Tokens;
  7823. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  7824. use Symfony\Component\OptionsResolver\Options;
  7825. final class NoExtraBlankLinesFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface, WhitespacesAwareFixerInterface
  7826. {
  7827. private static $availableTokens = [
  7828. 'break',
  7829. 'case',
  7830. 'continue',
  7831. 'curly_brace_block',
  7832. 'default',
  7833. 'extra',
  7834. 'parenthesis_brace_block',
  7835. 'return',
  7836. 'square_brace_block',
  7837. 'switch',
  7838. 'throw',
  7839. 'use',
  7840. 'useTrait',
  7841. 'use_trait',
  7842. ];
  7843. private $tokenKindCallbackMap;
  7844. private $tokenEqualsMap;
  7845. private $tokens;
  7846. private $tokensAnalyzer;
  7847. public function configure(array $configuration = null)
  7848. {
  7849. parent::configure($configuration);
  7850. static $reprToTokenMap = [
  7851. 'break' => T_BREAK,
  7852. 'case' => T_CASE,
  7853. 'continue' => T_CONTINUE,
  7854. 'curly_brace_block' => '{',
  7855. 'default' => T_DEFAULT,
  7856. 'extra' => T_WHITESPACE,
  7857. 'parenthesis_brace_block' => '(',
  7858. 'return' => T_RETURN,
  7859. 'square_brace_block' => CT::T_ARRAY_SQUARE_BRACE_OPEN,
  7860. 'switch' => T_SWITCH,
  7861. 'throw' => T_THROW,
  7862. 'use' => T_USE,
  7863. 'use_trait' => CT::T_USE_TRAIT,
  7864. ];
  7865. static $tokenKindCallbackMap = [
  7866. T_BREAK => 'fixAfterToken',
  7867. T_CASE => 'fixAfterToken',
  7868. T_CONTINUE => 'fixAfterToken',
  7869. T_DEFAULT => 'fixAfterToken',
  7870. T_RETURN => 'fixAfterToken',
  7871. T_SWITCH => 'fixAfterToken',
  7872. T_THROW => 'fixAfterToken',
  7873. T_USE => 'removeBetweenUse',
  7874. T_WHITESPACE => 'removeMultipleBlankLines',
  7875. CT::T_USE_TRAIT => 'removeBetweenUse',
  7876. CT::T_ARRAY_SQUARE_BRACE_OPEN => 'fixStructureOpenCloseIfMultiLine',
  7877. ];
  7878. static $tokenEqualsMap = [
  7879. '{' => 'fixStructureOpenCloseIfMultiLine',
  7880. '(' => 'fixStructureOpenCloseIfMultiLine',
  7881. ];
  7882. $tokensAssoc = array_flip(array_intersect_key($reprToTokenMap, array_flip($this->configuration['tokens'])));
  7883. $this->tokenKindCallbackMap = array_intersect_key($tokenKindCallbackMap, $tokensAssoc);
  7884. $this->tokenEqualsMap = array_intersect_key($tokenEqualsMap, $tokensAssoc);
  7885. }
  7886. public function getDefinition()
  7887. {
  7888. return new FixerDefinition(
  7889. 'Removes extra blank lines and/or blank lines following configuration.',
  7890. [
  7891. new CodeSample(
  7892. '<?php
  7893. $foo = array("foo");
  7894. $bar = "bar";
  7895. '
  7896. ),
  7897. new CodeSample(
  7898. '<?php
  7899. switch ($foo) {
  7900. case 41:
  7901. echo "foo";
  7902. break;
  7903. case 42:
  7904. break;
  7905. }
  7906. ',
  7907. ['tokens' => ['break']]
  7908. ),
  7909. new CodeSample(
  7910. '<?php
  7911. for ($i = 0; $i < 9000; ++$i) {
  7912. if (true) {
  7913. continue;
  7914. }
  7915. }
  7916. ',
  7917. ['tokens' => ['continue']]
  7918. ),
  7919. new CodeSample(
  7920. '<?php
  7921. for ($i = 0; $i < 9000; ++$i) {
  7922. echo $i;
  7923. }
  7924. ',
  7925. ['tokens' => ['curly_brace_block']]
  7926. ),
  7927. new CodeSample(
  7928. '<?php
  7929. $foo = array("foo");
  7930. $bar = "bar";
  7931. ',
  7932. ['tokens' => ['extra']]
  7933. ),
  7934. new CodeSample(
  7935. '<?php
  7936. $foo = array(
  7937. "foo"
  7938. );
  7939. ',
  7940. ['tokens' => ['parenthesis_brace_block']]
  7941. ),
  7942. new CodeSample(
  7943. '<?php
  7944. function foo($bar)
  7945. {
  7946. return $bar;
  7947. }
  7948. ',
  7949. ['tokens' => ['return']]
  7950. ),
  7951. new CodeSample(
  7952. '<?php
  7953. $foo = [
  7954. "foo"
  7955. ];
  7956. ',
  7957. ['tokens' => ['square_brace_block']]
  7958. ),
  7959. new CodeSample(
  7960. '<?php
  7961. function foo($bar)
  7962. {
  7963. throw new \Exception("Hello!");
  7964. }
  7965. ',
  7966. ['tokens' => ['throw']]
  7967. ),
  7968. new CodeSample(
  7969. '<?php
  7970. namespace Foo;
  7971. use Bar\Baz;
  7972. use Baz\Bar;
  7973. class Bar
  7974. {
  7975. }
  7976. ',
  7977. ['tokens' => ['use']]
  7978. ),
  7979. new CodeSample(
  7980. '<?php
  7981. class Foo
  7982. {
  7983. use Bar;
  7984. use Baz;
  7985. }
  7986. ',
  7987. ['tokens' => ['use_trait']]
  7988. ),
  7989. new CodeSample(
  7990. '<?php
  7991. switch($a) {
  7992. case 1:
  7993. default:
  7994. echo 3;
  7995. }
  7996. ',
  7997. ['tokens' => ['switch', 'case', 'default']]
  7998. ),
  7999. ]
  8000. );
  8001. }
  8002. public function getPriority()
  8003. {
  8004. return -20;
  8005. }
  8006. public function isCandidate(Tokens $tokens)
  8007. {
  8008. return true;
  8009. }
  8010. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  8011. {
  8012. $this->tokens = $tokens;
  8013. $this->tokensAnalyzer = new TokensAnalyzer($this->tokens);
  8014. for ($index = $tokens->getSize() - 1; $index > 0; --$index) {
  8015. $this->fixByToken($tokens[$index], $index);
  8016. }
  8017. }
  8018. protected function createConfigurationDefinition()
  8019. {
  8020. $that = $this;
  8021. return new FixerConfigurationResolverRootless('tokens', [
  8022. (new FixerOptionBuilder('tokens', 'List of tokens to fix.'))
  8023. ->setAllowedTypes(['array'])
  8024. ->setAllowedValues([new AllowedValueSubset(self::$availableTokens)])
  8025. ->setNormalizer(static function (Options $options, $tokens) use ($that) {
  8026. foreach ($tokens as &$token) {
  8027. if ('useTrait' === $token) {
  8028. $message = "Token \"useTrait\" in option \"tokens\" for rule \"{$that->getName()}\" is deprecated and will be removed in 3.0, use \"use_trait\" instead.";
  8029. if (getenv('PHP_CS_FIXER_FUTURE_MODE')) {
  8030. throw new InvalidConfigurationException("{$message} This check was performed as `PHP_CS_FIXER_FUTURE_MODE` env var is set.");
  8031. }
  8032. @trigger_error($message, E_USER_DEPRECATED);
  8033. $token = 'use_trait';
  8034. break;
  8035. }
  8036. }
  8037. return $tokens;
  8038. })
  8039. ->setDefault(['extra'])
  8040. ->getOption(),
  8041. ], $this->getName());
  8042. }
  8043. private function fixByToken(Token $token, $index)
  8044. {
  8045. foreach ($this->tokenKindCallbackMap as $kind => $callback) {
  8046. if (!$token->isGivenKind($kind)) {
  8047. continue;
  8048. }
  8049. $this->{$callback}($index);
  8050. return;
  8051. }
  8052. foreach ($this->tokenEqualsMap as $equals => $callback) {
  8053. if (!$token->equals($equals)) {
  8054. continue;
  8055. }
  8056. $this->{$callback}($index);
  8057. return;
  8058. }
  8059. }
  8060. private function removeBetweenUse($index)
  8061. {
  8062. $next = $this->tokens->getNextTokenOfKind($index, [';', [T_CLOSE_TAG]]);
  8063. if (null === $next || $this->tokens[$next]->isGivenKind(T_CLOSE_TAG)) {
  8064. return;
  8065. }
  8066. $nextUseCandidate = $this->tokens->getNextMeaningfulToken($next);
  8067. if (null === $nextUseCandidate || !$this->tokens[$nextUseCandidate]->isGivenKind($this->tokens[$index]->getId()) || !$this->containsLinebreak($index, $nextUseCandidate)) {
  8068. return;
  8069. }
  8070. return $this->removeEmptyLinesAfterLineWithTokenAt($next);
  8071. }
  8072. private function removeMultipleBlankLines($index)
  8073. {
  8074. $expected = $this->tokens[$index - 1]->isGivenKind(T_OPEN_TAG) && 1 === Preg::match('/\R$/', $this->tokens[$index - 1]->getContent()) ? 1 : 2;
  8075. $parts = Preg::split('/(.*\R)/', $this->tokens[$index]->getContent(), -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
  8076. $count = \count($parts);
  8077. if ($count > $expected) {
  8078. $this->tokens[$index] = new Token([T_WHITESPACE, implode('', \array_slice($parts, 0, $expected)).rtrim($parts[$count - 1], "\r\n")]);
  8079. }
  8080. }
  8081. private function fixAfterToken($index)
  8082. {
  8083. for ($i = $index - 1; $i > 0; --$i) {
  8084. if ($this->tokens[$i]->isGivenKind(T_FUNCTION) && $this->tokensAnalyzer->isLambda($i)) {
  8085. return;
  8086. }
  8087. if ($this->tokens[$i]->isGivenKind(T_CLASS) && $this->tokensAnalyzer->isAnonymousClass($i)) {
  8088. return;
  8089. }
  8090. if ($this->tokens[$i]->isWhitespace() && false !== strpos($this->tokens[$i]->getContent(), "\n")) {
  8091. break;
  8092. }
  8093. }
  8094. $this->removeEmptyLinesAfterLineWithTokenAt($index);
  8095. }
  8096. private function fixStructureOpenCloseIfMultiLine($index)
  8097. {
  8098. $blockTypeInfo = Tokens::detectBlockType($this->tokens[$index]);
  8099. $bodyEnd = $this->tokens->findBlockEnd($blockTypeInfo['type'], $index);
  8100. for ($i = $bodyEnd - 1; $i >= $index; --$i) {
  8101. if (false !== strpos($this->tokens[$i]->getContent(), "\n")) {
  8102. $this->removeEmptyLinesAfterLineWithTokenAt($i);
  8103. $this->removeEmptyLinesAfterLineWithTokenAt($index);
  8104. break;
  8105. }
  8106. }
  8107. }
  8108. private function removeEmptyLinesAfterLineWithTokenAt($index)
  8109. {
  8110. $tokenCount = \count($this->tokens);
  8111. for ($end = $index; $end < $tokenCount; ++$end) {
  8112. if (
  8113. $this->tokens[$end]->equals('}')
  8114. || false !== strpos($this->tokens[$end]->getContent(), "\n")
  8115. ) {
  8116. break;
  8117. }
  8118. }
  8119. if ($end === $tokenCount) {
  8120. return;
  8121. }
  8122. $ending = $this->whitespacesConfig->getLineEnding();
  8123. for ($i = $end; $i < $tokenCount && $this->tokens[$i]->isWhitespace(); ++$i) {
  8124. $content = $this->tokens[$i]->getContent();
  8125. if (substr_count($content, "\n") < 1) {
  8126. continue;
  8127. }
  8128. $pos = strrpos($content, "\n");
  8129. if ($pos + 2 <= \strlen($content)) {
  8130. $newContent = $ending.substr($content, $pos + 1);
  8131. } else {
  8132. $newContent = $ending;
  8133. }
  8134. $this->tokens[$i] = new Token([T_WHITESPACE, $newContent]);
  8135. }
  8136. }
  8137. private function containsLinebreak($startIndex, $endIndex)
  8138. {
  8139. for ($i = $endIndex; $i > $startIndex; --$i) {
  8140. if (Preg::match('/\R/', $this->tokens[$i]->getContent())) {
  8141. return true;
  8142. }
  8143. }
  8144. return false;
  8145. }
  8146. }
  8147. <?php
  8148. namespace PhpCsFixer\Fixer\Whitespace;
  8149. use PhpCsFixer\AbstractFixer;
  8150. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  8151. use PhpCsFixer\FixerDefinition\CodeSample;
  8152. use PhpCsFixer\FixerDefinition\FixerDefinition;
  8153. use PhpCsFixer\Preg;
  8154. use PhpCsFixer\Tokenizer\Token;
  8155. use PhpCsFixer\Tokenizer\Tokens;
  8156. /**
  8157. @gmail
  8158. */
  8159. final class LineEndingFixer extends AbstractFixer implements WhitespacesAwareFixerInterface
  8160. {
  8161. public function isCandidate(Tokens $tokens)
  8162. {
  8163. return true;
  8164. }
  8165. public function getDefinition()
  8166. {
  8167. return new FixerDefinition(
  8168. 'All PHP files must use same line ending.',
  8169. [
  8170. new CodeSample(
  8171. "<?php \$b = \" \$a \r\n 123\"; \$a = <<<TEST\r\nAAAAA \r\n |\r\nTEST;\n"
  8172. ),
  8173. ]
  8174. );
  8175. }
  8176. public function getPriority()
  8177. {
  8178. return 0;
  8179. }
  8180. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  8181. {
  8182. $ending = $this->whitespacesConfig->getLineEnding();
  8183. for ($index = 0, $count = \count($tokens); $index < $count; ++$index) {
  8184. $token = $tokens[$index];
  8185. if ($token->isGivenKind(T_ENCAPSED_AND_WHITESPACE)) {
  8186. if ($tokens[$tokens->getNextMeaningfulToken($index)]->isGivenKind(T_END_HEREDOC)) {
  8187. $tokens[$index] = new Token([
  8188. $token->getId(),
  8189. Preg::replace(
  8190. '#\R#',
  8191. $ending,
  8192. $token->getContent()
  8193. ),
  8194. ]);
  8195. }
  8196. continue;
  8197. }
  8198. if ($token->isGivenKind([T_CLOSE_TAG, T_COMMENT, T_DOC_COMMENT, T_OPEN_TAG, T_START_HEREDOC, T_WHITESPACE])) {
  8199. $tokens[$index] = new Token([
  8200. $token->getId(),
  8201. Preg::replace(
  8202. '#\R#',
  8203. $ending,
  8204. $token->getContent()
  8205. ),
  8206. ]);
  8207. }
  8208. }
  8209. }
  8210. }
  8211. <?php
  8212. namespace PhpCsFixer\Fixer\Whitespace;
  8213. use PhpCsFixer\AbstractFixer;
  8214. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  8215. use PhpCsFixer\FixerDefinition\CodeSample;
  8216. use PhpCsFixer\FixerDefinition\FixerDefinition;
  8217. use PhpCsFixer\Preg;
  8218. use PhpCsFixer\Tokenizer\Token;
  8219. use PhpCsFixer\Tokenizer\Tokens;
  8220. final class NoWhitespaceInBlankLineFixer extends AbstractFixer implements WhitespacesAwareFixerInterface
  8221. {
  8222. public function getDefinition()
  8223. {
  8224. return new FixerDefinition(
  8225. 'Remove trailing whitespace at the end of blank lines.',
  8226. [new CodeSample("<?php\n \n\$a = 1;\n")]
  8227. );
  8228. }
  8229. public function getPriority()
  8230. {
  8231. return -19;
  8232. }
  8233. public function isCandidate(Tokens $tokens)
  8234. {
  8235. return true;
  8236. }
  8237. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  8238. {
  8239. for ($i = 1, $count = \count($tokens); $i < $count; ++$i) {
  8240. if ($tokens[$i]->isWhitespace()) {
  8241. $this->fixWhitespaceToken($tokens, $i);
  8242. }
  8243. }
  8244. }
  8245. private function fixWhitespaceToken(Tokens $tokens, $index)
  8246. {
  8247. $content = $tokens[$index]->getContent();
  8248. $lines = Preg::split("/(\r\n|\n)/", $content);
  8249. $lineCount = \count($lines);
  8250. if (
  8251. $lineCount > 2
  8252. || ($lineCount > 0 && (!isset($tokens[$index + 1]) || $tokens[$index - 1]->isGivenKind(T_OPEN_TAG)))
  8253. ) {
  8254. $lMax = isset($tokens[$index + 1]) ? $lineCount - 1 : $lineCount;
  8255. $lStart = 1;
  8256. if ($tokens[$index - 1]->isGivenKind(T_OPEN_TAG) && "\n" === substr($tokens[$index - 1]->getContent(), -1)) {
  8257. $lStart = 0;
  8258. }
  8259. for ($l = $lStart; $l < $lMax; ++$l) {
  8260. $lines[$l] = Preg::replace('/^\h+$/', '', $lines[$l]);
  8261. }
  8262. $content = implode($this->whitespacesConfig->getLineEnding(), $lines);
  8263. if ('' !== $content) {
  8264. $tokens[$index] = new Token([T_WHITESPACE, $content]);
  8265. } else {
  8266. $tokens->clearAt($index);
  8267. }
  8268. }
  8269. }
  8270. }
  8271. <?php
  8272. namespace PhpCsFixer\Fixer\Whitespace;
  8273. use PhpCsFixer\AbstractFixer;
  8274. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  8275. use PhpCsFixer\FixerDefinition\FixerDefinition;
  8276. use PhpCsFixer\FixerDefinition\VersionSpecification;
  8277. use PhpCsFixer\FixerDefinition\VersionSpecificCodeSample;
  8278. use PhpCsFixer\Preg;
  8279. use PhpCsFixer\Tokenizer\Token;
  8280. use PhpCsFixer\Tokenizer\Tokens;
  8281. final class HeredocIndentationFixer extends AbstractFixer implements WhitespacesAwareFixerInterface
  8282. {
  8283. public function getDefinition()
  8284. {
  8285. return new FixerDefinition(
  8286. 'Heredoc/nowdoc content must be properly indented. Requires PHP >= 7.3.',
  8287. [
  8288. new VersionSpecificCodeSample(
  8289. <<<'SAMPLE'
  8290. <?php
  8291. $a = <<<EOD
  8292. abc
  8293. def
  8294. EOD;
  8295. SAMPLE
  8296. ,
  8297. new VersionSpecification(70300)
  8298. ),
  8299. new VersionSpecificCodeSample(
  8300. <<<'SAMPLE'
  8301. <?php
  8302. $a = <<<'EOD'
  8303. abc
  8304. def
  8305. EOD;
  8306. SAMPLE
  8307. ,
  8308. new VersionSpecification(70300)
  8309. ),
  8310. ]
  8311. );
  8312. }
  8313. public function isCandidate(Tokens $tokens)
  8314. {
  8315. return \PHP_VERSION_ID >= 70300 && $tokens->isTokenKindFound(T_START_HEREDOC);
  8316. }
  8317. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  8318. {
  8319. for ($index = \count($tokens) - 1; 0 <= $index; --$index) {
  8320. if (!$tokens[$index]->isGivenKind(T_END_HEREDOC)) {
  8321. continue;
  8322. }
  8323. $end = $index;
  8324. $index = $tokens->getPrevTokenOfKind($index, [[T_START_HEREDOC]]);
  8325. $this->fixIndentation($tokens, $index, $end);
  8326. }
  8327. }
  8328. private function fixIndentation(Tokens $tokens, $start, $end)
  8329. {
  8330. $indent = $this->getIndentAt($tokens, $start).$this->whitespacesConfig->getIndent();
  8331. Preg::match('/^\h*/', $tokens[$end]->getContent(), $matches);
  8332. $currentIndent = $matches[0];
  8333. $currentIndentLength = \strlen($currentIndent);
  8334. $content = $indent.substr($tokens[$end]->getContent(), $currentIndentLength);
  8335. $tokens[$end] = new Token([T_END_HEREDOC, $content]);
  8336. if ($end === $start + 1) {
  8337. return;
  8338. }
  8339. for ($index = $end - 1, $last = true; $index > $start; --$index, $last = false) {
  8340. if (!$tokens[$index]->isGivenKind([T_ENCAPSED_AND_WHITESPACE, T_WHITESPACE])) {
  8341. continue;
  8342. }
  8343. $content = $tokens[$index]->getContent();
  8344. if ('' !== $currentIndent) {
  8345. $content = Preg::replace('/(?<=\v)(?!'.$currentIndent.')\h+/', '', $content);
  8346. }
  8347. $regexEnd = $last && !$currentIndent ? '(?!\v|$)' : '(?!\v)';
  8348. $content = Preg::replace('/(?<=\v)'.$currentIndent.$regexEnd.'/', $indent, $content);
  8349. $tokens[$index] = new Token([$tokens[$index]->getId(), $content]);
  8350. }
  8351. ++$index;
  8352. if (!$tokens[$index]->isGivenKind(T_ENCAPSED_AND_WHITESPACE)) {
  8353. $tokens->insertAt($index, new Token([T_ENCAPSED_AND_WHITESPACE, $indent]));
  8354. return;
  8355. }
  8356. $content = $tokens[$index]->getContent();
  8357. if (!\in_array($content[0], ["\r", "\n"], true) && (!$currentIndent || $currentIndent === substr($content, 0, $currentIndentLength))) {
  8358. $content = $indent.substr($content, $currentIndentLength);
  8359. } elseif ($currentIndent) {
  8360. $content = Preg::replace('/^(?!'.$currentIndent.')\h+/', '', $content);
  8361. }
  8362. $tokens[$index] = new Token([T_ENCAPSED_AND_WHITESPACE, $content]);
  8363. }
  8364. private function getIndentAt(Tokens $tokens, $index)
  8365. {
  8366. for (; $index >= 0; --$index) {
  8367. if (!$tokens[$index]->isGivenKind([T_WHITESPACE, T_INLINE_HTML, T_OPEN_TAG])) {
  8368. continue;
  8369. }
  8370. $content = $tokens[$index]->getContent();
  8371. if ($tokens[$index]->isWhitespace() && $tokens[$index - 1]->isGivenKind(T_OPEN_TAG)) {
  8372. $content = $tokens[$index - 1]->getContent().$content;
  8373. }
  8374. if (1 === Preg::match('/\R(\h*)$/', $content, $matches)) {
  8375. return $matches[1];
  8376. }
  8377. }
  8378. return '';
  8379. }
  8380. }
  8381. <?php
  8382. namespace PhpCsFixer\Fixer\Whitespace;
  8383. use PhpCsFixer\AbstractFixer;
  8384. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  8385. use PhpCsFixer\FixerDefinition\CodeSample;
  8386. use PhpCsFixer\FixerDefinition\FixerDefinition;
  8387. use PhpCsFixer\Preg;
  8388. use PhpCsFixer\Tokenizer\CT;
  8389. use PhpCsFixer\Tokenizer\Token;
  8390. use PhpCsFixer\Tokenizer\Tokens;
  8391. final class ArrayIndentationFixer extends AbstractFixer implements WhitespacesAwareFixerInterface
  8392. {
  8393. public function getDefinition()
  8394. {
  8395. return new FixerDefinition(
  8396. 'Each element of an array must be indented exactly once.',
  8397. [
  8398. new CodeSample("<?php\n\$foo = [\n 'bar' => [\n 'baz' => true,\n ],\n];\n"),
  8399. ]
  8400. );
  8401. }
  8402. public function isCandidate(Tokens $tokens)
  8403. {
  8404. return $tokens->isAnyTokenKindsFound([T_ARRAY, CT::T_ARRAY_SQUARE_BRACE_OPEN]);
  8405. }
  8406. public function getPriority()
  8407. {
  8408. return -31;
  8409. }
  8410. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  8411. {
  8412. foreach ($this->findArrays($tokens) as $array) {
  8413. $indentLevel = 1;
  8414. $scopes = [[
  8415. 'opening_braces' => $array['start_braces']['opening'],
  8416. 'unindented' => false,
  8417. ]];
  8418. $currentScope = 0;
  8419. $arrayIndent = $this->getLineIndentation($tokens, $array['start']);
  8420. $previousLineInitialIndent = $arrayIndent;
  8421. $previousLineNewIndent = $arrayIndent;
  8422. foreach ($array['braces'] as $index => $braces) {
  8423. $currentIndentLevel = $indentLevel;
  8424. if (
  8425. $braces['starts_with_closing']
  8426. && !$scopes[$currentScope]['unindented']
  8427. && !$this->isClosingLineWithMeaningfulContent($tokens, $index)
  8428. ) {
  8429. --$currentIndentLevel;
  8430. }
  8431. $token = $tokens[$index];
  8432. if ($this->newlineIsInArrayScope($tokens, $index, $array)) {
  8433. $content = Preg::replace(
  8434. '/(\R+)\h*$/',
  8435. '$1'.$arrayIndent.str_repeat($this->whitespacesConfig->getIndent(), $currentIndentLevel),
  8436. $token->getContent()
  8437. );
  8438. $previousLineInitialIndent = $this->extractIndent($token->getContent());
  8439. $previousLineNewIndent = $this->extractIndent($content);
  8440. } else {
  8441. $content = Preg::replace(
  8442. '/(\R)'.preg_quote($previousLineInitialIndent, '/').'(\h*)$/',
  8443. '$1'.$previousLineNewIndent.'$2',
  8444. $token->getContent()
  8445. );
  8446. }
  8447. $closingBraces = $braces['closing'];
  8448. while ($closingBraces-- > 0) {
  8449. if (!$scopes[$currentScope]['unindented']) {
  8450. --$indentLevel;
  8451. $scopes[$currentScope]['unindented'] = true;
  8452. }
  8453. if (0 === --$scopes[$currentScope]['opening_braces']) {
  8454. array_pop($scopes);
  8455. --$currentScope;
  8456. }
  8457. }
  8458. if ($braces['opening'] > 0) {
  8459. $scopes[] = [
  8460. 'opening_braces' => $braces['opening'],
  8461. 'unindented' => false,
  8462. ];
  8463. ++$indentLevel;
  8464. ++$currentScope;
  8465. }
  8466. $tokens[$index] = new Token([T_WHITESPACE, $content]);
  8467. }
  8468. }
  8469. }
  8470. private function findArrays(Tokens $tokens)
  8471. {
  8472. $arrays = [];
  8473. foreach ($this->findArrayTokenRanges($tokens, 0, \count($tokens) - 1) as $arrayTokenRanges) {
  8474. $array = [
  8475. 'start' => $arrayTokenRanges[0][0],
  8476. 'end' => $arrayTokenRanges[\count($arrayTokenRanges) - 1][1],
  8477. 'token_ranges' => $arrayTokenRanges,
  8478. ];
  8479. $array['start_braces'] = $this->getLineSignificantBraces($tokens, $array['start'] - 1, $array);
  8480. $array['braces'] = $this->computeArrayLineSignificantBraces($tokens, $array);
  8481. $arrays[] = $array;
  8482. }
  8483. return $arrays;
  8484. }
  8485. private function findArrayTokenRanges(Tokens $tokens, $from, $to)
  8486. {
  8487. $arrayTokenRanges = [];
  8488. $currentArray = null;
  8489. $valueSinceIndex = null;
  8490. for ($index = $from; $index <= $to; ++$index) {
  8491. $token = $tokens[$index];
  8492. if ($token->isGivenKind([T_ARRAY, CT::T_ARRAY_SQUARE_BRACE_OPEN])) {
  8493. $arrayStartIndex = $index;
  8494. if ($token->isGivenKind(T_ARRAY)) {
  8495. $index = $tokens->getNextTokenOfKind($index, ['(']);
  8496. }
  8497. $endIndex = $tokens->findBlockEnd(
  8498. $tokens[$index]->equals('(') ? Tokens::BLOCK_TYPE_PARENTHESIS_BRACE : Tokens::BLOCK_TYPE_ARRAY_SQUARE_BRACE,
  8499. $index
  8500. );
  8501. if (null === $currentArray) {
  8502. $currentArray = [
  8503. 'start' => $index,
  8504. 'end' => $endIndex,
  8505. 'ignored_tokens_ranges' => [],
  8506. ];
  8507. } else {
  8508. if (null === $valueSinceIndex) {
  8509. $valueSinceIndex = $arrayStartIndex;
  8510. }
  8511. $index = $endIndex;
  8512. }
  8513. continue;
  8514. }
  8515. if (null === $currentArray || $token->isWhitespace() || $token->isComment()) {
  8516. continue;
  8517. }
  8518. if ($currentArray['end'] === $index) {
  8519. if (null !== $valueSinceIndex) {
  8520. $currentArray['ignored_tokens_ranges'][] = [$valueSinceIndex, $tokens->getPrevMeaningfulToken($index)];
  8521. $valueSinceIndex = null;
  8522. }
  8523. $rangeIndexes = [$currentArray['start']];
  8524. foreach ($currentArray['ignored_tokens_ranges'] as list($start, $end)) {
  8525. $rangeIndexes[] = $start - 1;
  8526. $rangeIndexes[] = $end + 1;
  8527. }
  8528. $rangeIndexes[] = $currentArray['end'];
  8529. $arrayTokenRanges[] = array_chunk($rangeIndexes, 2);
  8530. foreach ($currentArray['ignored_tokens_ranges'] as list($start, $end)) {
  8531. foreach ($this->findArrayTokenRanges($tokens, $start, $end) as $nestedArray) {
  8532. $arrayTokenRanges[] = $nestedArray;
  8533. }
  8534. }
  8535. $currentArray = null;
  8536. continue;
  8537. }
  8538. if (null === $valueSinceIndex) {
  8539. $valueSinceIndex = $index;
  8540. }
  8541. if (
  8542. ($token->equals('(') && !$tokens[$tokens->getPrevMeaningfulToken($index)]->isGivenKind(T_ARRAY))
  8543. || $token->equals('{')
  8544. ) {
  8545. $index = $tokens->findBlockEnd(
  8546. $token->equals('{') ? Tokens::BLOCK_TYPE_CURLY_BRACE : Tokens::BLOCK_TYPE_PARENTHESIS_BRACE,
  8547. $index
  8548. );
  8549. }
  8550. if ($token->equals(',')) {
  8551. $currentArray['ignored_tokens_ranges'][] = [$valueSinceIndex, $tokens->getPrevMeaningfulToken($index)];
  8552. $valueSinceIndex = null;
  8553. }
  8554. }
  8555. return $arrayTokenRanges;
  8556. }
  8557. private function computeArrayLineSignificantBraces(Tokens $tokens, array $array)
  8558. {
  8559. $braces = [];
  8560. for ($index = $array['start']; $index <= $array['end']; ++$index) {
  8561. if (!$this->isNewLineToken($tokens, $index)) {
  8562. continue;
  8563. }
  8564. $braces[$index] = $this->getLineSignificantBraces($tokens, $index, $array);
  8565. }
  8566. return $braces;
  8567. }
  8568. private function getLineSignificantBraces(Tokens $tokens, $index, array $array)
  8569. {
  8570. $deltas = [];
  8571. for (++$index; $index <= $array['end']; ++$index) {
  8572. if ($this->isNewLineToken($tokens, $index)) {
  8573. break;
  8574. }
  8575. if (!$this->indexIsInArrayTokenRanges($index, $array)) {
  8576. continue;
  8577. }
  8578. $token = $tokens[$index];
  8579. if ($token->equals('(') && !$tokens[$tokens->getPrevMeaningfulToken($index)]->isGivenKind(T_ARRAY)) {
  8580. continue;
  8581. }
  8582. if ($token->equals(')')) {
  8583. $openBraceIndex = $tokens->findBlockStart(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $index);
  8584. if (!$tokens[$tokens->getPrevMeaningfulToken($openBraceIndex)]->isGivenKind(T_ARRAY)) {
  8585. continue;
  8586. }
  8587. }
  8588. if ($token->equalsAny(['(', [CT::T_ARRAY_SQUARE_BRACE_OPEN]])) {
  8589. $deltas[] = 1;
  8590. continue;
  8591. }
  8592. if ($token->equalsAny([')', [CT::T_ARRAY_SQUARE_BRACE_CLOSE]])) {
  8593. $deltas[] = -1;
  8594. }
  8595. }
  8596. $braces = [
  8597. 'opening' => 0,
  8598. 'closing' => 0,
  8599. 'starts_with_closing' => -1 === reset($deltas),
  8600. ];
  8601. foreach ($deltas as $delta) {
  8602. if (1 === $delta) {
  8603. ++$braces['opening'];
  8604. } elseif ($braces['opening'] > 0) {
  8605. --$braces['opening'];
  8606. } else {
  8607. ++$braces['closing'];
  8608. }
  8609. }
  8610. return $braces;
  8611. }
  8612. private function isClosingLineWithMeaningfulContent(Tokens $tokens, $newLineIndex)
  8613. {
  8614. $nextMeaningfulIndex = $tokens->getNextMeaningfulToken($newLineIndex);
  8615. return !$tokens[$nextMeaningfulIndex]->equalsAny([')', [CT::T_ARRAY_SQUARE_BRACE_CLOSE]]);
  8616. }
  8617. private function getLineIndentation(Tokens $tokens, $index)
  8618. {
  8619. $newlineTokenIndex = $this->getPreviousNewlineTokenIndex($tokens, $index);
  8620. if (null === $newlineTokenIndex) {
  8621. return '';
  8622. }
  8623. return $this->extractIndent($this->computeNewLineContent($tokens, $newlineTokenIndex));
  8624. }
  8625. private function extractIndent($content)
  8626. {
  8627. if (Preg::match('/\R(\h*)[^\r\n]*$/D', $content, $matches)) {
  8628. return $matches[1];
  8629. }
  8630. return '';
  8631. }
  8632. private function getPreviousNewlineTokenIndex(Tokens $tokens, $index)
  8633. {
  8634. while ($index > 0) {
  8635. $index = $tokens->getPrevTokenOfKind($index, [[T_WHITESPACE], [T_INLINE_HTML]]);
  8636. if (null === $index) {
  8637. break;
  8638. }
  8639. if ($this->isNewLineToken($tokens, $index)) {
  8640. return $index;
  8641. }
  8642. }
  8643. return null;
  8644. }
  8645. private function newlineIsInArrayScope(Tokens $tokens, $index, array $array)
  8646. {
  8647. if ($tokens[$tokens->getPrevMeaningfulToken($index)]->equalsAny(['.', '?', ':'])) {
  8648. return false;
  8649. }
  8650. $nextToken = $tokens[$tokens->getNextMeaningfulToken($index)];
  8651. if ($nextToken->isGivenKind(T_OBJECT_OPERATOR) || $nextToken->equalsAny(['.', '?', ':'])) {
  8652. return false;
  8653. }
  8654. return $this->indexIsInArrayTokenRanges($index, $array);
  8655. }
  8656. private function indexIsInArrayTokenRanges($index, array $array)
  8657. {
  8658. foreach ($array['token_ranges'] as list($start, $end)) {
  8659. if ($index < $start) {
  8660. return false;
  8661. }
  8662. if ($index <= $end) {
  8663. return true;
  8664. }
  8665. }
  8666. return false;
  8667. }
  8668. private function isNewLineToken(Tokens $tokens, $index)
  8669. {
  8670. if (!$tokens[$index]->equalsAny([[T_WHITESPACE], [T_INLINE_HTML]])) {
  8671. return false;
  8672. }
  8673. return (bool) Preg::match('/\R/', $this->computeNewLineContent($tokens, $index));
  8674. }
  8675. private function computeNewLineContent(Tokens $tokens, $index)
  8676. {
  8677. $content = $tokens[$index]->getContent();
  8678. if (0 !== $index && $tokens[$index - 1]->equalsAny([[T_OPEN_TAG], [T_CLOSE_TAG]])) {
  8679. $content = Preg::replace('/\S/', '', $tokens[$index - 1]->getContent()).$content;
  8680. }
  8681. return $content;
  8682. }
  8683. }
  8684. <?php
  8685. namespace PhpCsFixer\Fixer\Strict;
  8686. use PhpCsFixer\AbstractFixer;
  8687. use PhpCsFixer\FixerDefinition\CodeSample;
  8688. use PhpCsFixer\FixerDefinition\FixerDefinition;
  8689. use PhpCsFixer\Tokenizer\CT;
  8690. use PhpCsFixer\Tokenizer\Token;
  8691. use PhpCsFixer\Tokenizer\Tokens;
  8692. final class StrictParamFixer extends AbstractFixer
  8693. {
  8694. public function getDefinition()
  8695. {
  8696. return new FixerDefinition(
  8697. 'Functions should be used with `$strict` param set to `true`.',
  8698. [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")],
  8699. 'The functions "array_keys", "array_search", "base64_decode", "in_array" and "mb_detect_encoding" should be used with $strict param.',
  8700. 'Risky when the fixed function is overridden or if the code relies on non-strict usage.'
  8701. );
  8702. }
  8703. public function isCandidate(Tokens $tokens)
  8704. {
  8705. return $tokens->isTokenKindFound(T_STRING);
  8706. }
  8707. public function isRisky()
  8708. {
  8709. return true;
  8710. }
  8711. public function getPriority()
  8712. {
  8713. return 11;
  8714. }
  8715. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  8716. {
  8717. static $map = null;
  8718. if (null === $map) {
  8719. $trueToken = new Token([T_STRING, 'true']);
  8720. $map = [
  8721. 'array_keys' => [null, null, $trueToken],
  8722. 'array_search' => [null, null, $trueToken],
  8723. 'base64_decode' => [null, $trueToken],
  8724. 'in_array' => [null, null, $trueToken],
  8725. 'mb_detect_encoding' => [null, [new Token([T_STRING, 'mb_detect_order']), new Token('('), new Token(')')], $trueToken],
  8726. ];
  8727. }
  8728. for ($index = $tokens->count() - 1; 0 <= $index; --$index) {
  8729. $token = $tokens[$index];
  8730. $nextIndex = $tokens->getNextMeaningfulToken($index);
  8731. if (null !== $nextIndex && !$tokens[$nextIndex]->equals('(')) {
  8732. continue;
  8733. }
  8734. $lowercaseContent = strtolower($token->getContent());
  8735. if ($token->isGivenKind(T_STRING) && isset($map[$lowercaseContent])) {
  8736. $this->fixFunction($tokens, $index, $map[$lowercaseContent]);
  8737. }
  8738. }
  8739. }
  8740. private function fixFunction(Tokens $tokens, $functionIndex, array $functionParams)
  8741. {
  8742. $startBraceIndex = $tokens->getNextTokenOfKind($functionIndex, ['(']);
  8743. $endBraceIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $startBraceIndex);
  8744. $paramsQuantity = 0;
  8745. $expectParam = true;
  8746. for ($index = $startBraceIndex + 1; $index < $endBraceIndex; ++$index) {
  8747. $token = $tokens[$index];
  8748. if ($expectParam && !$token->isWhitespace() && !$token->isComment()) {
  8749. ++$paramsQuantity;
  8750. $expectParam = false;
  8751. }
  8752. if ($token->equals('(')) {
  8753. $index = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $index);
  8754. continue;
  8755. }
  8756. if ($token->isGivenKind(CT::T_ARRAY_SQUARE_BRACE_OPEN)) {
  8757. $index = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_ARRAY_SQUARE_BRACE, $index);
  8758. continue;
  8759. }
  8760. if ($token->equals(',')) {
  8761. $expectParam = true;
  8762. continue;
  8763. }
  8764. }
  8765. $functionParamsQuantity = \count($functionParams);
  8766. if ($paramsQuantity === $functionParamsQuantity) {
  8767. return;
  8768. }
  8769. $tokensToInsert = [];
  8770. for ($i = $paramsQuantity; $i < $functionParamsQuantity; ++$i) {
  8771. if (!$functionParams[$i]) {
  8772. return;
  8773. }
  8774. $tokensToInsert[] = new Token(',');
  8775. $tokensToInsert[] = new Token([T_WHITESPACE, ' ']);
  8776. if (!\is_array($functionParams[$i])) {
  8777. $tokensToInsert[] = clone $functionParams[$i];
  8778. continue;
  8779. }
  8780. foreach ($functionParams[$i] as $param) {
  8781. $tokensToInsert[] = clone $param;
  8782. }
  8783. }
  8784. $beforeEndBraceIndex = $tokens->getTokenNotOfKindSibling($endBraceIndex, -1, [[T_WHITESPACE], ',']);
  8785. $tokens->insertAt($beforeEndBraceIndex + 1, $tokensToInsert);
  8786. }
  8787. }
  8788. <?php
  8789. namespace PhpCsFixer\Fixer\Strict;
  8790. use PhpCsFixer\AbstractFixer;
  8791. use PhpCsFixer\FixerDefinition\CodeSample;
  8792. use PhpCsFixer\FixerDefinition\FixerDefinition;
  8793. use PhpCsFixer\Tokenizer\Token;
  8794. use PhpCsFixer\Tokenizer\Tokens;
  8795. final class StrictComparisonFixer extends AbstractFixer
  8796. {
  8797. public function getDefinition()
  8798. {
  8799. return new FixerDefinition(
  8800. 'Comparisons should be strict.',
  8801. [new CodeSample("<?php\n\$a = 1== \$b;\n")],
  8802. null,
  8803. 'Changing comparisons to strict might change code behavior.'
  8804. );
  8805. }
  8806. public function getPriority()
  8807. {
  8808. return 0;
  8809. }
  8810. public function isCandidate(Tokens $tokens)
  8811. {
  8812. return $tokens->isAnyTokenKindsFound([T_IS_EQUAL, T_IS_NOT_EQUAL]);
  8813. }
  8814. public function isRisky()
  8815. {
  8816. return true;
  8817. }
  8818. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  8819. {
  8820. static $map = [
  8821. T_IS_EQUAL => [
  8822. 'id' => T_IS_IDENTICAL,
  8823. 'content' => '===',
  8824. ],
  8825. T_IS_NOT_EQUAL => [
  8826. 'id' => T_IS_NOT_IDENTICAL,
  8827. 'content' => '!==',
  8828. ],
  8829. ];
  8830. foreach ($tokens as $index => $token) {
  8831. $tokenId = $token->getId();
  8832. if (isset($map[$tokenId])) {
  8833. $tokens[$index] = new Token([$map[$tokenId]['id'], $map[$tokenId]['content']]);
  8834. }
  8835. }
  8836. }
  8837. }
  8838. <?php
  8839. namespace PhpCsFixer\Fixer\Strict;
  8840. use PhpCsFixer\AbstractFixer;
  8841. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  8842. use PhpCsFixer\FixerDefinition\FixerDefinition;
  8843. use PhpCsFixer\FixerDefinition\VersionSpecification;
  8844. use PhpCsFixer\FixerDefinition\VersionSpecificCodeSample;
  8845. use PhpCsFixer\Tokenizer\Token;
  8846. use PhpCsFixer\Tokenizer\Tokens;
  8847. final class DeclareStrictTypesFixer extends AbstractFixer implements WhitespacesAwareFixerInterface
  8848. {
  8849. public function getDefinition()
  8850. {
  8851. return new FixerDefinition(
  8852. 'Force strict types declaration in all files. Requires PHP >= 7.0.',
  8853. [
  8854. new VersionSpecificCodeSample(
  8855. "<?php\n",
  8856. new VersionSpecification(70000)
  8857. ),
  8858. ],
  8859. null,
  8860. 'Forcing strict types will stop non strict code from working.'
  8861. );
  8862. }
  8863. public function getPriority()
  8864. {
  8865. return 2;
  8866. }
  8867. public function isCandidate(Tokens $tokens)
  8868. {
  8869. return \PHP_VERSION_ID >= 70000 && isset($tokens[0]) && $tokens[0]->isGivenKind(T_OPEN_TAG);
  8870. }
  8871. public function isRisky()
  8872. {
  8873. return true;
  8874. }
  8875. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  8876. {
  8877. $searchIndex = $tokens->getNextMeaningfulToken(0);
  8878. if (null === $searchIndex) {
  8879. $this->insertSequence($tokens);
  8880. return;
  8881. }
  8882. $sequenceLocation = $tokens->findSequence([[T_DECLARE, 'declare'], '(', [T_STRING, 'strict_types'], '=', [T_LNUMBER], ')'], $searchIndex, null, false);
  8883. if (null === $sequenceLocation) {
  8884. $this->insertSequence($tokens);
  8885. return;
  8886. }
  8887. $this->fixStrictTypesCasingAndValue($tokens, $sequenceLocation);
  8888. }
  8889. private function fixStrictTypesCasingAndValue(Tokens $tokens, array $sequence)
  8890. {
  8891. foreach ($sequence as $index => $token) {
  8892. if ($token->isGivenKind(T_STRING)) {
  8893. $tokens[$index] = new Token([T_STRING, strtolower($token->getContent())]);
  8894. continue;
  8895. }
  8896. if ($token->isGivenKind(T_LNUMBER)) {
  8897. $tokens[$index] = new Token([T_LNUMBER, '1']);
  8898. break;
  8899. }
  8900. }
  8901. }
  8902. private function insertSequence(Tokens $tokens)
  8903. {
  8904. $sequence = [
  8905. new Token([T_DECLARE, 'declare']),
  8906. new Token('('),
  8907. new Token([T_STRING, 'strict_types']),
  8908. new Token('='),
  8909. new Token([T_LNUMBER, '1']),
  8910. new Token(')'),
  8911. new Token(';'),
  8912. ];
  8913. $endIndex = \count($sequence);
  8914. $tokens->insertAt(1, $sequence);
  8915. if (false !== strpos($tokens[0]->getContent(), "\n")) {
  8916. $tokens[0] = new Token([$tokens[0]->getId(), trim($tokens[0]->getContent()).' ']);
  8917. }
  8918. if ($endIndex === \count($tokens) - 1) {
  8919. return;
  8920. }
  8921. $lineEnding = $this->whitespacesConfig->getLineEnding();
  8922. if (!$tokens[1 + $endIndex]->isWhitespace()) {
  8923. $tokens->insertAt(1 + $endIndex, new Token([T_WHITESPACE, $lineEnding]));
  8924. return;
  8925. }
  8926. $content = $tokens[1 + $endIndex]->getContent();
  8927. $tokens[1 + $endIndex] = new Token([T_WHITESPACE, $lineEnding.ltrim($content, " \t")]);
  8928. }
  8929. }
  8930. <?php
  8931. namespace PhpCsFixer\Fixer\DoctrineAnnotation;
  8932. use Doctrine\Common\Annotations\DocLexer;
  8933. use PhpCsFixer\AbstractDoctrineAnnotationFixer;
  8934. use PhpCsFixer\Doctrine\Annotation\Token;
  8935. use PhpCsFixer\Doctrine\Annotation\Tokens;
  8936. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  8937. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  8938. use PhpCsFixer\FixerDefinition\CodeSample;
  8939. use PhpCsFixer\FixerDefinition\FixerDefinition;
  8940. use PhpCsFixer\Preg;
  8941. final class DoctrineAnnotationSpacesFixer extends AbstractDoctrineAnnotationFixer
  8942. {
  8943. public function getDefinition()
  8944. {
  8945. return new FixerDefinition(
  8946. 'Fixes spaces in Doctrine annotations.',
  8947. [
  8948. new CodeSample(
  8949. "<?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"
  8950. ),
  8951. new CodeSample(
  8952. "<?php\n/**\n * @Foo(foo = \"foo\", bar = {\"foo\":\"foo\", \"bar\"=\"bar\"})\n */\nclass Bar {}\n",
  8953. ['after_array_assignments_equals' => false, 'before_array_assignments_equals' => false]
  8954. ),
  8955. ],
  8956. '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.'
  8957. );
  8958. }
  8959. public function getPriority()
  8960. {
  8961. return 0;
  8962. }
  8963. public function configure(array $configuration = null)
  8964. {
  8965. parent::configure($configuration);
  8966. if (!$this->configuration['around_argument_assignments']) {
  8967. foreach ([
  8968. 'before_argument_assignments',
  8969. 'after_argument_assignments',
  8970. ] as $newOption) {
  8971. if (!\array_key_exists($newOption, $configuration)) {
  8972. $this->configuration[$newOption] = null;
  8973. }
  8974. }
  8975. }
  8976. if (!$this->configuration['around_array_assignments']) {
  8977. foreach ([
  8978. 'before_array_assignments_equals',
  8979. 'after_array_assignments_equals',
  8980. 'before_array_assignments_colon',
  8981. 'after_array_assignments_colon',
  8982. ] as $newOption) {
  8983. if (!\array_key_exists($newOption, $configuration)) {
  8984. $this->configuration[$newOption] = null;
  8985. }
  8986. }
  8987. }
  8988. }
  8989. protected function createConfigurationDefinition()
  8990. {
  8991. return new FixerConfigurationResolver(array_merge(
  8992. parent::createConfigurationDefinition()->getOptions(),
  8993. [
  8994. (new FixerOptionBuilder('around_parentheses', 'Whether to fix spaces around parentheses.'))
  8995. ->setAllowedTypes(['bool'])
  8996. ->setDefault(true)
  8997. ->getOption(),
  8998. (new FixerOptionBuilder('around_commas', 'Whether to fix spaces around commas.'))
  8999. ->setAllowedTypes(['bool'])
  9000. ->setDefault(true)
  9001. ->getOption(),
  9002. (new FixerOptionBuilder('around_argument_assignments', 'Whether to fix spaces around argument assignment operator.'))
  9003. ->setAllowedTypes(['bool'])
  9004. ->setDefault(true)
  9005. ->setDeprecationMessage('Use options `before_argument_assignments` and `after_argument_assignments` instead.')
  9006. ->getOption(),
  9007. (new FixerOptionBuilder('before_argument_assignments', 'Whether to add, remove or ignore spaces before argument assignment operator.'))
  9008. ->setAllowedTypes(['null', 'bool'])
  9009. ->setDefault(false)
  9010. ->getOption(),
  9011. (new FixerOptionBuilder('after_argument_assignments', 'Whether to add, remove or ignore spaces after argument assignment operator.'))
  9012. ->setAllowedTypes(['null', 'bool'])
  9013. ->setDefault(false)
  9014. ->getOption(),
  9015. (new FixerOptionBuilder('around_array_assignments', 'Whether to fix spaces around array assignment operators.'))
  9016. ->setAllowedTypes(['bool'])
  9017. ->setDefault(true)
  9018. ->setDeprecationMessage('Use options `before_array_assignments_equals`, `after_array_assignments_equals`, `before_array_assignments_colon` and `after_array_assignments_colon` instead.')
  9019. ->getOption(),
  9020. (new FixerOptionBuilder('before_array_assignments_equals', 'Whether to add, remove or ignore spaces before array `=` assignment operator.'))
  9021. ->setAllowedTypes(['null', 'bool'])
  9022. ->setDefault(true)
  9023. ->getOption(),
  9024. (new FixerOptionBuilder('after_array_assignments_equals', 'Whether to add, remove or ignore spaces after array assignment `=` operator.'))
  9025. ->setAllowedTypes(['null', 'bool'])
  9026. ->setDefault(true)
  9027. ->getOption(),
  9028. (new FixerOptionBuilder('before_array_assignments_colon', 'Whether to add, remove or ignore spaces before array `:` assignment operator.'))
  9029. ->setAllowedTypes(['null', 'bool'])
  9030. ->setDefault(true)
  9031. ->getOption(),
  9032. (new FixerOptionBuilder('after_array_assignments_colon', 'Whether to add, remove or ignore spaces after array assignment `:` operator.'))
  9033. ->setAllowedTypes(['null', 'bool'])
  9034. ->setDefault(true)
  9035. ->getOption(),
  9036. ]
  9037. ));
  9038. }
  9039. protected function fixAnnotations(Tokens $tokens)
  9040. {
  9041. if ($this->configuration['around_parentheses']) {
  9042. $this->fixSpacesAroundParentheses($tokens);
  9043. }
  9044. if ($this->configuration['around_commas']) {
  9045. $this->fixSpacesAroundCommas($tokens);
  9046. }
  9047. if (
  9048. null !== $this->configuration['before_argument_assignments']
  9049. || null !== $this->configuration['after_argument_assignments']
  9050. || null !== $this->configuration['before_array_assignments_equals']
  9051. || null !== $this->configuration['after_array_assignments_equals']
  9052. || null !== $this->configuration['before_array_assignments_colon']
  9053. || null !== $this->configuration['after_array_assignments_colon']
  9054. ) {
  9055. $this->fixAroundAssignments($tokens);
  9056. }
  9057. }
  9058. private function fixSpacesAroundParentheses(Tokens $tokens)
  9059. {
  9060. $inAnnotationUntilIndex = null;
  9061. foreach ($tokens as $index => $token) {
  9062. if (null !== $inAnnotationUntilIndex) {
  9063. if ($index === $inAnnotationUntilIndex) {
  9064. $inAnnotationUntilIndex = null;
  9065. continue;
  9066. }
  9067. } elseif ($tokens[$index]->isType(DocLexer::T_AT)) {
  9068. $endIndex = $tokens->getAnnotationEnd($index);
  9069. if (null !== $endIndex) {
  9070. $inAnnotationUntilIndex = $endIndex + 1;
  9071. }
  9072. continue;
  9073. }
  9074. if (null === $inAnnotationUntilIndex) {
  9075. continue;
  9076. }
  9077. if (!$token->isType([DocLexer::T_OPEN_PARENTHESIS, DocLexer::T_CLOSE_PARENTHESIS])) {
  9078. continue;
  9079. }
  9080. if ($token->isType(DocLexer::T_OPEN_PARENTHESIS)) {
  9081. $token = $tokens[$index - 1];
  9082. if ($token->isType(DocLexer::T_NONE)) {
  9083. $token->clear();
  9084. }
  9085. $token = $tokens[$index + 1];
  9086. } else {
  9087. $token = $tokens[$index - 1];
  9088. }
  9089. if ($token->isType(DocLexer::T_NONE)) {
  9090. if (false !== strpos($token->getContent(), "\n")) {
  9091. continue;
  9092. }
  9093. $token->clear();
  9094. }
  9095. }
  9096. }
  9097. private function fixSpacesAroundCommas(Tokens $tokens)
  9098. {
  9099. $inAnnotationUntilIndex = null;
  9100. foreach ($tokens as $index => $token) {
  9101. if (null !== $inAnnotationUntilIndex) {
  9102. if ($index === $inAnnotationUntilIndex) {
  9103. $inAnnotationUntilIndex = null;
  9104. continue;
  9105. }
  9106. } elseif ($tokens[$index]->isType(DocLexer::T_AT)) {
  9107. $endIndex = $tokens->getAnnotationEnd($index);
  9108. if (null !== $endIndex) {
  9109. $inAnnotationUntilIndex = $endIndex;
  9110. }
  9111. continue;
  9112. }
  9113. if (null === $inAnnotationUntilIndex) {
  9114. continue;
  9115. }
  9116. if (!$token->isType(DocLexer::T_COMMA)) {
  9117. continue;
  9118. }
  9119. $token = $tokens[$index - 1];
  9120. if ($token->isType(DocLexer::T_NONE)) {
  9121. $token->clear();
  9122. }
  9123. if ($index < \count($tokens) - 1 && !Preg::match('/^\s/', $tokens[$index + 1]->getContent())) {
  9124. $tokens->insertAt($index + 1, new Token(DocLexer::T_NONE, ' '));
  9125. }
  9126. }
  9127. }
  9128. private function fixAroundAssignments(Tokens $tokens)
  9129. {
  9130. $beforeArguments = $this->configuration['before_argument_assignments'];
  9131. $afterArguments = $this->configuration['after_argument_assignments'];
  9132. $beforeArraysEquals = $this->configuration['before_array_assignments_equals'];
  9133. $afterArraysEquals = $this->configuration['after_array_assignments_equals'];
  9134. $beforeArraysColon = $this->configuration['before_array_assignments_colon'];
  9135. $afterArraysColon = $this->configuration['after_array_assignments_colon'];
  9136. $scopes = [];
  9137. foreach ($tokens as $index => $token) {
  9138. $endScopeType = end($scopes);
  9139. if (false !== $endScopeType && $token->isType($endScopeType)) {
  9140. array_pop($scopes);
  9141. continue;
  9142. }
  9143. if ($tokens[$index]->isType(DocLexer::T_AT)) {
  9144. $scopes[] = DocLexer::T_CLOSE_PARENTHESIS;
  9145. continue;
  9146. }
  9147. if ($tokens[$index]->isType(DocLexer::T_OPEN_CURLY_BRACES)) {
  9148. $scopes[] = DocLexer::T_CLOSE_CURLY_BRACES;
  9149. continue;
  9150. }
  9151. if (DocLexer::T_CLOSE_PARENTHESIS === $endScopeType && $token->isType(DocLexer::T_EQUALS)) {
  9152. $this->updateSpacesAfter($tokens, $index, $afterArguments);
  9153. $this->updateSpacesBefore($tokens, $index, $beforeArguments);
  9154. continue;
  9155. }
  9156. if (DocLexer::T_CLOSE_CURLY_BRACES === $endScopeType) {
  9157. if ($token->isType(DocLexer::T_EQUALS)) {
  9158. $this->updateSpacesAfter($tokens, $index, $afterArraysEquals);
  9159. $this->updateSpacesBefore($tokens, $index, $beforeArraysEquals);
  9160. continue;
  9161. }
  9162. if ($token->isType(DocLexer::T_COLON)) {
  9163. $this->updateSpacesAfter($tokens, $index, $afterArraysColon);
  9164. $this->updateSpacesBefore($tokens, $index, $beforeArraysColon);
  9165. }
  9166. }
  9167. }
  9168. }
  9169. private function updateSpacesAfter(Tokens $tokens, $index, $insert)
  9170. {
  9171. $this->updateSpacesAt($tokens, $index + 1, $index + 1, $insert);
  9172. }
  9173. private function updateSpacesBefore(Tokens $tokens, $index, $insert)
  9174. {
  9175. $this->updateSpacesAt($tokens, $index - 1, $index, $insert);
  9176. }
  9177. private function updateSpacesAt(Tokens $tokens, $index, $insertIndex, $insert)
  9178. {
  9179. if (null === $insert) {
  9180. return;
  9181. }
  9182. $token = $tokens[$index];
  9183. if ($insert) {
  9184. if (!$token->isType(DocLexer::T_NONE)) {
  9185. $tokens->insertAt($insertIndex, $token = new Token());
  9186. }
  9187. $token->setContent(' ');
  9188. } elseif ($token->isType(DocLexer::T_NONE)) {
  9189. $token->clear();
  9190. }
  9191. }
  9192. }
  9193. <?php
  9194. namespace PhpCsFixer\Fixer\DoctrineAnnotation;
  9195. use Doctrine\Common\Annotations\DocLexer;
  9196. use PhpCsFixer\AbstractDoctrineAnnotationFixer;
  9197. use PhpCsFixer\Doctrine\Annotation\Tokens;
  9198. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  9199. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  9200. use PhpCsFixer\FixerDefinition\CodeSample;
  9201. use PhpCsFixer\FixerDefinition\FixerDefinition;
  9202. final class DoctrineAnnotationArrayAssignmentFixer extends AbstractDoctrineAnnotationFixer
  9203. {
  9204. public function getDefinition()
  9205. {
  9206. return new FixerDefinition(
  9207. 'Doctrine annotations must use configured operator for assignment in arrays.',
  9208. [
  9209. new CodeSample(
  9210. "<?php\n/**\n * @Foo({bar : \"baz\"})\n */\nclass Bar {}\n"
  9211. ),
  9212. new CodeSample(
  9213. "<?php\n/**\n * @Foo({bar = \"baz\"})\n */\nclass Bar {}\n",
  9214. ['operator' => ':']
  9215. ),
  9216. ]
  9217. );
  9218. }
  9219. public function getPriority()
  9220. {
  9221. return 1;
  9222. }
  9223. protected function createConfigurationDefinition()
  9224. {
  9225. $options = parent::createConfigurationDefinition()->getOptions();
  9226. $operator = new FixerOptionBuilder('operator', 'The operator to use.');
  9227. $options[] = $operator
  9228. ->setAllowedValues(['=', ':'])
  9229. ->setDefault('=')
  9230. ->getOption()
  9231. ;
  9232. return new FixerConfigurationResolver($options);
  9233. }
  9234. protected function fixAnnotations(Tokens $tokens)
  9235. {
  9236. $scopes = [];
  9237. foreach ($tokens as $token) {
  9238. if ($token->isType(DocLexer::T_OPEN_PARENTHESIS)) {
  9239. $scopes[] = 'annotation';
  9240. continue;
  9241. }
  9242. if ($token->isType(DocLexer::T_OPEN_CURLY_BRACES)) {
  9243. $scopes[] = 'array';
  9244. continue;
  9245. }
  9246. if ($token->isType([DocLexer::T_CLOSE_PARENTHESIS, DocLexer::T_CLOSE_CURLY_BRACES])) {
  9247. array_pop($scopes);
  9248. continue;
  9249. }
  9250. if ('array' === end($scopes) && $token->isType([DocLexer::T_EQUALS, DocLexer::T_COLON])) {
  9251. $token->setContent($this->configuration['operator']);
  9252. }
  9253. }
  9254. }
  9255. }
  9256. <?php
  9257. namespace PhpCsFixer\Fixer\DoctrineAnnotation;
  9258. use Doctrine\Common\Annotations\DocLexer;
  9259. use PhpCsFixer\AbstractDoctrineAnnotationFixer;
  9260. use PhpCsFixer\Doctrine\Annotation\Tokens;
  9261. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  9262. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  9263. use PhpCsFixer\FixerDefinition\CodeSample;
  9264. use PhpCsFixer\FixerDefinition\FixerDefinition;
  9265. use PhpCsFixer\Preg;
  9266. final class DoctrineAnnotationIndentationFixer extends AbstractDoctrineAnnotationFixer
  9267. {
  9268. public function getDefinition()
  9269. {
  9270. return new FixerDefinition(
  9271. 'Doctrine annotations must be indented with four spaces.',
  9272. [
  9273. new CodeSample("<?php\n/**\n * @Foo(\n * foo=\"foo\"\n * )\n */\nclass Bar {}\n"),
  9274. new CodeSample(
  9275. "<?php\n/**\n * @Foo({@Bar,\n * @Baz})\n */\nclass Bar {}\n",
  9276. ['indent_mixed_lines' => true]
  9277. ),
  9278. ]
  9279. );
  9280. }
  9281. protected function createConfigurationDefinition()
  9282. {
  9283. return new FixerConfigurationResolver(array_merge(
  9284. parent::createConfigurationDefinition()->getOptions(),
  9285. [
  9286. (new FixerOptionBuilder('indent_mixed_lines', 'Whether to indent lines that have content before closing parenthesis.'))
  9287. ->setAllowedTypes(['bool'])
  9288. ->setDefault(false)
  9289. ->getOption(),
  9290. ]
  9291. ));
  9292. }
  9293. protected function fixAnnotations(Tokens $tokens)
  9294. {
  9295. $annotationPositions = [];
  9296. for ($index = 0, $max = \count($tokens); $index < $max; ++$index) {
  9297. if (!$tokens[$index]->isType(DocLexer::T_AT)) {
  9298. continue;
  9299. }
  9300. $annotationEndIndex = $tokens->getAnnotationEnd($index);
  9301. if (null === $annotationEndIndex) {
  9302. return;
  9303. }
  9304. $annotationPositions[] = [$index, $annotationEndIndex];
  9305. $index = $annotationEndIndex;
  9306. }
  9307. $indentLevel = 0;
  9308. foreach ($tokens as $index => $token) {
  9309. if (!$token->isType(DocLexer::T_NONE) || false === strpos($token->getContent(), "\n")) {
  9310. continue;
  9311. }
  9312. if (!$this->indentationCanBeFixed($tokens, $index, $annotationPositions)) {
  9313. continue;
  9314. }
  9315. $braces = $this->getLineBracesCount($tokens, $index);
  9316. $delta = $braces[0] - $braces[1];
  9317. $mixedBraces = 0 === $delta && $braces[0] > 0;
  9318. $extraIndentLevel = 0;
  9319. if ($indentLevel > 0 && ($delta < 0 || $mixedBraces)) {
  9320. --$indentLevel;
  9321. if ($this->configuration['indent_mixed_lines'] && $this->isClosingLineWithMeaningfulContent($tokens, $index)) {
  9322. $extraIndentLevel = 1;
  9323. }
  9324. }
  9325. $token->setContent(Preg::replace(
  9326. '/(\n( +\*)?) *$/',
  9327. '$1'.str_repeat(' ', 4 * ($indentLevel + $extraIndentLevel) + 1),
  9328. $token->getContent()
  9329. ));
  9330. if ($delta > 0 || $mixedBraces) {
  9331. ++$indentLevel;
  9332. }
  9333. }
  9334. }
  9335. private function getLineBracesCount(Tokens $tokens, $index)
  9336. {
  9337. $opening = 0;
  9338. $closing = 0;
  9339. while (isset($tokens[++$index])) {
  9340. $token = $tokens[$index];
  9341. if ($token->isType(DocLexer::T_NONE) && false !== strpos($token->getContent(), "\n")) {
  9342. break;
  9343. }
  9344. if ($token->isType([DocLexer::T_OPEN_PARENTHESIS, DocLexer::T_OPEN_CURLY_BRACES])) {
  9345. ++$opening;
  9346. continue;
  9347. }
  9348. if (!$token->isType([DocLexer::T_CLOSE_PARENTHESIS, DocLexer::T_CLOSE_CURLY_BRACES])) {
  9349. continue;
  9350. }
  9351. if ($opening > 0) {
  9352. --$opening;
  9353. } else {
  9354. ++$closing;
  9355. }
  9356. }
  9357. return [$opening, $closing];
  9358. }
  9359. private function isClosingLineWithMeaningfulContent(Tokens $tokens, $index)
  9360. {
  9361. while (isset($tokens[++$index])) {
  9362. $token = $tokens[$index];
  9363. if ($token->isType(DocLexer::T_NONE)) {
  9364. if (false !== strpos($token->getContent(), "\n")) {
  9365. return false;
  9366. }
  9367. continue;
  9368. }
  9369. return !$token->isType([DocLexer::T_CLOSE_PARENTHESIS, DocLexer::T_CLOSE_CURLY_BRACES]);
  9370. }
  9371. return false;
  9372. }
  9373. private function indentationCanBeFixed(Tokens $tokens, $newLineTokenIndex, array $annotationPositions)
  9374. {
  9375. foreach ($annotationPositions as $position) {
  9376. if ($newLineTokenIndex >= $position[0] && $newLineTokenIndex <= $position[1]) {
  9377. return true;
  9378. }
  9379. }
  9380. for ($index = $newLineTokenIndex + 1, $max = \count($tokens); $index < $max; ++$index) {
  9381. $token = $tokens[$index];
  9382. if (false !== strpos($token->getContent(), "\n")) {
  9383. return false;
  9384. }
  9385. return $tokens[$index]->isType(DocLexer::T_AT);
  9386. }
  9387. return false;
  9388. }
  9389. }
  9390. <?php
  9391. namespace PhpCsFixer\Fixer\DoctrineAnnotation;
  9392. use Doctrine\Common\Annotations\DocLexer;
  9393. use PhpCsFixer\AbstractDoctrineAnnotationFixer;
  9394. use PhpCsFixer\Doctrine\Annotation\Token;
  9395. use PhpCsFixer\Doctrine\Annotation\Tokens;
  9396. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  9397. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  9398. use PhpCsFixer\FixerDefinition\CodeSample;
  9399. use PhpCsFixer\FixerDefinition\FixerDefinition;
  9400. final class DoctrineAnnotationBracesFixer extends AbstractDoctrineAnnotationFixer
  9401. {
  9402. public function getDefinition()
  9403. {
  9404. return new FixerDefinition(
  9405. 'Doctrine annotations without arguments must use the configured syntax.',
  9406. [
  9407. new CodeSample(
  9408. "<?php\n/**\n * @Foo()\n */\nclass Bar {}\n"
  9409. ),
  9410. new CodeSample(
  9411. "<?php\n/**\n * @Foo\n */\nclass Bar {}\n",
  9412. ['syntax' => 'with_braces']
  9413. ),
  9414. ]
  9415. );
  9416. }
  9417. protected function createConfigurationDefinition()
  9418. {
  9419. return new FixerConfigurationResolver(array_merge(
  9420. parent::createConfigurationDefinition()->getOptions(),
  9421. [
  9422. (new FixerOptionBuilder('syntax', 'Whether to add or remove braces.'))
  9423. ->setAllowedValues(['with_braces', 'without_braces'])
  9424. ->setDefault('without_braces')
  9425. ->getOption(),
  9426. ]
  9427. ));
  9428. }
  9429. protected function fixAnnotations(Tokens $tokens)
  9430. {
  9431. if ('without_braces' === $this->configuration['syntax']) {
  9432. $this->removesBracesFromAnnotations($tokens);
  9433. } else {
  9434. $this->addBracesToAnnotations($tokens);
  9435. }
  9436. }
  9437. private function addBracesToAnnotations(Tokens $tokens)
  9438. {
  9439. foreach ($tokens as $index => $token) {
  9440. if (!$tokens[$index]->isType(DocLexer::T_AT)) {
  9441. continue;
  9442. }
  9443. $braceIndex = $tokens->getNextMeaningfulToken($index + 1);
  9444. if (null !== $braceIndex && $tokens[$braceIndex]->isType(DocLexer::T_OPEN_PARENTHESIS)) {
  9445. continue;
  9446. }
  9447. $tokens->insertAt($index + 2, new Token(DocLexer::T_OPEN_PARENTHESIS, '('));
  9448. $tokens->insertAt($index + 3, new Token(DocLexer::T_CLOSE_PARENTHESIS, ')'));
  9449. }
  9450. }
  9451. private function removesBracesFromAnnotations(Tokens $tokens)
  9452. {
  9453. for ($index = 0, $max = \count($tokens); $index < $max; ++$index) {
  9454. if (!$tokens[$index]->isType(DocLexer::T_AT)) {
  9455. continue;
  9456. }
  9457. $openBraceIndex = $tokens->getNextMeaningfulToken($index + 1);
  9458. if (null === $openBraceIndex) {
  9459. continue;
  9460. }
  9461. if (!$tokens[$openBraceIndex]->isType(DocLexer::T_OPEN_PARENTHESIS)) {
  9462. continue;
  9463. }
  9464. $closeBraceIndex = $tokens->getNextMeaningfulToken($openBraceIndex);
  9465. if (null === $closeBraceIndex) {
  9466. continue;
  9467. }
  9468. if (!$tokens[$closeBraceIndex]->isType(DocLexer::T_CLOSE_PARENTHESIS)) {
  9469. continue;
  9470. }
  9471. for ($currentIndex = $index + 2; $currentIndex <= $closeBraceIndex; ++$currentIndex) {
  9472. $tokens[$currentIndex]->clear();
  9473. }
  9474. }
  9475. }
  9476. }
  9477. <?php
  9478. namespace PhpCsFixer\Fixer;
  9479. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  9480. interface DefinedFixerInterface extends FixerInterface
  9481. {
  9482. public function getDefinition();
  9483. }
  9484. <?php
  9485. namespace PhpCsFixer\Fixer\Import;
  9486. use PhpCsFixer\AbstractFixer;
  9487. use PhpCsFixer\DocBlock\Annotation;
  9488. use PhpCsFixer\DocBlock\DocBlock;
  9489. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  9490. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  9491. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  9492. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  9493. use PhpCsFixer\FixerDefinition\CodeSample;
  9494. use PhpCsFixer\FixerDefinition\FixerDefinition;
  9495. use PhpCsFixer\Preg;
  9496. use PhpCsFixer\Tokenizer\Analyzer\Analysis\NamespaceUseAnalysis;
  9497. use PhpCsFixer\Tokenizer\Analyzer\ClassyAnalyzer;
  9498. use PhpCsFixer\Tokenizer\Analyzer\FunctionsAnalyzer;
  9499. use PhpCsFixer\Tokenizer\Analyzer\NamespacesAnalyzer;
  9500. use PhpCsFixer\Tokenizer\Analyzer\NamespaceUsesAnalyzer;
  9501. use PhpCsFixer\Tokenizer\CT;
  9502. use PhpCsFixer\Tokenizer\Token;
  9503. use PhpCsFixer\Tokenizer\Tokens;
  9504. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  9505. final class GlobalNamespaceImportFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface, WhitespacesAwareFixerInterface
  9506. {
  9507. public function getDefinition()
  9508. {
  9509. return new FixerDefinition(
  9510. 'Imports or fully qualifies global classes/functions/constants.',
  9511. [
  9512. new CodeSample(
  9513. '<?php
  9514. namespace Foo;
  9515. $d = new \DateTimeImmutable();
  9516. '
  9517. ),
  9518. new CodeSample(
  9519. '<?php
  9520. namespace Foo;
  9521. if (\count($x)) {
  9522. /** @var \DateTimeImmutable $d */
  9523. $d = new \DateTimeImmutable();
  9524. $p = \M_PI;
  9525. }
  9526. ',
  9527. ['import_classes' => true, 'import_constants' => true, 'import_functions' => true]
  9528. ),
  9529. new CodeSample(
  9530. '<?php
  9531. namespace Foo;
  9532. use DateTimeImmutable;
  9533. use function count;
  9534. use const M_PI;
  9535. if (count($x)) {
  9536. /** @var DateTimeImmutable $d */
  9537. $d = new DateTimeImmutable();
  9538. $p = M_PI;
  9539. }
  9540. ',
  9541. ['import_classes' => false, 'import_constants' => false, 'import_functions' => false]
  9542. ),
  9543. ]
  9544. );
  9545. }
  9546. public function getPriority()
  9547. {
  9548. return 0;
  9549. }
  9550. public function isCandidate(Tokens $tokens)
  9551. {
  9552. return $tokens->isAnyTokenKindsFound([T_DOC_COMMENT, T_NS_SEPARATOR, T_USE])
  9553. && $tokens->isTokenKindFound(T_NAMESPACE)
  9554. && (Tokens::isLegacyMode() || 1 === $tokens->countTokenKind(T_NAMESPACE))
  9555. && $tokens->isMonolithicPhp();
  9556. }
  9557. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  9558. {
  9559. $namespaceAnalyses = (new NamespacesAnalyzer())->getDeclarations($tokens);
  9560. if (1 !== \count($namespaceAnalyses) || '' === $namespaceAnalyses[0]->getFullName()) {
  9561. return;
  9562. }
  9563. $useDeclarations = (new NamespaceUsesAnalyzer())->getDeclarationsFromTokens($tokens);
  9564. $newImports = [];
  9565. if (true === $this->configuration['import_constants']) {
  9566. $newImports['const'] = $this->importConstants($tokens, $useDeclarations);
  9567. } elseif (false === $this->configuration['import_constants']) {
  9568. $this->fullyQualifyConstants($tokens, $useDeclarations);
  9569. }
  9570. if (true === $this->configuration['import_functions']) {
  9571. $newImports['function'] = $this->importFunctions($tokens, $useDeclarations);
  9572. } elseif (false === $this->configuration['import_functions']) {
  9573. $this->fullyQualifyFunctions($tokens, $useDeclarations);
  9574. }
  9575. if (true === $this->configuration['import_classes']) {
  9576. $newImports['class'] = $this->importClasses($tokens, $useDeclarations);
  9577. } elseif (false === $this->configuration['import_classes']) {
  9578. $this->fullyQualifyClasses($tokens, $useDeclarations);
  9579. }
  9580. $newImports = array_filter($newImports);
  9581. if ($newImports) {
  9582. $this->insertImports($tokens, $newImports, $useDeclarations);
  9583. }
  9584. }
  9585. protected function createConfigurationDefinition()
  9586. {
  9587. return new FixerConfigurationResolver([
  9588. (new FixerOptionBuilder('import_constants', 'Whether to import, not import or ignore global constants.'))
  9589. ->setDefault(null)
  9590. ->setAllowedValues([true, false, null])
  9591. ->getOption(),
  9592. (new FixerOptionBuilder('import_functions', 'Whether to import, not import or ignore global functions.'))
  9593. ->setDefault(null)
  9594. ->setAllowedValues([true, false, null])
  9595. ->getOption(),
  9596. (new FixerOptionBuilder('import_classes', 'Whether to import, not import or ignore global classes.'))
  9597. ->setDefault(true)
  9598. ->setAllowedValues([true, false, null])
  9599. ->getOption(),
  9600. ]);
  9601. }
  9602. private function importConstants(Tokens $tokens, array $useDeclarations)
  9603. {
  9604. list($global, $other) = $this->filterUseDeclarations($useDeclarations, static function (NamespaceUseAnalysis $declaration) {
  9605. return $declaration->isConstant();
  9606. }, true);
  9607. for ($index = 0, $count = $tokens->count(); $index < $count; ++$index) {
  9608. $token = $tokens[$index];
  9609. if ($token->isClassy()) {
  9610. $index = $tokens->getNextTokenOfKind($index, ['{']);
  9611. $index = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $index);
  9612. continue;
  9613. }
  9614. if (!$token->isGivenKind(T_CONST)) {
  9615. continue;
  9616. }
  9617. $index = $tokens->getNextMeaningfulToken($index);
  9618. $other[$tokens[$index]->getContent()] = true;
  9619. }
  9620. $analyzer = new TokensAnalyzer($tokens);
  9621. $indexes = [];
  9622. for ($index = $tokens->count() - 1; $index >= 0; --$index) {
  9623. $token = $tokens[$index];
  9624. if (!$token->isGivenKind(T_STRING)) {
  9625. continue;
  9626. }
  9627. $name = $token->getContent();
  9628. if (isset($other[$name])) {
  9629. continue;
  9630. }
  9631. if (!$analyzer->isConstantInvocation($index)) {
  9632. continue;
  9633. }
  9634. $nsSeparatorIndex = $tokens->getPrevMeaningfulToken($index);
  9635. if (!$tokens[$nsSeparatorIndex]->isGivenKind(T_NS_SEPARATOR)) {
  9636. if (!isset($global[$name])) {
  9637. $other[$name] = true;
  9638. }
  9639. continue;
  9640. }
  9641. $prevIndex = $tokens->getPrevMeaningfulToken($nsSeparatorIndex);
  9642. if ($tokens[$prevIndex]->isGivenKind([CT::T_NAMESPACE_OPERATOR, T_STRING])) {
  9643. continue;
  9644. }
  9645. $indexes[] = $index;
  9646. }
  9647. return $this->prepareImports($tokens, $indexes, $global, $other, true);
  9648. }
  9649. private function importFunctions(Tokens $tokens, array $useDeclarations)
  9650. {
  9651. list($global, $other) = $this->filterUseDeclarations($useDeclarations, static function (NamespaceUseAnalysis $declaration) {
  9652. return $declaration->isFunction();
  9653. }, false);
  9654. foreach ($this->findFunctionDeclarations($tokens, 0, $tokens->count() - 1) as $name) {
  9655. $other[strtolower($name)] = true;
  9656. }
  9657. $analyzer = new FunctionsAnalyzer();
  9658. $indexes = [];
  9659. for ($index = $tokens->count() - 1; $index >= 0; --$index) {
  9660. $token = $tokens[$index];
  9661. if (!$token->isGivenKind(T_STRING)) {
  9662. continue;
  9663. }
  9664. $name = strtolower($token->getContent());
  9665. if (isset($other[$name])) {
  9666. continue;
  9667. }
  9668. if (!$analyzer->isGlobalFunctionCall($tokens, $index)) {
  9669. continue;
  9670. }
  9671. $nsSeparatorIndex = $tokens->getPrevMeaningfulToken($index);
  9672. if (!$tokens[$nsSeparatorIndex]->isGivenKind(T_NS_SEPARATOR)) {
  9673. if (!isset($global[$name])) {
  9674. $other[$name] = true;
  9675. }
  9676. continue;
  9677. }
  9678. $indexes[] = $index;
  9679. }
  9680. return $this->prepareImports($tokens, $indexes, $global, $other, false);
  9681. }
  9682. private function importClasses(Tokens $tokens, array $useDeclarations)
  9683. {
  9684. list($global, $other) = $this->filterUseDeclarations($useDeclarations, static function (NamespaceUseAnalysis $declaration) {
  9685. return $declaration->isClass();
  9686. }, false);
  9687. $docBlocks = [];
  9688. for ($index = 0, $count = $tokens->count(); $index < $count; ++$index) {
  9689. $token = $tokens[$index];
  9690. if ($token->isGivenKind(T_DOC_COMMENT)) {
  9691. $docBlocks[$index] = new DocBlock($token->getContent());
  9692. $this->traverseDocBlockTypes($docBlocks[$index], static function ($type) use ($global, &$other) {
  9693. if (false !== strpos($type, '\\')) {
  9694. return;
  9695. }
  9696. $name = strtolower($type);
  9697. if (!isset($global[$name])) {
  9698. $other[$name] = true;
  9699. }
  9700. });
  9701. }
  9702. if (!$token->isClassy()) {
  9703. continue;
  9704. }
  9705. $index = $tokens->getNextMeaningfulToken($index);
  9706. if ($tokens[$index]->isGivenKind(T_STRING)) {
  9707. $other[strtolower($tokens[$index]->getContent())] = true;
  9708. }
  9709. }
  9710. $analyzer = new ClassyAnalyzer();
  9711. $indexes = [];
  9712. for ($index = $tokens->count() - 1; $index >= 0; --$index) {
  9713. $token = $tokens[$index];
  9714. if (!$token->isGivenKind(T_STRING)) {
  9715. continue;
  9716. }
  9717. $name = strtolower($token->getContent());
  9718. if (isset($other[$name])) {
  9719. continue;
  9720. }
  9721. if (!$analyzer->isClassyInvocation($tokens, $index)) {
  9722. continue;
  9723. }
  9724. $nsSeparatorIndex = $tokens->getPrevMeaningfulToken($index);
  9725. if (!$tokens[$nsSeparatorIndex]->isGivenKind(T_NS_SEPARATOR)) {
  9726. if (!isset($global[$name])) {
  9727. $other[$name] = true;
  9728. }
  9729. continue;
  9730. }
  9731. if ($tokens[$tokens->getPrevMeaningfulToken($nsSeparatorIndex)]->isGivenKind([CT::T_NAMESPACE_OPERATOR, T_STRING])) {
  9732. continue;
  9733. }
  9734. $indexes[] = $index;
  9735. }
  9736. $imports = [];
  9737. foreach ($docBlocks as $index => $docBlock) {
  9738. $changed = $this->traverseDocBlockTypes($docBlock, static function ($type) use ($global, $other, &$imports) {
  9739. if ('\\' !== $type[0]) {
  9740. return $type;
  9741. }
  9742. $name = substr($type, 1);
  9743. $checkName = strtolower($name);
  9744. if (false !== strpos($checkName, '\\') || isset($other[$checkName])) {
  9745. return $type;
  9746. }
  9747. if (isset($global[$checkName])) {
  9748. return \is_string($global[$checkName]) ? $global[$checkName] : $name;
  9749. }
  9750. $imports[$checkName] = $name;
  9751. return $name;
  9752. });
  9753. if ($changed) {
  9754. $tokens[$index] = new Token([T_DOC_COMMENT, $docBlock->getContent()]);
  9755. }
  9756. }
  9757. return $imports + $this->prepareImports($tokens, $indexes, $global, $other, false);
  9758. }
  9759. private function prepareImports(Tokens $tokens, array $indexes, array $global, array $other, $caseSensitive)
  9760. {
  9761. $imports = [];
  9762. foreach ($indexes as $index) {
  9763. $name = $tokens[$index]->getContent();
  9764. $checkName = $caseSensitive ? $name : strtolower($name);
  9765. if (isset($other[$checkName])) {
  9766. continue;
  9767. }
  9768. if (!isset($global[$checkName])) {
  9769. $imports[$checkName] = $name;
  9770. } elseif (\is_string($global[$checkName])) {
  9771. $tokens[$index] = new Token([T_STRING, $global[$checkName]]);
  9772. }
  9773. $tokens->clearAt($tokens->getPrevMeaningfulToken($index));
  9774. }
  9775. return $imports;
  9776. }
  9777. private function insertImports(Tokens $tokens, array $imports, array $useDeclarations)
  9778. {
  9779. if ($useDeclarations) {
  9780. $useDeclaration = end($useDeclarations);
  9781. $index = $useDeclaration->getEndIndex() + 1;
  9782. } else {
  9783. $namespace = (new NamespacesAnalyzer())->getDeclarations($tokens)[0];
  9784. $index = $namespace->getEndIndex() + 1;
  9785. }
  9786. $lineEnding = $this->whitespacesConfig->getLineEnding();
  9787. if (!$tokens[$index]->isWhitespace() || false === strpos($tokens[$index]->getContent(), "\n")) {
  9788. $tokens->insertAt($index, new Token([T_WHITESPACE, $lineEnding]));
  9789. }
  9790. foreach ($imports as $type => $typeImports) {
  9791. foreach ($typeImports as $name) {
  9792. $items = [
  9793. new Token([T_WHITESPACE, $lineEnding]),
  9794. new Token([T_USE, 'use']),
  9795. new Token([T_WHITESPACE, ' ']),
  9796. ];
  9797. if ('const' === $type) {
  9798. $items[] = new Token([CT::T_CONST_IMPORT, 'const']);
  9799. $items[] = new Token([T_WHITESPACE, ' ']);
  9800. } elseif ('function' === $type) {
  9801. $items[] = new Token([CT::T_FUNCTION_IMPORT, 'function']);
  9802. $items[] = new Token([T_WHITESPACE, ' ']);
  9803. }
  9804. $items[] = new Token([T_STRING, $name]);
  9805. $items[] = new Token(';');
  9806. $tokens->insertAt($index, $items);
  9807. }
  9808. }
  9809. }
  9810. private function fullyQualifyConstants(Tokens $tokens, array $useDeclarations)
  9811. {
  9812. if (!$tokens->isTokenKindFound(CT::T_CONST_IMPORT)) {
  9813. return;
  9814. }
  9815. list($global) = $this->filterUseDeclarations($useDeclarations, static function (NamespaceUseAnalysis $declaration) {
  9816. return $declaration->isConstant() && !$declaration->isAliased();
  9817. }, true);
  9818. if (!$global) {
  9819. return;
  9820. }
  9821. $analyzer = new TokensAnalyzer($tokens);
  9822. for ($index = $tokens->count() - 1; $index >= 0; --$index) {
  9823. $token = $tokens[$index];
  9824. if (!$token->isGivenKind(T_STRING)) {
  9825. continue;
  9826. }
  9827. if (!isset($global[$token->getContent()])) {
  9828. continue;
  9829. }
  9830. if ($tokens[$tokens->getPrevMeaningfulToken($index)]->isGivenKind(T_NS_SEPARATOR)) {
  9831. continue;
  9832. }
  9833. if (!$analyzer->isConstantInvocation($index)) {
  9834. continue;
  9835. }
  9836. $tokens->insertAt($index, new Token([T_NS_SEPARATOR, '\\']));
  9837. }
  9838. }
  9839. private function fullyQualifyFunctions(Tokens $tokens, array $useDeclarations)
  9840. {
  9841. if (!$tokens->isTokenKindFound(CT::T_FUNCTION_IMPORT)) {
  9842. return;
  9843. }
  9844. list($global) = $this->filterUseDeclarations($useDeclarations, static function (NamespaceUseAnalysis $declaration) {
  9845. return $declaration->isFunction() && !$declaration->isAliased();
  9846. }, false);
  9847. if (!$global) {
  9848. return;
  9849. }
  9850. $analyzer = new FunctionsAnalyzer();
  9851. for ($index = $tokens->count() - 1; $index >= 0; --$index) {
  9852. $token = $tokens[$index];
  9853. if (!$token->isGivenKind(T_STRING)) {
  9854. continue;
  9855. }
  9856. if (!isset($global[strtolower($token->getContent())])) {
  9857. continue;
  9858. }
  9859. if ($tokens[$tokens->getPrevMeaningfulToken($index)]->isGivenKind(T_NS_SEPARATOR)) {
  9860. continue;
  9861. }
  9862. if (!$analyzer->isGlobalFunctionCall($tokens, $index)) {
  9863. continue;
  9864. }
  9865. $tokens->insertAt($index, new Token([T_NS_SEPARATOR, '\\']));
  9866. }
  9867. }
  9868. private function fullyQualifyClasses(Tokens $tokens, array $useDeclarations)
  9869. {
  9870. if (!$tokens->isTokenKindFound(T_USE)) {
  9871. return;
  9872. }
  9873. list($global) = $this->filterUseDeclarations($useDeclarations, static function (NamespaceUseAnalysis $declaration) {
  9874. return $declaration->isClass() && !$declaration->isAliased();
  9875. }, false);
  9876. if (!$global) {
  9877. return;
  9878. }
  9879. $analyzer = new ClassyAnalyzer();
  9880. for ($index = $tokens->count() - 1; $index >= 0; --$index) {
  9881. $token = $tokens[$index];
  9882. if ($token->isGivenKind(T_DOC_COMMENT)) {
  9883. $doc = new DocBlock($token->getContent());
  9884. $changed = $this->traverseDocBlockTypes($doc, static function ($type) use ($global) {
  9885. if (!isset($global[strtolower($type)])) {
  9886. return $type;
  9887. }
  9888. return '\\'.$type;
  9889. });
  9890. if ($changed) {
  9891. $tokens[$index] = new Token([T_DOC_COMMENT, $doc->getContent()]);
  9892. }
  9893. continue;
  9894. }
  9895. if (!$token->isGivenKind(T_STRING)) {
  9896. continue;
  9897. }
  9898. if (!isset($global[strtolower($token->getContent())])) {
  9899. continue;
  9900. }
  9901. if ($tokens[$tokens->getPrevMeaningfulToken($index)]->isGivenKind(T_NS_SEPARATOR)) {
  9902. continue;
  9903. }
  9904. if (!$analyzer->isClassyInvocation($tokens, $index)) {
  9905. continue;
  9906. }
  9907. $tokens->insertAt($index, new Token([T_NS_SEPARATOR, '\\']));
  9908. }
  9909. }
  9910. private function filterUseDeclarations(array $declarations, callable $callback, $caseSensitive)
  9911. {
  9912. $global = [];
  9913. $other = [];
  9914. foreach ($declarations as $declaration) {
  9915. if (!$callback($declaration)) {
  9916. continue;
  9917. }
  9918. $fullName = ltrim($declaration->getFullName(), '\\');
  9919. if (false !== strpos($fullName, '\\')) {
  9920. $name = $caseSensitive ? $declaration->getShortName() : strtolower($declaration->getShortName());
  9921. $other[$name] = true;
  9922. continue;
  9923. }
  9924. $checkName = $caseSensitive ? $fullName : strtolower($fullName);
  9925. $alias = $declaration->getShortName();
  9926. $global[$checkName] = $alias === $fullName ? true : $alias;
  9927. }
  9928. return [$global, $other];
  9929. }
  9930. private function findFunctionDeclarations(Tokens $tokens, $start, $end)
  9931. {
  9932. for ($index = $start; $index <= $end; ++$index) {
  9933. $token = $tokens[$index];
  9934. if ($token->isClassy()) {
  9935. $classStart = $tokens->getNextTokenOfKind($index, ['{']);
  9936. $classEnd = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $classStart);
  9937. for ($index = $classStart; $index <= $classEnd; ++$index) {
  9938. if (!$tokens[$index]->isGivenKind(T_FUNCTION)) {
  9939. continue;
  9940. }
  9941. $methodStart = $tokens->getNextTokenOfKind($index, ['{', ';']);
  9942. if ($tokens[$methodStart]->equals(';')) {
  9943. $index = $methodStart;
  9944. continue;
  9945. }
  9946. $methodEnd = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $methodStart);
  9947. foreach ($this->findFunctionDeclarations($tokens, $methodStart, $methodEnd) as $function) {
  9948. yield $function;
  9949. }
  9950. $index = $methodEnd;
  9951. }
  9952. continue;
  9953. }
  9954. if (!$token->isGivenKind(T_FUNCTION)) {
  9955. continue;
  9956. }
  9957. $index = $tokens->getNextMeaningfulToken($index);
  9958. if ($tokens[$index]->isGivenKind(CT::T_RETURN_REF)) {
  9959. $index = $tokens->getNextMeaningfulToken($index);
  9960. }
  9961. if ($tokens[$index]->isGivenKind(T_STRING)) {
  9962. yield $tokens[$index]->getContent();
  9963. }
  9964. }
  9965. }
  9966. private function traverseDocBlockTypes(DocBlock $doc, callable $callback)
  9967. {
  9968. $annotations = $doc->getAnnotationsOfType(Annotation::getTagsWithTypes());
  9969. if (!$annotations) {
  9970. return false;
  9971. }
  9972. $changed = false;
  9973. foreach ($annotations as $annotation) {
  9974. $types = $new = $annotation->getTypes();
  9975. foreach ($types as $i => $fullType) {
  9976. $newFullType = $fullType;
  9977. Preg::matchAll('/[\\\\\w]+/', $fullType, $matches, PREG_OFFSET_CAPTURE);
  9978. foreach (array_reverse($matches[0]) as list($type, $offset)) {
  9979. $newType = $callback($type);
  9980. if (null !== $newType && $type !== $newType) {
  9981. $newFullType = substr_replace($newFullType, $newType, $offset, \strlen($type));
  9982. }
  9983. }
  9984. $new[$i] = $newFullType;
  9985. }
  9986. if ($types !== $new) {
  9987. $annotation->setTypes($new);
  9988. $changed = true;
  9989. }
  9990. }
  9991. return $changed;
  9992. }
  9993. }
  9994. <?php
  9995. namespace PhpCsFixer\Fixer\Import;
  9996. use PhpCsFixer\AbstractFixer;
  9997. use PhpCsFixer\FixerDefinition\CodeSample;
  9998. use PhpCsFixer\FixerDefinition\FixerDefinition;
  9999. use PhpCsFixer\Preg;
  10000. use PhpCsFixer\Tokenizer\Analyzer\Analysis\NamespaceAnalysis;
  10001. use PhpCsFixer\Tokenizer\Analyzer\Analysis\NamespaceUseAnalysis;
  10002. use PhpCsFixer\Tokenizer\Analyzer\NamespacesAnalyzer;
  10003. use PhpCsFixer\Tokenizer\Analyzer\NamespaceUsesAnalyzer;
  10004. use PhpCsFixer\Tokenizer\Token;
  10005. use PhpCsFixer\Tokenizer\Tokens;
  10006. final class NoUnusedImportsFixer extends AbstractFixer
  10007. {
  10008. public function getDefinition()
  10009. {
  10010. return new FixerDefinition(
  10011. 'Unused `use` statements must be removed.',
  10012. [new CodeSample("<?php\nuse \\DateTime;\nuse \\Exception;\n\nnew DateTime();\n")]
  10013. );
  10014. }
  10015. public function getPriority()
  10016. {
  10017. return -10;
  10018. }
  10019. public function isCandidate(Tokens $tokens)
  10020. {
  10021. return $tokens->isTokenKindFound(T_USE);
  10022. }
  10023. public function supports(\SplFileInfo $file)
  10024. {
  10025. $path = $file->getPathname();
  10026. if (false !== strpos($path, \DIRECTORY_SEPARATOR.'Fixtures'.\DIRECTORY_SEPARATOR)
  10027. && false === strpos($path, \DIRECTORY_SEPARATOR.'tests'.\DIRECTORY_SEPARATOR.'Fixtures'.\DIRECTORY_SEPARATOR)
  10028. ) {
  10029. return false;
  10030. }
  10031. return true;
  10032. }
  10033. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  10034. {
  10035. $useDeclarations = (new NamespaceUsesAnalyzer())->getDeclarationsFromTokens($tokens);
  10036. if (0 === \count($useDeclarations)) {
  10037. return;
  10038. }
  10039. foreach ((new NamespacesAnalyzer())->getDeclarations($tokens) as $namespace) {
  10040. $currentNamespaceUseDeclarations = array_filter(
  10041. $useDeclarations,
  10042. static function (NamespaceUseAnalysis $useDeclaration) use ($namespace) {
  10043. return
  10044. $useDeclaration->getStartIndex() >= $namespace->getScopeStartIndex()
  10045. && $useDeclaration->getEndIndex() <= $namespace->getScopeEndIndex()
  10046. ;
  10047. }
  10048. );
  10049. $usagesSearchIgnoredIndexes = [];
  10050. foreach ($currentNamespaceUseDeclarations as $useDeclaration) {
  10051. $usagesSearchIgnoredIndexes[$useDeclaration->getStartIndex()] = $useDeclaration->getEndIndex();
  10052. }
  10053. foreach ($currentNamespaceUseDeclarations as $useDeclaration) {
  10054. if (!$this->isImportUsed($tokens, $namespace, $usagesSearchIgnoredIndexes, $useDeclaration->getShortName())) {
  10055. $this->removeUseDeclaration($tokens, $useDeclaration);
  10056. }
  10057. }
  10058. $this->removeUsesInSameNamespace($tokens, $currentNamespaceUseDeclarations, $namespace);
  10059. }
  10060. }
  10061. private function isImportUsed(Tokens $tokens, NamespaceAnalysis $namespace, array $ignoredIndexes, $shortName)
  10062. {
  10063. $namespaceEndIndex = $namespace->getScopeEndIndex();
  10064. for ($index = $namespace->getScopeStartIndex(); $index <= $namespaceEndIndex; ++$index) {
  10065. if (isset($ignoredIndexes[$index])) {
  10066. $index = $ignoredIndexes[$index];
  10067. continue;
  10068. }
  10069. $token = $tokens[$index];
  10070. if ($token->isGivenKind(T_STRING)) {
  10071. $prevMeaningfulToken = $tokens[$tokens->getPrevMeaningfulToken($index)];
  10072. if ($prevMeaningfulToken->isGivenKind(T_NAMESPACE)) {
  10073. $index = $tokens->getNextTokenOfKind($index, [';', '{', [T_CLOSE_TAG]]);
  10074. continue;
  10075. }
  10076. if (
  10077. 0 === strcasecmp($shortName, $token->getContent())
  10078. && !$prevMeaningfulToken->isGivenKind([T_NS_SEPARATOR, T_CONST, T_OBJECT_OPERATOR, T_DOUBLE_COLON])
  10079. ) {
  10080. return true;
  10081. }
  10082. continue;
  10083. }
  10084. if ($token->isComment()
  10085. && Preg::match(
  10086. '/(?<![[:alnum:]\$])(?<!\\\\)'.$shortName.'(?![[:alnum:]])/i',
  10087. $token->getContent()
  10088. )
  10089. ) {
  10090. return true;
  10091. }
  10092. }
  10093. return false;
  10094. }
  10095. private function removeUseDeclaration(Tokens $tokens, NamespaceUseAnalysis $useDeclaration)
  10096. {
  10097. for ($index = $useDeclaration->getEndIndex() - 1; $index >= $useDeclaration->getStartIndex(); --$index) {
  10098. if ($tokens[$index]->isComment()) {
  10099. continue;
  10100. }
  10101. if (!$tokens[$index]->isWhitespace() || false === strpos($tokens[$index]->getContent(), "\n")) {
  10102. $tokens->clearTokenAndMergeSurroundingWhitespace($index);
  10103. continue;
  10104. }
  10105. $prevIndex = $tokens->getPrevNonWhitespace($index);
  10106. if ($tokens[$prevIndex]->isComment()) {
  10107. $content = $tokens[$index]->getContent();
  10108. $tokens[$index] = new Token([T_WHITESPACE, substr($content, strrpos($content, "\n"))]);
  10109. } else {
  10110. $tokens->clearTokenAndMergeSurroundingWhitespace($index);
  10111. }
  10112. }
  10113. if ($tokens[$useDeclaration->getEndIndex()]->equals(';')) {
  10114. $tokens->clearAt($useDeclaration->getEndIndex());
  10115. }
  10116. $prevIndex = $useDeclaration->getStartIndex() - 1;
  10117. $prevToken = $tokens[$prevIndex];
  10118. if ($prevToken->isWhitespace()) {
  10119. $content = rtrim($prevToken->getContent(), " \t");
  10120. if ('' === $content) {
  10121. $tokens->clearAt($prevIndex);
  10122. } else {
  10123. $tokens[$prevIndex] = new Token([T_WHITESPACE, $content]);
  10124. }
  10125. $prevToken = $tokens[$prevIndex];
  10126. }
  10127. if (!isset($tokens[$useDeclaration->getEndIndex() + 1])) {
  10128. return;
  10129. }
  10130. $nextIndex = $tokens->getNonEmptySibling($useDeclaration->getEndIndex(), 1);
  10131. if (null === $nextIndex) {
  10132. return;
  10133. }
  10134. $nextToken = $tokens[$nextIndex];
  10135. if ($nextToken->isWhitespace()) {
  10136. $content = Preg::replace(
  10137. "#^\r\n|^\n#",
  10138. '',
  10139. ltrim($nextToken->getContent(), " \t"),
  10140. 1
  10141. );
  10142. if ('' !== $content) {
  10143. $tokens[$nextIndex] = new Token([T_WHITESPACE, $content]);
  10144. } else {
  10145. $tokens->clearAt($nextIndex);
  10146. }
  10147. $nextToken = $tokens[$nextIndex];
  10148. }
  10149. if ($prevToken->isWhitespace() && $nextToken->isWhitespace()) {
  10150. $content = $prevToken->getContent().$nextToken->getContent();
  10151. if ('' !== $content) {
  10152. $tokens[$nextIndex] = new Token([T_WHITESPACE, $content]);
  10153. } else {
  10154. $tokens->clearAt($nextIndex);
  10155. }
  10156. $tokens->clearAt($prevIndex);
  10157. }
  10158. }
  10159. private function removeUsesInSameNamespace(Tokens $tokens, array $useDeclarations, NamespaceAnalysis $namespaceDeclaration)
  10160. {
  10161. $namespace = $namespaceDeclaration->getFullName();
  10162. $nsLength = \strlen($namespace.'\\');
  10163. foreach ($useDeclarations as $useDeclaration) {
  10164. if ($useDeclaration->isAliased()) {
  10165. continue;
  10166. }
  10167. $useDeclarationFullName = ltrim($useDeclaration->getFullName(), '\\');
  10168. if (0 !== strpos($useDeclarationFullName, $namespace.'\\')) {
  10169. continue;
  10170. }
  10171. $partName = substr($useDeclarationFullName, $nsLength);
  10172. if (false === strpos($partName, '\\')) {
  10173. $this->removeUseDeclaration($tokens, $useDeclaration);
  10174. }
  10175. }
  10176. }
  10177. }
  10178. <?php
  10179. namespace PhpCsFixer\Fixer\Import;
  10180. use PhpCsFixer\AbstractFixer;
  10181. use PhpCsFixer\FixerDefinition\CodeSample;
  10182. use PhpCsFixer\FixerDefinition\FixerDefinition;
  10183. use PhpCsFixer\FixerDefinition\VersionSpecification;
  10184. use PhpCsFixer\FixerDefinition\VersionSpecificCodeSample;
  10185. use PhpCsFixer\Tokenizer\Analyzer\Analysis\TypeAnalysis;
  10186. use PhpCsFixer\Tokenizer\Analyzer\FunctionsAnalyzer;
  10187. use PhpCsFixer\Tokenizer\Analyzer\NamespacesAnalyzer;
  10188. use PhpCsFixer\Tokenizer\Analyzer\NamespaceUsesAnalyzer;
  10189. use PhpCsFixer\Tokenizer\CT;
  10190. use PhpCsFixer\Tokenizer\Generator\NamespacedStringTokenGenerator;
  10191. use PhpCsFixer\Tokenizer\Resolver\TypeShortNameResolver;
  10192. use PhpCsFixer\Tokenizer\Token;
  10193. use PhpCsFixer\Tokenizer\Tokens;
  10194. final class FullyQualifiedStrictTypesFixer extends AbstractFixer
  10195. {
  10196. public function getDefinition()
  10197. {
  10198. return new FixerDefinition(
  10199. 'Transforms imported FQCN parameters and return types in function arguments to short version.',
  10200. [
  10201. new CodeSample(
  10202. '<?php
  10203. use Foo\Bar;
  10204. class SomeClass
  10205. {
  10206. public function doSomething(\Foo\Bar $foo)
  10207. {
  10208. }
  10209. }
  10210. '
  10211. ),
  10212. new VersionSpecificCodeSample(
  10213. '<?php
  10214. use Foo\Bar;
  10215. use Foo\Bar\Baz;
  10216. class SomeClass
  10217. {
  10218. public function doSomething(\Foo\Bar $foo): \Foo\Bar\Baz
  10219. {
  10220. }
  10221. }
  10222. ',
  10223. new VersionSpecification(70000)
  10224. ),
  10225. ]
  10226. );
  10227. }
  10228. public function getPriority()
  10229. {
  10230. return 7;
  10231. }
  10232. public function isCandidate(Tokens $tokens)
  10233. {
  10234. return $tokens->isTokenKindFound(T_FUNCTION) && (
  10235. \count((new NamespacesAnalyzer())->getDeclarations($tokens)) ||
  10236. \count((new NamespaceUsesAnalyzer())->getDeclarationsFromTokens($tokens))
  10237. );
  10238. }
  10239. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  10240. {
  10241. $lastIndex = $tokens->count() - 1;
  10242. for ($index = $lastIndex; $index >= 0; --$index) {
  10243. if (!$tokens[$index]->isGivenKind(T_FUNCTION)) {
  10244. continue;
  10245. }
  10246. $this->fixFunctionReturnType($tokens, $index);
  10247. $this->fixFunctionArguments($tokens, $index);
  10248. }
  10249. }
  10250. private function fixFunctionArguments(Tokens $tokens, $index)
  10251. {
  10252. $arguments = (new FunctionsAnalyzer())->getFunctionArguments($tokens, $index);
  10253. foreach ($arguments as $argument) {
  10254. if (!$argument->hasTypeAnalysis()) {
  10255. continue;
  10256. }
  10257. $this->detectAndReplaceTypeWithShortType($tokens, $argument->getTypeAnalysis());
  10258. }
  10259. }
  10260. private function fixFunctionReturnType(Tokens $tokens, $index)
  10261. {
  10262. if (\PHP_VERSION_ID < 70000) {
  10263. return;
  10264. }
  10265. $returnType = (new FunctionsAnalyzer())->getFunctionReturnType($tokens, $index);
  10266. if (!$returnType) {
  10267. return;
  10268. }
  10269. $this->detectAndReplaceTypeWithShortType($tokens, $returnType);
  10270. }
  10271. private function detectAndReplaceTypeWithShortType(
  10272. Tokens $tokens,
  10273. TypeAnalysis $type
  10274. ) {
  10275. if ($type->isReservedType()) {
  10276. return;
  10277. }
  10278. $typeName = $type->getName();
  10279. if (0 !== strpos($typeName, '\\')) {
  10280. return;
  10281. }
  10282. $shortType = (new TypeShortNameResolver())->resolve($tokens, $typeName);
  10283. if ($shortType === $typeName) {
  10284. return;
  10285. }
  10286. $shortType = (new NamespacedStringTokenGenerator())->generate($shortType);
  10287. if (true === $type->isNullable()) {
  10288. array_unshift($shortType, new Token([CT::T_NULLABLE_TYPE, '?']));
  10289. }
  10290. $tokens->overrideRange(
  10291. $type->getStartIndex(),
  10292. $type->getEndIndex(),
  10293. $shortType
  10294. );
  10295. }
  10296. }
  10297. <?php
  10298. namespace PhpCsFixer\Fixer\Import;
  10299. use PhpCsFixer\AbstractFixer;
  10300. use PhpCsFixer\FixerDefinition\CodeSample;
  10301. use PhpCsFixer\FixerDefinition\FixerDefinition;
  10302. use PhpCsFixer\Tokenizer\CT;
  10303. use PhpCsFixer\Tokenizer\Token;
  10304. use PhpCsFixer\Tokenizer\Tokens;
  10305. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  10306. final class NoLeadingImportSlashFixer extends AbstractFixer
  10307. {
  10308. public function getDefinition()
  10309. {
  10310. return new FixerDefinition(
  10311. 'Remove leading slashes in `use` clauses.',
  10312. [new CodeSample("<?php\nnamespace Foo;\nuse \\Bar;\n")]
  10313. );
  10314. }
  10315. public function getPriority()
  10316. {
  10317. return -20;
  10318. }
  10319. public function isCandidate(Tokens $tokens)
  10320. {
  10321. return $tokens->isTokenKindFound(T_USE);
  10322. }
  10323. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  10324. {
  10325. $tokensAnalyzer = new TokensAnalyzer($tokens);
  10326. $usesIndexes = $tokensAnalyzer->getImportUseIndexes();
  10327. foreach ($usesIndexes as $idx) {
  10328. $nextTokenIdx = $tokens->getNextMeaningfulToken($idx);
  10329. $nextToken = $tokens[$nextTokenIdx];
  10330. if ($nextToken->isGivenKind(T_NS_SEPARATOR)) {
  10331. $this->removeLeadingImportSlash($tokens, $nextTokenIdx);
  10332. } elseif ($nextToken->isGivenKind([CT::T_FUNCTION_IMPORT, CT::T_CONST_IMPORT])) {
  10333. $nextTokenIdx = $tokens->getNextMeaningfulToken($nextTokenIdx);
  10334. if ($tokens[$nextTokenIdx]->isGivenKind(T_NS_SEPARATOR)) {
  10335. $this->removeLeadingImportSlash($tokens, $nextTokenIdx);
  10336. }
  10337. }
  10338. }
  10339. }
  10340. private function removeLeadingImportSlash(Tokens $tokens, $index)
  10341. {
  10342. $previousIndex = $tokens->getPrevNonWhitespace($index);
  10343. if (
  10344. $previousIndex < $index - 1
  10345. || $tokens[$previousIndex]->isComment()
  10346. ) {
  10347. $tokens->clearAt($index);
  10348. return;
  10349. }
  10350. $tokens[$index] = new Token([T_WHITESPACE, ' ']);
  10351. }
  10352. }
  10353. <?php
  10354. namespace PhpCsFixer\Fixer\Import;
  10355. use PhpCsFixer\AbstractFixer;
  10356. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  10357. use PhpCsFixer\FixerDefinition\CodeSample;
  10358. use PhpCsFixer\FixerDefinition\FixerDefinition;
  10359. use PhpCsFixer\Tokenizer\CT;
  10360. use PhpCsFixer\Tokenizer\Token;
  10361. use PhpCsFixer\Tokenizer\Tokens;
  10362. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  10363. final class SingleImportPerStatementFixer extends AbstractFixer implements WhitespacesAwareFixerInterface
  10364. {
  10365. public function getDefinition()
  10366. {
  10367. return new FixerDefinition(
  10368. 'There MUST be one use keyword per declaration.',
  10369. [new CodeSample("<?php\nuse Foo, Sample, Sample\\Sample as Sample2;\n")]
  10370. );
  10371. }
  10372. public function getPriority()
  10373. {
  10374. return 1;
  10375. }
  10376. public function isCandidate(Tokens $tokens)
  10377. {
  10378. return $tokens->isTokenKindFound(T_USE);
  10379. }
  10380. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  10381. {
  10382. $tokensAnalyzer = new TokensAnalyzer($tokens);
  10383. $uses = array_reverse($tokensAnalyzer->getImportUseIndexes());
  10384. foreach ($uses as $index) {
  10385. $endIndex = $tokens->getNextTokenOfKind($index, [';', [T_CLOSE_TAG]]);
  10386. $groupClose = $tokens->getPrevMeaningfulToken($endIndex);
  10387. if ($tokens[$groupClose]->isGivenKind(CT::T_GROUP_IMPORT_BRACE_CLOSE)) {
  10388. $this->fixGroupUse($tokens, $index, $endIndex);
  10389. } else {
  10390. $this->fixMultipleUse($tokens, $index, $endIndex);
  10391. }
  10392. }
  10393. }
  10394. private function detectIndent(Tokens $tokens, $index)
  10395. {
  10396. if (!$tokens[$index - 1]->isWhitespace()) {
  10397. return '';
  10398. }
  10399. $explodedContent = explode("\n", $tokens[$index - 1]->getContent());
  10400. return end($explodedContent);
  10401. }
  10402. private function getGroupDeclaration(Tokens $tokens, $index)
  10403. {
  10404. $groupPrefix = '';
  10405. $comment = '';
  10406. $groupOpenIndex = null;
  10407. for ($i = $index + 1;; ++$i) {
  10408. if ($tokens[$i]->isGivenKind(CT::T_GROUP_IMPORT_BRACE_OPEN)) {
  10409. $groupOpenIndex = $i;
  10410. break;
  10411. }
  10412. if ($tokens[$i]->isComment()) {
  10413. $comment .= $tokens[$i]->getContent();
  10414. if (!$tokens[$i - 1]->isWhitespace() && !$tokens[$i + 1]->isWhitespace()) {
  10415. $groupPrefix .= ' ';
  10416. }
  10417. continue;
  10418. }
  10419. if ($tokens[$i]->isWhitespace()) {
  10420. $groupPrefix .= ' ';
  10421. continue;
  10422. }
  10423. $groupPrefix .= $tokens[$i]->getContent();
  10424. }
  10425. return [
  10426. rtrim($groupPrefix),
  10427. $groupOpenIndex,
  10428. $tokens->findBlockEnd(Tokens::BLOCK_TYPE_GROUP_IMPORT_BRACE, $groupOpenIndex),
  10429. $comment,
  10430. ];
  10431. }
  10432. private function getGroupStatements(Tokens $tokens, $groupPrefix, $groupOpenIndex, $groupCloseIndex, $comment)
  10433. {
  10434. $statements = [];
  10435. $statement = $groupPrefix;
  10436. for ($i = $groupOpenIndex + 1; $i <= $groupCloseIndex; ++$i) {
  10437. $token = $tokens[$i];
  10438. if ($token->equals(',') && $tokens[$tokens->getNextMeaningfulToken($i)]->equals([CT::T_GROUP_IMPORT_BRACE_CLOSE])) {
  10439. continue;
  10440. }
  10441. if ($token->equalsAny([',', [CT::T_GROUP_IMPORT_BRACE_CLOSE]])) {
  10442. $statements[] = 'use'.$statement.';';
  10443. $statement = $groupPrefix;
  10444. continue;
  10445. }
  10446. if ($token->isWhitespace()) {
  10447. $j = $tokens->getNextMeaningfulToken($i);
  10448. if ($tokens[$j]->equals([T_AS])) {
  10449. $statement .= ' as ';
  10450. $i += 2;
  10451. } elseif ($tokens[$j]->equals([T_FUNCTION])) {
  10452. $statement = ' function'.$statement;
  10453. $i += 2;
  10454. } elseif ($tokens[$j]->equals([T_CONST])) {
  10455. $statement = ' const'.$statement;
  10456. $i += 2;
  10457. }
  10458. if ($token->isWhitespace(" \t") || '//' !== substr($tokens[$i - 1]->getContent(), 0, 2)) {
  10459. continue;
  10460. }
  10461. }
  10462. $statement .= $token->getContent();
  10463. }
  10464. if ('' !== $comment) {
  10465. $statements[0] .= ' '.$comment;
  10466. }
  10467. return $statements;
  10468. }
  10469. private function fixGroupUse(Tokens $tokens, $index, $endIndex)
  10470. {
  10471. list($groupPrefix, $groupOpenIndex, $groupCloseIndex, $comment) = $this->getGroupDeclaration($tokens, $index);
  10472. $statements = $this->getGroupStatements($tokens, $groupPrefix, $groupOpenIndex, $groupCloseIndex, $comment);
  10473. if (\count($statements) < 2) {
  10474. return;
  10475. }
  10476. $tokens->clearRange($index, $groupCloseIndex);
  10477. if ($tokens[$endIndex]->equals(';')) {
  10478. $tokens->clearAt($endIndex);
  10479. }
  10480. $ending = $this->whitespacesConfig->getLineEnding();
  10481. $importTokens = Tokens::fromCode('<?php '.implode($ending, $statements));
  10482. $importTokens->clearAt(0);
  10483. $importTokens->clearEmptyTokens();
  10484. $tokens->insertAt($index, $importTokens);
  10485. }
  10486. private function fixMultipleUse(Tokens $tokens, $index, $endIndex)
  10487. {
  10488. $ending = $this->whitespacesConfig->getLineEnding();
  10489. for ($i = $endIndex - 1; $i > $index; --$i) {
  10490. if (!$tokens[$i]->equals(',')) {
  10491. continue;
  10492. }
  10493. $tokens[$i] = new Token(';');
  10494. $i = $tokens->getNextMeaningfulToken($i);
  10495. $tokens->insertAt($i, new Token([T_USE, 'use']));
  10496. $tokens->insertAt($i + 1, new Token([T_WHITESPACE, ' ']));
  10497. $indent = $this->detectIndent($tokens, $index);
  10498. if ($tokens[$i - 1]->isWhitespace()) {
  10499. $tokens[$i - 1] = new Token([T_WHITESPACE, $ending.$indent]);
  10500. continue;
  10501. }
  10502. if (false === strpos($tokens[$i - 1]->getContent(), "\n")) {
  10503. $tokens->insertAt($i, new Token([T_WHITESPACE, $ending.$indent]));
  10504. }
  10505. }
  10506. }
  10507. }
  10508. <?php
  10509. namespace PhpCsFixer\Fixer\Import;
  10510. use PhpCsFixer\AbstractFixer;
  10511. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  10512. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  10513. use PhpCsFixer\FixerConfiguration\AliasedFixerOptionBuilder;
  10514. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  10515. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  10516. use PhpCsFixer\FixerDefinition\CodeSample;
  10517. use PhpCsFixer\FixerDefinition\FixerDefinition;
  10518. use PhpCsFixer\FixerDefinition\VersionSpecification;
  10519. use PhpCsFixer\FixerDefinition\VersionSpecificCodeSample;
  10520. use PhpCsFixer\Preg;
  10521. use PhpCsFixer\Tokenizer\CT;
  10522. use PhpCsFixer\Tokenizer\Token;
  10523. use PhpCsFixer\Tokenizer\Tokens;
  10524. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  10525. use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException;
  10526. /**
  10527. @gmail
  10528. @matulionis
  10529. @gmail
  10530. */
  10531. final class OrderedImportsFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface, WhitespacesAwareFixerInterface
  10532. {
  10533. const IMPORT_TYPE_CLASS = 'class';
  10534. const IMPORT_TYPE_CONST = 'const';
  10535. const IMPORT_TYPE_FUNCTION = 'function';
  10536. const SORT_ALPHA = 'alpha';
  10537. const SORT_LENGTH = 'length';
  10538. const SORT_NONE = 'none';
  10539. private $supportedSortTypes = [self::IMPORT_TYPE_CLASS, self::IMPORT_TYPE_CONST, self::IMPORT_TYPE_FUNCTION];
  10540. private $supportedSortAlgorithms = [self::SORT_ALPHA, self::SORT_LENGTH, self::SORT_NONE];
  10541. public function getDefinition()
  10542. {
  10543. return new FixerDefinition(
  10544. 'Ordering `use` statements.',
  10545. [
  10546. new CodeSample("<?php\nuse Z; use A;\n"),
  10547. new CodeSample(
  10548. '<?php
  10549. use Acme\Bar;
  10550. use Bar1;
  10551. use Acme;
  10552. use Bar;
  10553. ',
  10554. ['sort_algorithm' => self::SORT_LENGTH]
  10555. ),
  10556. new VersionSpecificCodeSample(
  10557. "<?php\nuse function AAC;\nuse const AAB;\nuse AAA;\n",
  10558. new VersionSpecification(70000)
  10559. ),
  10560. new VersionSpecificCodeSample(
  10561. '<?php
  10562. use const AAAA;
  10563. use const BBB;
  10564. use Bar;
  10565. use AAC;
  10566. use Acme;
  10567. use function CCC\AA;
  10568. use function DDD;
  10569. ',
  10570. new VersionSpecification(70000),
  10571. [
  10572. 'sort_algorithm' => self::SORT_LENGTH,
  10573. 'imports_order' => [
  10574. self::IMPORT_TYPE_CONST,
  10575. self::IMPORT_TYPE_CLASS,
  10576. self::IMPORT_TYPE_FUNCTION,
  10577. ],
  10578. ]
  10579. ),
  10580. new VersionSpecificCodeSample(
  10581. '<?php
  10582. use const BBB;
  10583. use const AAAA;
  10584. use Acme;
  10585. use AAC;
  10586. use Bar;
  10587. use function DDD;
  10588. use function CCC\AA;
  10589. ',
  10590. new VersionSpecification(70000),
  10591. [
  10592. 'sort_algorithm' => self::SORT_ALPHA,
  10593. 'imports_order' => [
  10594. self::IMPORT_TYPE_CONST,
  10595. self::IMPORT_TYPE_CLASS,
  10596. self::IMPORT_TYPE_FUNCTION,
  10597. ],
  10598. ]
  10599. ),
  10600. new VersionSpecificCodeSample(
  10601. '<?php
  10602. use const BBB;
  10603. use const AAAA;
  10604. use function DDD;
  10605. use function CCC\AA;
  10606. use Acme;
  10607. use AAC;
  10608. use Bar;
  10609. ',
  10610. new VersionSpecification(70000),
  10611. [
  10612. 'sort_algorithm' => self::SORT_NONE,
  10613. 'imports_order' => [
  10614. self::IMPORT_TYPE_CONST,
  10615. self::IMPORT_TYPE_CLASS,
  10616. self::IMPORT_TYPE_FUNCTION,
  10617. ],
  10618. ]
  10619. ),
  10620. ]
  10621. );
  10622. }
  10623. public function getPriority()
  10624. {
  10625. return -30;
  10626. }
  10627. public function isCandidate(Tokens $tokens)
  10628. {
  10629. return $tokens->isTokenKindFound(T_USE);
  10630. }
  10631. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  10632. {
  10633. $tokensAnalyzer = new TokensAnalyzer($tokens);
  10634. $namespacesImports = $tokensAnalyzer->getImportUseIndexes(true);
  10635. if (0 === \count($namespacesImports)) {
  10636. return;
  10637. }
  10638. $usesOrder = [];
  10639. foreach ($namespacesImports as $uses) {
  10640. $usesOrder[] = $this->getNewOrder(array_reverse($uses), $tokens);
  10641. }
  10642. $usesOrder = array_replace(...$usesOrder);
  10643. $usesOrder = array_reverse($usesOrder, true);
  10644. $mapStartToEnd = [];
  10645. foreach ($usesOrder as $use) {
  10646. $mapStartToEnd[$use['startIndex']] = $use['endIndex'];
  10647. }
  10648. foreach ($usesOrder as $index => $use) {
  10649. $declarationTokens = Tokens::fromCode(
  10650. sprintf(
  10651. '<?php use %s%s;',
  10652. self::IMPORT_TYPE_CLASS === $use['importType'] ? '' : ' '.$use['importType'].' ',
  10653. $use['namespace']
  10654. )
  10655. );
  10656. $declarationTokens->clearRange(0, 2);
  10657. $declarationTokens->clearAt(\count($declarationTokens) - 1);
  10658. $declarationTokens->clearEmptyTokens();
  10659. $tokens->overrideRange($index, $mapStartToEnd[$index], $declarationTokens);
  10660. if ($use['group']) {
  10661. $prev = $tokens->getPrevMeaningfulToken($index);
  10662. if ($tokens[$prev]->equals(',')) {
  10663. $tokens[$prev] = new Token(';');
  10664. $tokens->insertAt($prev + 1, new Token([T_USE, 'use']));
  10665. if (!$tokens[$prev + 2]->isWhitespace()) {
  10666. $tokens->insertAt($prev + 2, new Token([T_WHITESPACE, ' ']));
  10667. }
  10668. }
  10669. }
  10670. }
  10671. }
  10672. protected function createConfigurationDefinition()
  10673. {
  10674. $supportedSortTypes = $this->supportedSortTypes;
  10675. return new FixerConfigurationResolver([
  10676. (new AliasedFixerOptionBuilder(
  10677. new FixerOptionBuilder('sort_algorithm', 'whether the statements should be sorted alphabetically or by length, or not sorted'),
  10678. 'sortAlgorithm'
  10679. ))
  10680. ->setAllowedValues($this->supportedSortAlgorithms)
  10681. ->setDefault(self::SORT_ALPHA)
  10682. ->getOption(),
  10683. (new AliasedFixerOptionBuilder(
  10684. new FixerOptionBuilder('imports_order', 'Defines the order of import types.'),
  10685. 'importsOrder'
  10686. ))
  10687. ->setAllowedTypes(['array', 'null'])
  10688. ->setAllowedValues([static function ($value) use ($supportedSortTypes) {
  10689. if (null !== $value) {
  10690. $missing = array_diff($supportedSortTypes, $value);
  10691. if (\count($missing)) {
  10692. throw new InvalidOptionsException(sprintf(
  10693. 'Missing sort %s "%s".',
  10694. 1 === \count($missing) ? 'type' : 'types',
  10695. implode('", "', $missing)
  10696. ));
  10697. }
  10698. $unknown = array_diff($value, $supportedSortTypes);
  10699. if (\count($unknown)) {
  10700. throw new InvalidOptionsException(sprintf(
  10701. 'Unknown sort %s "%s".',
  10702. 1 === \count($unknown) ? 'type' : 'types',
  10703. implode('", "', $unknown)
  10704. ));
  10705. }
  10706. }
  10707. return true;
  10708. }])
  10709. ->setDefault(null)
  10710. ->getOption(),
  10711. ]);
  10712. }
  10713. private function sortAlphabetically(array $first, array $second)
  10714. {
  10715. $firstNamespace = str_replace('\\', ' ', $this->prepareNamespace($first['namespace']));
  10716. $secondNamespace = str_replace('\\', ' ', $this->prepareNamespace($second['namespace']));
  10717. return strcasecmp($firstNamespace, $secondNamespace);
  10718. }
  10719. private function sortByLength(array $first, array $second)
  10720. {
  10721. $firstNamespace = (self::IMPORT_TYPE_CLASS === $first['importType'] ? '' : $first['importType'].' ').$this->prepareNamespace($first['namespace']);
  10722. $secondNamespace = (self::IMPORT_TYPE_CLASS === $second['importType'] ? '' : $second['importType'].' ').$this->prepareNamespace($second['namespace']);
  10723. $firstNamespaceLength = \strlen($firstNamespace);
  10724. $secondNamespaceLength = \strlen($secondNamespace);
  10725. if ($firstNamespaceLength === $secondNamespaceLength) {
  10726. $sortResult = strcasecmp($firstNamespace, $secondNamespace);
  10727. } else {
  10728. $sortResult = $firstNamespaceLength > $secondNamespaceLength ? 1 : -1;
  10729. }
  10730. return $sortResult;
  10731. }
  10732. private function prepareNamespace($namespace)
  10733. {
  10734. return trim(Preg::replace('%/\*(.*)\*/%s', '', $namespace));
  10735. }
  10736. private function getNewOrder(array $uses, Tokens $tokens)
  10737. {
  10738. $indexes = [];
  10739. $originalIndexes = [];
  10740. $lineEnding = $this->whitespacesConfig->getLineEnding();
  10741. for ($i = \count($uses) - 1; $i >= 0; --$i) {
  10742. $index = $uses[$i];
  10743. $startIndex = $tokens->getTokenNotOfKindSibling($index + 1, 1, [[T_WHITESPACE]]);
  10744. $endIndex = $tokens->getNextTokenOfKind($startIndex, [';', [T_CLOSE_TAG]]);
  10745. $previous = $tokens->getPrevMeaningfulToken($endIndex);
  10746. $group = $tokens[$previous]->isGivenKind(CT::T_GROUP_IMPORT_BRACE_CLOSE);
  10747. if ($tokens[$startIndex]->isGivenKind(CT::T_CONST_IMPORT)) {
  10748. $type = self::IMPORT_TYPE_CONST;
  10749. $index = $tokens->getNextNonWhitespace($startIndex);
  10750. } elseif ($tokens[$startIndex]->isGivenKind(CT::T_FUNCTION_IMPORT)) {
  10751. $type = self::IMPORT_TYPE_FUNCTION;
  10752. $index = $tokens->getNextNonWhitespace($startIndex);
  10753. } else {
  10754. $type = self::IMPORT_TYPE_CLASS;
  10755. $index = $startIndex;
  10756. }
  10757. $namespaceTokens = [];
  10758. while ($index <= $endIndex) {
  10759. $token = $tokens[$index];
  10760. if ($index === $endIndex || (!$group && $token->equals(','))) {
  10761. if ($group && self::SORT_NONE !== $this->configuration['sort_algorithm']) {
  10762. $namespaceTokensCount = \count($namespaceTokens) - 1;
  10763. $namespace = '';
  10764. for ($k = 0; $k < $namespaceTokensCount; ++$k) {
  10765. if ($namespaceTokens[$k]->isGivenKind(CT::T_GROUP_IMPORT_BRACE_OPEN)) {
  10766. $namespace .= '{';
  10767. break;
  10768. }
  10769. $namespace .= $namespaceTokens[$k]->getContent();
  10770. }
  10771. $parts = [];
  10772. $firstIndent = '';
  10773. $separator = ', ';
  10774. $lastIndent = '';
  10775. $hasGroupTrailingComma = false;
  10776. for ($k1 = $k + 1; $k1 < $namespaceTokensCount; ++$k1) {
  10777. $comment = '';
  10778. $namespacePart = '';
  10779. for ($k2 = $k1;; ++$k2) {
  10780. if ($namespaceTokens[$k2]->equalsAny([',', [CT::T_GROUP_IMPORT_BRACE_CLOSE]])) {
  10781. break;
  10782. }
  10783. if ($namespaceTokens[$k2]->isComment()) {
  10784. $comment .= $namespaceTokens[$k2]->getContent();
  10785. continue;
  10786. }
  10787. if (
  10788. '' === $firstIndent &&
  10789. $namespaceTokens[$k2]->isWhitespace() &&
  10790. false !== strpos($namespaceTokens[$k2]->getContent(), $lineEnding)
  10791. ) {
  10792. $lastIndent = $lineEnding;
  10793. $firstIndent = $lineEnding.$this->whitespacesConfig->getIndent();
  10794. $separator = ','.$firstIndent;
  10795. }
  10796. $namespacePart .= $namespaceTokens[$k2]->getContent();
  10797. }
  10798. $namespacePart = trim($namespacePart);
  10799. if ('' === $namespacePart) {
  10800. $hasGroupTrailingComma = true;
  10801. continue;
  10802. }
  10803. $comment = trim($comment);
  10804. if ('' !== $comment) {
  10805. $namespacePart .= ' '.$comment;
  10806. }
  10807. $parts[] = $namespacePart;
  10808. $k1 = $k2;
  10809. }
  10810. $sortedParts = $parts;
  10811. sort($parts);
  10812. if ($sortedParts === $parts) {
  10813. $namespace = Tokens::fromArray($namespaceTokens)->generateCode();
  10814. } else {
  10815. $namespace .= $firstIndent.implode($separator, $parts).($hasGroupTrailingComma ? ',' : '').$lastIndent.'}';
  10816. }
  10817. } else {
  10818. $namespace = Tokens::fromArray($namespaceTokens)->generateCode();
  10819. }
  10820. $indexes[$startIndex] = [
  10821. 'namespace' => $namespace,
  10822. 'startIndex' => $startIndex,
  10823. 'endIndex' => $index - 1,
  10824. 'importType' => $type,
  10825. 'group' => $group,
  10826. ];
  10827. $originalIndexes[] = $startIndex;
  10828. if ($index === $endIndex) {
  10829. break;
  10830. }
  10831. $namespaceTokens = [];
  10832. $nextPartIndex = $tokens->getTokenNotOfKindSibling($index, 1, [[','], [T_WHITESPACE]]);
  10833. $startIndex = $nextPartIndex;
  10834. $index = $nextPartIndex;
  10835. continue;
  10836. }
  10837. $namespaceTokens[] = $token;
  10838. ++$index;
  10839. }
  10840. }
  10841. if (null !== $this->configuration['imports_order']) {
  10842. $groupedByTypes = [];
  10843. foreach ($indexes as $startIndex => $item) {
  10844. $groupedByTypes[$item['importType']][$startIndex] = $item;
  10845. }
  10846. foreach ($groupedByTypes as $type => $indexes) {
  10847. $groupedByTypes[$type] = $this->sortByAlgorithm($indexes);
  10848. }
  10849. $sortedGroups = [];
  10850. foreach ($this->configuration['imports_order'] as $type) {
  10851. if (isset($groupedByTypes[$type]) && !empty($groupedByTypes[$type])) {
  10852. foreach ($groupedByTypes[$type] as $startIndex => $item) {
  10853. $sortedGroups[$startIndex] = $item;
  10854. }
  10855. }
  10856. }
  10857. $indexes = $sortedGroups;
  10858. } else {
  10859. $indexes = $this->sortByAlgorithm($indexes);
  10860. }
  10861. $index = -1;
  10862. $usesOrder = [];
  10863. foreach ($indexes as $v) {
  10864. $usesOrder[$originalIndexes[++$index]] = $v;
  10865. }
  10866. return $usesOrder;
  10867. }
  10868. private function sortByAlgorithm(array $indexes)
  10869. {
  10870. if (self::SORT_ALPHA === $this->configuration['sort_algorithm']) {
  10871. uasort($indexes, [$this, 'sortAlphabetically']);
  10872. } elseif (self::SORT_LENGTH === $this->configuration['sort_algorithm']) {
  10873. uasort($indexes, [$this, 'sortByLength']);
  10874. }
  10875. return $indexes;
  10876. }
  10877. }
  10878. <?php
  10879. namespace PhpCsFixer\Fixer\Import;
  10880. use PhpCsFixer\AbstractFixer;
  10881. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  10882. use PhpCsFixer\FixerDefinition\CodeSample;
  10883. use PhpCsFixer\FixerDefinition\FixerDefinition;
  10884. use PhpCsFixer\Tokenizer\Token;
  10885. use PhpCsFixer\Tokenizer\Tokens;
  10886. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  10887. use PhpCsFixer\Utils;
  10888. /**
  10889. @alt
  10890. */
  10891. final class SingleLineAfterImportsFixer extends AbstractFixer implements WhitespacesAwareFixerInterface
  10892. {
  10893. public function isCandidate(Tokens $tokens)
  10894. {
  10895. return $tokens->isTokenKindFound(T_USE);
  10896. }
  10897. public function getDefinition()
  10898. {
  10899. return new FixerDefinition(
  10900. 'Each namespace use MUST go on its own line and there MUST be one blank line after the use statements block.',
  10901. [
  10902. new CodeSample(
  10903. '<?php
  10904. namespace Foo;
  10905. use Bar;
  10906. use Baz;
  10907. final class Example
  10908. {
  10909. }
  10910. '
  10911. ),
  10912. new CodeSample(
  10913. '<?php
  10914. namespace Foo;
  10915. use Bar;
  10916. use Baz;
  10917. final class Example
  10918. {
  10919. }
  10920. '
  10921. ),
  10922. ]
  10923. );
  10924. }
  10925. public function getPriority()
  10926. {
  10927. return -11;
  10928. }
  10929. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  10930. {
  10931. $ending = $this->whitespacesConfig->getLineEnding();
  10932. $tokensAnalyzer = new TokensAnalyzer($tokens);
  10933. $added = 0;
  10934. foreach ($tokensAnalyzer->getImportUseIndexes() as $index) {
  10935. $index += $added;
  10936. $indent = '';
  10937. if ($tokens[$index - 1]->isWhitespace(" \t") && $tokens[$index - 2]->isGivenKind(T_COMMENT)) {
  10938. $indent = $tokens[$index - 1]->getContent();
  10939. } elseif ($tokens[$index - 1]->isWhitespace()) {
  10940. $indent = Utils::calculateTrailingWhitespaceIndent($tokens[$index - 1]);
  10941. }
  10942. $semicolonIndex = $tokens->getNextTokenOfKind($index, [';', [T_CLOSE_TAG]]);
  10943. $insertIndex = $semicolonIndex;
  10944. if ($tokens[$semicolonIndex]->isGivenKind(T_CLOSE_TAG)) {
  10945. if ($tokens[$insertIndex - 1]->isWhitespace()) {
  10946. --$insertIndex;
  10947. }
  10948. $tokens->insertAt($insertIndex, new Token(';'));
  10949. ++$added;
  10950. }
  10951. if ($semicolonIndex === \count($tokens) - 1) {
  10952. $tokens->insertAt($insertIndex + 1, new Token([T_WHITESPACE, $ending.$ending.$indent]));
  10953. ++$added;
  10954. } else {
  10955. $newline = $ending;
  10956. $tokens[$semicolonIndex]->isGivenKind(T_CLOSE_TAG) ? --$insertIndex : ++$insertIndex;
  10957. if ($tokens[$insertIndex]->isWhitespace(" \t") && $tokens[$insertIndex + 1]->isComment()) {
  10958. ++$insertIndex;
  10959. }
  10960. if ($tokens[$insertIndex]->isComment()) {
  10961. ++$insertIndex;
  10962. }
  10963. $afterSemicolon = $tokens->getNextMeaningfulToken($semicolonIndex);
  10964. if (null === $afterSemicolon || !$tokens[$afterSemicolon]->isGivenKind(T_USE)) {
  10965. $newline .= $ending;
  10966. }
  10967. if ($tokens[$insertIndex]->isWhitespace()) {
  10968. $nextToken = $tokens[$insertIndex];
  10969. if (2 === substr_count($nextToken->getContent(), "\n")) {
  10970. continue;
  10971. }
  10972. $nextMeaningfulAfterUseIndex = $tokens->getNextMeaningfulToken($insertIndex);
  10973. if (null !== $nextMeaningfulAfterUseIndex && $tokens[$nextMeaningfulAfterUseIndex]->isGivenKind(T_USE)) {
  10974. if (substr_count($nextToken->getContent(), "\n") < 2) {
  10975. $tokens[$insertIndex] = new Token([T_WHITESPACE, $newline.$indent.ltrim($nextToken->getContent())]);
  10976. }
  10977. } else {
  10978. $tokens[$insertIndex] = new Token([T_WHITESPACE, $newline.$indent.ltrim($nextToken->getContent())]);
  10979. }
  10980. } else {
  10981. $tokens->insertAt($insertIndex, new Token([T_WHITESPACE, $newline.$indent]));
  10982. ++$added;
  10983. }
  10984. }
  10985. }
  10986. }
  10987. }
  10988. <?php
  10989. namespace PhpCsFixer\Fixer\PhpTag;
  10990. use PhpCsFixer\AbstractFixer;
  10991. use PhpCsFixer\FixerDefinition\CodeSample;
  10992. use PhpCsFixer\FixerDefinition\FixerDefinition;
  10993. use PhpCsFixer\Tokenizer\Token;
  10994. use PhpCsFixer\Tokenizer\Tokens;
  10995. final class NoClosingTagFixer extends AbstractFixer
  10996. {
  10997. public function getDefinition()
  10998. {
  10999. return new FixerDefinition(
  11000. 'The closing `?>` tag MUST be omitted from files containing only PHP.',
  11001. [new CodeSample("<?php\nclass Sample\n{\n}\n?>\n")]
  11002. );
  11003. }
  11004. public function isCandidate(Tokens $tokens)
  11005. {
  11006. return $tokens->isTokenKindFound(T_CLOSE_TAG);
  11007. }
  11008. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  11009. {
  11010. if (\count($tokens) < 2 || !$tokens->isMonolithicPhp() || !$tokens->isTokenKindFound(T_CLOSE_TAG)) {
  11011. return;
  11012. }
  11013. $closeTags = $tokens->findGivenKind(T_CLOSE_TAG);
  11014. $index = key($closeTags);
  11015. if (isset($tokens[$index - 1]) && $tokens[$index - 1]->isWhitespace()) {
  11016. $tokens->clearAt($index - 1);
  11017. }
  11018. $tokens->clearAt($index);
  11019. $prevIndex = $tokens->getPrevMeaningfulToken($index);
  11020. if (!$tokens[$prevIndex]->equalsAny([';', '}', [T_OPEN_TAG]])) {
  11021. $tokens->insertAt($prevIndex + 1, new Token(';'));
  11022. }
  11023. }
  11024. }
  11025. <?php
  11026. namespace PhpCsFixer\Fixer\PhpTag;
  11027. use PhpCsFixer\AbstractFixer;
  11028. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  11029. use PhpCsFixer\FixerDefinition\CodeSample;
  11030. use PhpCsFixer\FixerDefinition\FixerDefinition;
  11031. use PhpCsFixer\Tokenizer\Token;
  11032. use PhpCsFixer\Tokenizer\Tokens;
  11033. final class LinebreakAfterOpeningTagFixer extends AbstractFixer implements WhitespacesAwareFixerInterface
  11034. {
  11035. public function getDefinition()
  11036. {
  11037. return new FixerDefinition(
  11038. 'Ensure there is no code on the same line as the PHP open tag.',
  11039. [new CodeSample("<?php \$a = 1;\n\$b = 3;\n")]
  11040. );
  11041. }
  11042. public function isCandidate(Tokens $tokens)
  11043. {
  11044. return $tokens->isTokenKindFound(T_OPEN_TAG);
  11045. }
  11046. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  11047. {
  11048. if (!$tokens[0]->isGivenKind(T_OPEN_TAG) || !$tokens->isMonolithicPhp()) {
  11049. return;
  11050. }
  11051. $newlineFound = false;
  11052. foreach ($tokens as $token) {
  11053. if ($token->isWhitespace() && false !== strpos($token->getContent(), "\n")) {
  11054. $newlineFound = true;
  11055. break;
  11056. }
  11057. }
  11058. if (!$newlineFound) {
  11059. return;
  11060. }
  11061. $token = $tokens[0];
  11062. $tokens[0] = new Token([$token->getId(), rtrim($token->getContent()).$this->whitespacesConfig->getLineEnding()]);
  11063. }
  11064. }
  11065. <?php
  11066. namespace PhpCsFixer\Fixer\PhpTag;
  11067. use PhpCsFixer\AbstractFixer;
  11068. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  11069. use PhpCsFixer\FixerDefinition\CodeSample;
  11070. use PhpCsFixer\FixerDefinition\FixerDefinition;
  11071. use PhpCsFixer\Tokenizer\Token;
  11072. use PhpCsFixer\Tokenizer\Tokens;
  11073. final class BlankLineAfterOpeningTagFixer extends AbstractFixer implements WhitespacesAwareFixerInterface
  11074. {
  11075. public function getDefinition()
  11076. {
  11077. return new FixerDefinition(
  11078. 'Ensure there is no code on the same line as the PHP open tag and it is followed by a blank line.',
  11079. [new CodeSample("<?php \$a = 1;\n\$b = 1;\n")]
  11080. );
  11081. }
  11082. public function getPriority()
  11083. {
  11084. return 1;
  11085. }
  11086. public function isCandidate(Tokens $tokens)
  11087. {
  11088. return $tokens->isTokenKindFound(T_OPEN_TAG);
  11089. }
  11090. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  11091. {
  11092. $lineEnding = $this->whitespacesConfig->getLineEnding();
  11093. if (!$tokens[0]->isGivenKind(T_OPEN_TAG) || !$tokens->isMonolithicPhp()) {
  11094. return;
  11095. }
  11096. $newlineFound = false;
  11097. foreach ($tokens as $token) {
  11098. if ($token->isWhitespace() && false !== strpos($token->getContent(), "\n")) {
  11099. $newlineFound = true;
  11100. break;
  11101. }
  11102. }
  11103. if (!$newlineFound) {
  11104. return;
  11105. }
  11106. $token = $tokens[0];
  11107. if (false === strpos($token->getContent(), "\n")) {
  11108. $tokens[0] = new Token([$token->getId(), rtrim($token->getContent()).$lineEnding]);
  11109. }
  11110. if (false === strpos($tokens[1]->getContent(), "\n")) {
  11111. if ($tokens[1]->isWhitespace()) {
  11112. $tokens[1] = new Token([T_WHITESPACE, $lineEnding.$tokens[1]->getContent()]);
  11113. } else {
  11114. $tokens->insertAt(1, new Token([T_WHITESPACE, $lineEnding]));
  11115. }
  11116. }
  11117. }
  11118. }
  11119. <?php
  11120. namespace PhpCsFixer\Fixer\PhpTag;
  11121. use PhpCsFixer\AbstractFixer;
  11122. use PhpCsFixer\FixerDefinition\CodeSample;
  11123. use PhpCsFixer\FixerDefinition\FixerDefinition;
  11124. use PhpCsFixer\Tokenizer\Token;
  11125. use PhpCsFixer\Tokenizer\Tokens;
  11126. final class NoShortEchoTagFixer extends AbstractFixer
  11127. {
  11128. public function getDefinition()
  11129. {
  11130. return new FixerDefinition(
  11131. 'Replace short-echo `<?=` with long format `<?php echo` syntax.',
  11132. [new CodeSample("<?= \"foo\";\n")]
  11133. );
  11134. }
  11135. public function getPriority()
  11136. {
  11137. return 0;
  11138. }
  11139. public function isCandidate(Tokens $tokens)
  11140. {
  11141. return $tokens->isTokenKindFound(T_OPEN_TAG_WITH_ECHO);
  11142. }
  11143. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  11144. {
  11145. $i = \count($tokens);
  11146. while ($i--) {
  11147. $token = $tokens[$i];
  11148. if (!$token->isGivenKind(T_OPEN_TAG_WITH_ECHO)) {
  11149. continue;
  11150. }
  11151. $nextIndex = $i + 1;
  11152. $tokens[$i] = new Token([T_OPEN_TAG, '<?php ']);
  11153. if (!$tokens[$nextIndex]->isWhitespace()) {
  11154. $tokens->insertAt($nextIndex, new Token([T_WHITESPACE, ' ']));
  11155. }
  11156. $tokens->insertAt($nextIndex, new Token([T_ECHO, 'echo']));
  11157. }
  11158. }
  11159. }
  11160. <?php
  11161. namespace PhpCsFixer\Fixer\PhpTag;
  11162. use PhpCsFixer\AbstractFixer;
  11163. use PhpCsFixer\FixerDefinition\CodeSample;
  11164. use PhpCsFixer\FixerDefinition\FixerDefinition;
  11165. use PhpCsFixer\Preg;
  11166. use PhpCsFixer\Tokenizer\Token;
  11167. use PhpCsFixer\Tokenizer\Tokens;
  11168. final class FullOpeningTagFixer extends AbstractFixer
  11169. {
  11170. public function getDefinition()
  11171. {
  11172. return new FixerDefinition(
  11173. 'PHP code must use the long `<?php` tags or short-echo `<?=` tags and not other tag variations.',
  11174. [
  11175. new CodeSample(
  11176. '<?
  11177. echo "Hello!";
  11178. '
  11179. ),
  11180. ]
  11181. );
  11182. }
  11183. public function getPriority()
  11184. {
  11185. return 98;
  11186. }
  11187. public function isCandidate(Tokens $tokens)
  11188. {
  11189. return true;
  11190. }
  11191. protected function applyFix(\SplFileInfo $file, Tokens $tokensOrg)
  11192. {
  11193. $content = $tokensOrg->generateCode();
  11194. $newContent = Preg::replace('/<\?(?:phP|pHp|pHP|Php|PhP|PHp|PHP)?(\s|$)/', '<?php$1', $content, -1, $count);
  11195. if (!$count) {
  11196. return;
  11197. }
  11198. $tokens = Tokens::fromCode($newContent);
  11199. $tokensOldContentLength = 0;
  11200. foreach ($tokens as $index => $token) {
  11201. if ($token->isGivenKind(T_OPEN_TAG)) {
  11202. $tokenContent = $token->getContent();
  11203. if ('<?php' !== strtolower(substr($content, $tokensOldContentLength, 5))) {
  11204. $tokenContent = '<? ';
  11205. }
  11206. $tokensOldContentLength += \strlen($tokenContent);
  11207. continue;
  11208. }
  11209. if ($token->isGivenKind([T_COMMENT, T_DOC_COMMENT, T_CONSTANT_ENCAPSED_STRING, T_ENCAPSED_AND_WHITESPACE, T_STRING])) {
  11210. $tokenContent = '';
  11211. $tokenContentLength = 0;
  11212. $parts = explode('<?php', $token->getContent());
  11213. $iLast = \count($parts) - 1;
  11214. foreach ($parts as $i => $part) {
  11215. $tokenContent .= $part;
  11216. $tokenContentLength += \strlen($part);
  11217. if ($i !== $iLast) {
  11218. $originalTokenContent = substr($content, $tokensOldContentLength + $tokenContentLength, 5);
  11219. if ('<?php' === strtolower($originalTokenContent)) {
  11220. $tokenContent .= $originalTokenContent;
  11221. $tokenContentLength += 5;
  11222. } else {
  11223. $tokenContent .= '<?';
  11224. $tokenContentLength += 2;
  11225. }
  11226. }
  11227. }
  11228. $tokens[$index] = new Token([$token->getId(), $tokenContent]);
  11229. $token = $tokens[$index];
  11230. }
  11231. $tokensOldContentLength += \strlen($token->getContent());
  11232. }
  11233. $tokensOrg->overrideRange(0, $tokensOrg->count() - 1, $tokens);
  11234. }
  11235. }
  11236. <?php
  11237. namespace PhpCsFixer\Fixer\ListNotation;
  11238. use PhpCsFixer\AbstractFixer;
  11239. use PhpCsFixer\ConfigurationException\InvalidFixerConfigurationException;
  11240. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  11241. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  11242. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  11243. use PhpCsFixer\FixerDefinition\FixerDefinition;
  11244. use PhpCsFixer\FixerDefinition\VersionSpecification;
  11245. use PhpCsFixer\FixerDefinition\VersionSpecificCodeSample;
  11246. use PhpCsFixer\Tokenizer\CT;
  11247. use PhpCsFixer\Tokenizer\Token;
  11248. use PhpCsFixer\Tokenizer\Tokens;
  11249. final class ListSyntaxFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface
  11250. {
  11251. private $candidateTokenKind;
  11252. public function configure(array $configuration = null)
  11253. {
  11254. parent::configure($configuration);
  11255. $this->candidateTokenKind = 'long' === $this->configuration['syntax'] ? CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN : T_LIST;
  11256. }
  11257. public function getDefinition()
  11258. {
  11259. return new FixerDefinition(
  11260. 'List (`array` destructuring) assignment should be declared using the configured syntax. Requires PHP >= 7.1.',
  11261. [
  11262. new VersionSpecificCodeSample(
  11263. "<?php\n[\$sample] = \$array;\n",
  11264. new VersionSpecification(70100)
  11265. ),
  11266. new VersionSpecificCodeSample(
  11267. "<?php\nlist(\$sample) = \$array;\n",
  11268. new VersionSpecification(70100),
  11269. ['syntax' => 'short']
  11270. ),
  11271. ]
  11272. );
  11273. }
  11274. public function getPriority()
  11275. {
  11276. return 1;
  11277. }
  11278. public function isCandidate(Tokens $tokens)
  11279. {
  11280. return \PHP_VERSION_ID >= 70100 && $tokens->isTokenKindFound($this->candidateTokenKind);
  11281. }
  11282. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  11283. {
  11284. for ($index = $tokens->count() - 1; 0 <= $index; --$index) {
  11285. if ($tokens[$index]->isGivenKind($this->candidateTokenKind)) {
  11286. if (T_LIST === $this->candidateTokenKind) {
  11287. $this->fixToShortSyntax($tokens, $index);
  11288. } else {
  11289. $this->fixToLongSyntax($tokens, $index);
  11290. }
  11291. }
  11292. }
  11293. }
  11294. protected function createConfigurationDefinition()
  11295. {
  11296. return new FixerConfigurationResolver([
  11297. (new FixerOptionBuilder('syntax', 'Whether to use the `long` or `short` `list` syntax.'))
  11298. ->setAllowedValues(['long', 'short'])
  11299. ->setDefault('long')
  11300. ->getOption(),
  11301. ]);
  11302. }
  11303. private function fixToLongSyntax(Tokens $tokens, $index)
  11304. {
  11305. static $typesOfInterest = [
  11306. [CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE],
  11307. '[',
  11308. ];
  11309. $closeIndex = $tokens->getNextTokenOfKind($index, $typesOfInterest);
  11310. if (!$tokens[$closeIndex]->isGivenKind(CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE)) {
  11311. return;
  11312. }
  11313. $tokens[$index] = new Token('(');
  11314. $tokens[$closeIndex] = new Token(')');
  11315. $tokens->insertAt($index, new Token([T_LIST, 'list']));
  11316. }
  11317. private function fixToShortSyntax(Tokens $tokens, $index)
  11318. {
  11319. $openIndex = $tokens->getNextTokenOfKind($index, ['(']);
  11320. $closeIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $openIndex);
  11321. $tokens[$openIndex] = new Token([CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN, '[']);
  11322. $tokens[$closeIndex] = new Token([CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE, ']']);
  11323. $tokens->clearTokenAndMergeSurroundingWhitespace($index);
  11324. }
  11325. }
  11326. <?php
  11327. namespace PhpCsFixer\Fixer\ReturnNotation;
  11328. use PhpCsFixer\AbstractFixer;
  11329. use PhpCsFixer\FixerDefinition\CodeSample;
  11330. use PhpCsFixer\FixerDefinition\FixerDefinition;
  11331. use PhpCsFixer\FixerDefinition\VersionSpecification;
  11332. use PhpCsFixer\FixerDefinition\VersionSpecificCodeSample;
  11333. use PhpCsFixer\Tokenizer\CT;
  11334. use PhpCsFixer\Tokenizer\Tokens;
  11335. final class SimplifiedNullReturnFixer extends AbstractFixer
  11336. {
  11337. public function getDefinition()
  11338. {
  11339. return new FixerDefinition(
  11340. 'A return statement wishing to return `void` should not return `null`.',
  11341. [
  11342. new CodeSample("<?php return null;\n"),
  11343. new VersionSpecificCodeSample(
  11344. <<<'EOT'
  11345. <?php
  11346. function foo() { return null; }
  11347. function bar(): int { return null; }
  11348. function baz(): ?int { return null; }
  11349. function xyz(): void { return null; }
  11350. EOT
  11351. ,
  11352. new VersionSpecification(70100)
  11353. ),
  11354. ]
  11355. );
  11356. }
  11357. public function getPriority()
  11358. {
  11359. return 16;
  11360. }
  11361. public function isCandidate(Tokens $tokens)
  11362. {
  11363. return $tokens->isTokenKindFound(T_RETURN);
  11364. }
  11365. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  11366. {
  11367. foreach ($tokens as $index => $token) {
  11368. if (!$token->isGivenKind(T_RETURN)) {
  11369. continue;
  11370. }
  11371. if ($this->needFixing($tokens, $index)) {
  11372. $this->clear($tokens, $index);
  11373. }
  11374. }
  11375. }
  11376. private function clear(Tokens $tokens, $index)
  11377. {
  11378. while (!$tokens[++$index]->equals(';')) {
  11379. if ($this->shouldClearToken($tokens, $index)) {
  11380. $tokens->clearAt($index);
  11381. }
  11382. }
  11383. }
  11384. private function needFixing(Tokens $tokens, $index)
  11385. {
  11386. if ($this->isStrictOrNullableReturnTypeFunction($tokens, $index)) {
  11387. return false;
  11388. }
  11389. $content = '';
  11390. while (!$tokens[$index]->equals(';')) {
  11391. $index = $tokens->getNextMeaningfulToken($index);
  11392. $content .= $tokens[$index]->getContent();
  11393. }
  11394. $content = ltrim($content, '(');
  11395. $content = rtrim($content, ');');
  11396. return 'null' === strtolower($content);
  11397. }
  11398. private function isStrictOrNullableReturnTypeFunction(Tokens $tokens, $returnIndex)
  11399. {
  11400. $functionIndex = $returnIndex;
  11401. do {
  11402. $functionIndex = $tokens->getPrevTokenOfKind($functionIndex, [[T_FUNCTION]]);
  11403. if (null === $functionIndex) {
  11404. return false;
  11405. }
  11406. $openingCurlyBraceIndex = $tokens->getNextTokenOfKind($functionIndex, ['{']);
  11407. $closingCurlyBraceIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $openingCurlyBraceIndex);
  11408. } while ($closingCurlyBraceIndex < $returnIndex);
  11409. $possibleVoidIndex = $tokens->getPrevMeaningfulToken($openingCurlyBraceIndex);
  11410. $isStrictReturnType = $tokens[$possibleVoidIndex]->isGivenKind(T_STRING) && 'void' !== $tokens[$possibleVoidIndex]->getContent();
  11411. $nullableTypeIndex = $tokens->getNextTokenOfKind($functionIndex, [[CT::T_NULLABLE_TYPE]]);
  11412. $isNullableReturnType = null !== $nullableTypeIndex && $nullableTypeIndex < $openingCurlyBraceIndex;
  11413. return $isStrictReturnType || $isNullableReturnType;
  11414. }
  11415. private function shouldClearToken(Tokens $tokens, $index)
  11416. {
  11417. $token = $tokens[$index];
  11418. return !$token->isComment() && !($token->isWhitespace() && $tokens[$index + 1]->isComment());
  11419. }
  11420. }
  11421. <?php
  11422. namespace PhpCsFixer\Fixer\ReturnNotation;
  11423. use PhpCsFixer\AbstractProxyFixer;
  11424. use PhpCsFixer\Fixer\DeprecatedFixerInterface;
  11425. use PhpCsFixer\Fixer\Whitespace\BlankLineBeforeStatementFixer;
  11426. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  11427. use PhpCsFixer\FixerDefinition\CodeSample;
  11428. use PhpCsFixer\FixerDefinition\FixerDefinition;
  11429. /**
  11430. @localheinz
  11431. */
  11432. final class BlankLineBeforeReturnFixer extends AbstractProxyFixer implements DeprecatedFixerInterface, WhitespacesAwareFixerInterface
  11433. {
  11434. public function getDefinition()
  11435. {
  11436. return new FixerDefinition(
  11437. 'An empty line feed should precede a return statement.',
  11438. [new CodeSample("<?php\nfunction A()\n{\n echo 1;\n return 1;\n}\n")]
  11439. );
  11440. }
  11441. public function getPriority()
  11442. {
  11443. return parent::getPriority();
  11444. }
  11445. public function getSuccessorsNames()
  11446. {
  11447. return array_keys($this->proxyFixers);
  11448. }
  11449. protected function createProxyFixers()
  11450. {
  11451. $fixer = new BlankLineBeforeStatementFixer();
  11452. $fixer->configure(['statements' => ['return']]);
  11453. return [$fixer];
  11454. }
  11455. }
  11456. <?php
  11457. namespace PhpCsFixer\Fixer\ReturnNotation;
  11458. use PhpCsFixer\AbstractFixer;
  11459. use PhpCsFixer\FixerDefinition\CodeSample;
  11460. use PhpCsFixer\FixerDefinition\FixerDefinition;
  11461. use PhpCsFixer\Tokenizer\CT;
  11462. use PhpCsFixer\Tokenizer\Token;
  11463. use PhpCsFixer\Tokenizer\Tokens;
  11464. final class ReturnAssignmentFixer extends AbstractFixer
  11465. {
  11466. public function getDefinition()
  11467. {
  11468. return new FixerDefinition(
  11469. 'Local, dynamic and directly referenced variables should not be assigned and directly returned by a function or method.',
  11470. [new CodeSample("<?php\nfunction a() {\n \$a = 1;\n return \$a;\n}\n")]
  11471. );
  11472. }
  11473. public function getPriority()
  11474. {
  11475. return -15;
  11476. }
  11477. public function isCandidate(Tokens $tokens)
  11478. {
  11479. return $tokens->isAllTokenKindsFound([T_FUNCTION, T_RETURN, T_VARIABLE]);
  11480. }
  11481. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  11482. {
  11483. $tokenCount = \count($tokens);
  11484. for ($index = 1; $index < $tokenCount; ++$index) {
  11485. if (!$tokens[$index]->isGivenKind(T_FUNCTION)) {
  11486. continue;
  11487. }
  11488. $functionOpenIndex = $tokens->getNextTokenOfKind($index, ['{', ';']);
  11489. if ($tokens[$functionOpenIndex]->equals(';')) {
  11490. $index = $functionOpenIndex - 1;
  11491. continue;
  11492. }
  11493. $functionCloseIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $functionOpenIndex);
  11494. $totalTokensAdded = 0;
  11495. do {
  11496. $tokensAdded = $this->fixFunction(
  11497. $tokens,
  11498. $index,
  11499. $functionOpenIndex,
  11500. $functionCloseIndex
  11501. );
  11502. $totalTokensAdded += $tokensAdded;
  11503. } while ($tokensAdded > 0);
  11504. $index = $functionCloseIndex + $totalTokensAdded;
  11505. $tokenCount += $totalTokensAdded;
  11506. }
  11507. }
  11508. private function fixFunction(Tokens $tokens, $functionIndex, $functionOpenIndex, $functionCloseIndex)
  11509. {
  11510. static $riskyKinds = [
  11511. CT::T_DYNAMIC_VAR_BRACE_OPEN,
  11512. T_EVAL,
  11513. T_GLOBAL,
  11514. T_INCLUDE,
  11515. T_INCLUDE_ONCE,
  11516. T_REQUIRE,
  11517. T_REQUIRE_ONCE,
  11518. T_STATIC,
  11519. ];
  11520. $inserted = 0;
  11521. $candidates = [];
  11522. $isRisky = false;
  11523. for ($index = $functionIndex + 1; $index < $functionOpenIndex; ++$index) {
  11524. if ($tokens[$index]->equals('&')) {
  11525. $isRisky = true;
  11526. break;
  11527. }
  11528. }
  11529. for ($index = $functionOpenIndex + 1; $index < $functionCloseIndex; ++$index) {
  11530. if ($tokens[$index]->isGivenKind(T_FUNCTION)) {
  11531. $nestedFunctionOpenIndex = $tokens->getNextTokenOfKind($index, ['{', ';']);
  11532. if ($tokens[$nestedFunctionOpenIndex]->equals(';')) {
  11533. $index = $nestedFunctionOpenIndex - 1;
  11534. continue;
  11535. }
  11536. $nestedFunctionCloseIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $nestedFunctionOpenIndex);
  11537. $tokensAdded = $this->fixFunction(
  11538. $tokens,
  11539. $index,
  11540. $nestedFunctionOpenIndex,
  11541. $nestedFunctionCloseIndex
  11542. );
  11543. $index = $nestedFunctionCloseIndex + $tokensAdded;
  11544. $functionCloseIndex += $tokensAdded;
  11545. $inserted += $tokensAdded;
  11546. }
  11547. if ($isRisky) {
  11548. continue;
  11549. }
  11550. if ($tokens[$index]->equals('&')) {
  11551. $isRisky = true;
  11552. continue;
  11553. }
  11554. if ($tokens[$index]->isGivenKind(T_RETURN)) {
  11555. $candidates[] = $index;
  11556. continue;
  11557. }
  11558. if ($tokens[$index]->isGivenKind($riskyKinds)) {
  11559. $isRisky = true;
  11560. continue;
  11561. }
  11562. if ($tokens[$index]->equals('$')) {
  11563. $nextIndex = $tokens->getNextMeaningfulToken($index);
  11564. if ($tokens[$nextIndex]->isGivenKind(T_VARIABLE)) {
  11565. $isRisky = true;
  11566. continue;
  11567. }
  11568. }
  11569. if ($this->isSuperGlobal($tokens[$index])) {
  11570. $isRisky = true;
  11571. continue;
  11572. }
  11573. }
  11574. if ($isRisky) {
  11575. return $inserted;
  11576. }
  11577. for ($i = \count($candidates) - 1; $i >= 0; --$i) {
  11578. $index = $candidates[$i];
  11579. $returnVarIndex = $tokens->getNextMeaningfulToken($index);
  11580. if (!$tokens[$returnVarIndex]->isGivenKind(T_VARIABLE)) {
  11581. continue;
  11582. }
  11583. $endReturnVarIndex = $tokens->getNextMeaningfulToken($returnVarIndex);
  11584. if (!$tokens[$endReturnVarIndex]->equalsAny([';', [T_CLOSE_TAG]])) {
  11585. continue;
  11586. }
  11587. $assignVarEndIndex = $tokens->getPrevMeaningfulToken($index);
  11588. if (!$tokens[$assignVarEndIndex]->equals(';')) {
  11589. continue;
  11590. }
  11591. do {
  11592. $prevMeaningFul = $tokens->getPrevMeaningfulToken($assignVarEndIndex);
  11593. if (!$tokens[$prevMeaningFul]->equals(')')) {
  11594. break;
  11595. }
  11596. $assignVarEndIndex = $tokens->findBlockStart(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $prevMeaningFul);
  11597. } while (true);
  11598. $assignVarOperatorIndex = $tokens->getPrevTokenOfKind(
  11599. $assignVarEndIndex,
  11600. ['=', ';', '{', [T_OPEN_TAG], [T_OPEN_TAG_WITH_ECHO]]
  11601. );
  11602. if (null === $assignVarOperatorIndex || !$tokens[$assignVarOperatorIndex]->equals('=')) {
  11603. continue;
  11604. }
  11605. $assignVarIndex = $tokens->getPrevMeaningfulToken($assignVarOperatorIndex);
  11606. if (!$tokens[$assignVarIndex]->equals($tokens[$returnVarIndex], false)) {
  11607. continue;
  11608. }
  11609. $beforeAssignVarIndex = $tokens->getPrevMeaningfulToken($assignVarIndex);
  11610. if (!$tokens[$beforeAssignVarIndex]->equalsAny([';', '{', '}'])) {
  11611. continue;
  11612. }
  11613. $inserted += $this->simplifyReturnStatement(
  11614. $tokens,
  11615. $assignVarIndex,
  11616. $assignVarOperatorIndex,
  11617. $index,
  11618. $endReturnVarIndex
  11619. );
  11620. }
  11621. return $inserted;
  11622. }
  11623. private function simplifyReturnStatement(
  11624. Tokens $tokens,
  11625. $assignVarIndex,
  11626. $assignVarOperatorIndex,
  11627. $returnIndex,
  11628. $returnVarEndIndex
  11629. ) {
  11630. $inserted = 0;
  11631. $originalIndent = $tokens[$assignVarIndex - 1]->isWhitespace()
  11632. ? $tokens[$assignVarIndex - 1]->getContent()
  11633. : null
  11634. ;
  11635. if ($tokens[$returnVarEndIndex]->equals(';')) {
  11636. $tokens->clearTokenAndMergeSurroundingWhitespace($returnVarEndIndex);
  11637. }
  11638. for ($i = $returnIndex; $i <= $returnVarEndIndex - 1; ++$i) {
  11639. $this->clearIfSave($tokens, $i);
  11640. }
  11641. if ($tokens[$returnIndex - 1]->isWhitespace()) {
  11642. $content = $tokens[$returnIndex - 1]->getContent();
  11643. $fistLinebreakPos = strrpos($content, "\n");
  11644. $content = false === $fistLinebreakPos
  11645. ? ' '
  11646. : substr($content, $fistLinebreakPos)
  11647. ;
  11648. $tokens[$returnIndex - 1] = new Token([T_WHITESPACE, $content]);
  11649. }
  11650. for ($i = $assignVarIndex; $i <= $assignVarOperatorIndex; ++$i) {
  11651. $this->clearIfSave($tokens, $i);
  11652. }
  11653. $tokens->insertAt($assignVarIndex, new Token([T_RETURN, 'return']));
  11654. ++$inserted;
  11655. if (
  11656. null !== $originalIndent
  11657. && $tokens[$assignVarIndex - 1]->isWhitespace()
  11658. && $originalIndent !== $tokens[$assignVarIndex - 1]->getContent()
  11659. ) {
  11660. $tokens[$assignVarIndex - 1] = new Token([T_WHITESPACE, $originalIndent]);
  11661. }
  11662. $nextIndex = $tokens->getNonEmptySibling($assignVarIndex, 1);
  11663. if (!$tokens[$nextIndex]->isWhitespace()) {
  11664. $tokens->insertAt($nextIndex, new Token([T_WHITESPACE, ' ']));
  11665. ++$inserted;
  11666. }
  11667. return $inserted;
  11668. }
  11669. private function clearIfSave(Tokens $tokens, $index)
  11670. {
  11671. if ($tokens[$index]->isComment()) {
  11672. return;
  11673. }
  11674. if ($tokens[$index]->isWhitespace() && $tokens[$tokens->getPrevNonWhitespace($index)]->isComment()) {
  11675. return;
  11676. }
  11677. $tokens->clearTokenAndMergeSurroundingWhitespace($index);
  11678. }
  11679. private function isSuperGlobal(Token $token)
  11680. {
  11681. static $superNames = [
  11682. '$_COOKIE' => true,
  11683. '$_ENV' => true,
  11684. '$_FILES' => true,
  11685. '$_GET' => true,
  11686. '$_POST' => true,
  11687. '$_REQUEST' => true,
  11688. '$_SERVER' => true,
  11689. '$_SESSION' => true,
  11690. '$GLOBALS' => true,
  11691. ];
  11692. if (!$token->isGivenKind(T_VARIABLE)) {
  11693. return false;
  11694. }
  11695. return isset($superNames[strtoupper($token->getContent())]);
  11696. }
  11697. }
  11698. <?php
  11699. namespace PhpCsFixer\Fixer\ReturnNotation;
  11700. use PhpCsFixer\AbstractFixer;
  11701. use PhpCsFixer\FixerDefinition\CodeSample;
  11702. use PhpCsFixer\FixerDefinition\FixerDefinition;
  11703. use PhpCsFixer\Tokenizer\Tokens;
  11704. final class NoUselessReturnFixer extends AbstractFixer
  11705. {
  11706. public function isCandidate(Tokens $tokens)
  11707. {
  11708. return $tokens->isAllTokenKindsFound([T_FUNCTION, T_RETURN]);
  11709. }
  11710. public function getDefinition()
  11711. {
  11712. return new FixerDefinition(
  11713. 'There should not be an empty `return` statement at the end of a function.',
  11714. [
  11715. new CodeSample(
  11716. '<?php
  11717. function example($b) {
  11718. if ($b) {
  11719. return;
  11720. }
  11721. return;
  11722. }
  11723. '
  11724. ),
  11725. ]
  11726. );
  11727. }
  11728. public function getPriority()
  11729. {
  11730. return -18;
  11731. }
  11732. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  11733. {
  11734. foreach ($tokens as $index => $token) {
  11735. if (!$token->isGivenKind(T_FUNCTION)) {
  11736. continue;
  11737. }
  11738. $index = $tokens->getNextTokenOfKind($index, [';', '{']);
  11739. if ($tokens[$index]->equals('{')) {
  11740. $this->fixFunction($tokens, $index, $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $index));
  11741. }
  11742. }
  11743. }
  11744. private function fixFunction(Tokens $tokens, $start, $end)
  11745. {
  11746. for ($index = $end; $index > $start; --$index) {
  11747. if (!$tokens[$index]->isGivenKind(T_RETURN)) {
  11748. continue;
  11749. }
  11750. $nextAt = $tokens->getNextMeaningfulToken($index);
  11751. if (!$tokens[$nextAt]->equals(';')) {
  11752. continue;
  11753. }
  11754. if ($tokens->getNextMeaningfulToken($nextAt) !== $end) {
  11755. continue;
  11756. }
  11757. $previous = $tokens->getPrevMeaningfulToken($index);
  11758. if ($tokens[$previous]->equalsAny([[T_ELSE], ')'])) {
  11759. continue;
  11760. }
  11761. $tokens->clearTokenAndMergeSurroundingWhitespace($index);
  11762. $tokens->clearTokenAndMergeSurroundingWhitespace($nextAt);
  11763. }
  11764. }
  11765. }
  11766. <?php
  11767. namespace PhpCsFixer\Fixer\Comment;
  11768. use PhpCsFixer\AbstractProxyFixer;
  11769. use PhpCsFixer\Fixer\DeprecatedFixerInterface;
  11770. use PhpCsFixer\FixerDefinition\CodeSample;
  11771. use PhpCsFixer\FixerDefinition\FixerDefinition;
  11772. final class HashToSlashCommentFixer extends AbstractProxyFixer implements DeprecatedFixerInterface
  11773. {
  11774. public function getDefinition()
  11775. {
  11776. return new FixerDefinition(
  11777. 'Single line comments should use double slashes `//` and not hash `#`.',
  11778. [new CodeSample("<?php # comment\n")]
  11779. );
  11780. }
  11781. public function getSuccessorsNames()
  11782. {
  11783. return array_keys($this->proxyFixers);
  11784. }
  11785. protected function createProxyFixers()
  11786. {
  11787. $fixer = new SingleLineCommentStyleFixer();
  11788. $fixer->configure(['comment_types' => ['hash']]);
  11789. return [$fixer];
  11790. }
  11791. }
  11792. <?php
  11793. namespace PhpCsFixer\Fixer\Comment;
  11794. use PhpCsFixer\AbstractFixer;
  11795. use PhpCsFixer\FixerDefinition\CodeSample;
  11796. use PhpCsFixer\FixerDefinition\FixerDefinition;
  11797. use PhpCsFixer\Preg;
  11798. use PhpCsFixer\Tokenizer\Tokens;
  11799. final class NoEmptyCommentFixer extends AbstractFixer
  11800. {
  11801. const TYPE_HASH = 1;
  11802. const TYPE_DOUBLE_SLASH = 2;
  11803. const TYPE_SLASH_ASTERISK = 3;
  11804. public function getPriority()
  11805. {
  11806. return 2;
  11807. }
  11808. public function getDefinition()
  11809. {
  11810. return new FixerDefinition(
  11811. 'There should not be any empty comments.',
  11812. [new CodeSample("<?php\n//\n#\n/* */\n")]
  11813. );
  11814. }
  11815. public function isCandidate(Tokens $tokens)
  11816. {
  11817. return $tokens->isTokenKindFound(T_COMMENT);
  11818. }
  11819. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  11820. {
  11821. for ($index = 1, $count = \count($tokens); $index < $count; ++$index) {
  11822. if (!$tokens[$index]->isGivenKind(T_COMMENT)) {
  11823. continue;
  11824. }
  11825. list($blockStart, $index, $isEmpty) = $this->getCommentBlock($tokens, $index);
  11826. if (false === $isEmpty) {
  11827. continue;
  11828. }
  11829. for ($i = $blockStart; $i <= $index; ++$i) {
  11830. $tokens->clearTokenAndMergeSurroundingWhitespace($i);
  11831. }
  11832. }
  11833. }
  11834. private function getCommentBlock(Tokens $tokens, $index)
  11835. {
  11836. $commentType = $this->getCommentType($tokens[$index]->getContent());
  11837. $empty = $this->isEmptyComment($tokens[$index]->getContent());
  11838. if (self::TYPE_SLASH_ASTERISK === $commentType) {
  11839. return [$index, $index, $empty];
  11840. }
  11841. $start = $index;
  11842. $count = \count($tokens);
  11843. ++$index;
  11844. for (; $index < $count; ++$index) {
  11845. if ($tokens[$index]->isComment()) {
  11846. if ($commentType !== $this->getCommentType($tokens[$index]->getContent())) {
  11847. break;
  11848. }
  11849. if ($empty) {
  11850. $empty = $this->isEmptyComment($tokens[$index]->getContent());
  11851. }
  11852. continue;
  11853. }
  11854. if (!$tokens[$index]->isWhitespace() || $this->getLineBreakCount($tokens, $index, $index + 1) > 1) {
  11855. break;
  11856. }
  11857. }
  11858. return [$start, $index - 1, $empty];
  11859. }
  11860. private function getCommentType($content)
  11861. {
  11862. if ('#' === $content[0]) {
  11863. return self::TYPE_HASH;
  11864. }
  11865. if ('*' === $content[1]) {
  11866. return self::TYPE_SLASH_ASTERISK;
  11867. }
  11868. return self::TYPE_DOUBLE_SLASH;
  11869. }
  11870. private function getLineBreakCount(Tokens $tokens, $whiteStart, $whiteEnd)
  11871. {
  11872. $lineCount = 0;
  11873. for ($i = $whiteStart; $i < $whiteEnd; ++$i) {
  11874. $lineCount += Preg::matchAll('/\R/u', $tokens[$i]->getContent(), $matches);
  11875. }
  11876. return $lineCount;
  11877. }
  11878. private function isEmptyComment($content)
  11879. {
  11880. static $mapper = [
  11881. self::TYPE_HASH => '|^#\s*$|',
  11882. self::TYPE_SLASH_ASTERISK => '|^/\*[\s\*]*\*+/$|',
  11883. self::TYPE_DOUBLE_SLASH => '|^//\s*$|',
  11884. ];
  11885. $type = $this->getCommentType($content);
  11886. return 1 === Preg::match($mapper[$type], $content);
  11887. }
  11888. }
  11889. <?php
  11890. namespace PhpCsFixer\Fixer\Comment;
  11891. use PhpCsFixer\AbstractFixer;
  11892. use PhpCsFixer\FixerDefinition\CodeSample;
  11893. use PhpCsFixer\FixerDefinition\FixerDefinition;
  11894. use PhpCsFixer\Preg;
  11895. use PhpCsFixer\Tokenizer\Token;
  11896. use PhpCsFixer\Tokenizer\Tokens;
  11897. final class MultilineCommentOpeningClosingFixer extends AbstractFixer
  11898. {
  11899. public function getDefinition()
  11900. {
  11901. return new FixerDefinition(
  11902. '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.',
  11903. [
  11904. new CodeSample(
  11905. <<<'EOT'
  11906. <?php
  11907. /******
  11908. * Multiline comment with arbitrary asterisks count
  11909. ******/
  11910. /**\
  11911. * Multiline comment that seems a DocBlock
  11912. */
  11913. /**
  11914. * DocBlock with arbitrary asterisk count at the end
  11915. **/
  11916. EOT
  11917. ),
  11918. ]
  11919. );
  11920. }
  11921. public function isCandidate(Tokens $tokens)
  11922. {
  11923. return $tokens->isAnyTokenKindsFound([T_COMMENT, T_DOC_COMMENT]);
  11924. }
  11925. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  11926. {
  11927. foreach ($tokens as $index => $token) {
  11928. $originalContent = $token->getContent();
  11929. if (
  11930. !$token->isGivenKind(T_DOC_COMMENT)
  11931. && !($token->isGivenKind(T_COMMENT) && 0 === strpos($originalContent, '/*'))
  11932. ) {
  11933. continue;
  11934. }
  11935. $newContent = $originalContent;
  11936. if ($token->isGivenKind(T_COMMENT)) {
  11937. $newContent = Preg::replace('/^\\/\\*{2,}(?!\\/)/', '/*', $newContent);
  11938. }
  11939. $newContent = Preg::replace('/(?<!\\/)\\*{2,}\\/$/', '*/', $newContent);
  11940. if ($newContent !== $originalContent) {
  11941. $tokens[$index] = new Token([$token->getId(), $newContent]);
  11942. }
  11943. }
  11944. }
  11945. }
  11946. <?php
  11947. namespace PhpCsFixer\Fixer\Comment;
  11948. use PhpCsFixer\AbstractFixer;
  11949. use PhpCsFixer\FixerDefinition\CodeSample;
  11950. use PhpCsFixer\FixerDefinition\FixerDefinition;
  11951. use PhpCsFixer\Preg;
  11952. use PhpCsFixer\Tokenizer\Token;
  11953. use PhpCsFixer\Tokenizer\Tokens;
  11954. final class NoTrailingWhitespaceInCommentFixer extends AbstractFixer
  11955. {
  11956. public function getDefinition()
  11957. {
  11958. return new FixerDefinition(
  11959. 'There MUST be no trailing spaces inside comment or PHPDoc.',
  11960. [new CodeSample('<?php
  11961. // This is '.'
  11962. // a comment. '.'
  11963. ')]
  11964. );
  11965. }
  11966. public function getPriority()
  11967. {
  11968. return 0;
  11969. }
  11970. public function isCandidate(Tokens $tokens)
  11971. {
  11972. return $tokens->isAnyTokenKindsFound([T_COMMENT, T_DOC_COMMENT]);
  11973. }
  11974. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  11975. {
  11976. foreach ($tokens as $index => $token) {
  11977. if ($token->isGivenKind(T_DOC_COMMENT)) {
  11978. $tokens[$index] = new Token([T_DOC_COMMENT, Preg::replace('/(*ANY)[\h]+$/m', '', $token->getContent())]);
  11979. continue;
  11980. }
  11981. if ($token->isGivenKind(T_COMMENT)) {
  11982. if ('/*' === substr($token->getContent(), 0, 2)) {
  11983. $tokens[$index] = new Token([T_COMMENT, Preg::replace('/(*ANY)[\h]+$/m', '', $token->getContent())]);
  11984. } elseif (isset($tokens[$index + 1]) && $tokens[$index + 1]->isWhitespace()) {
  11985. $trimmedContent = ltrim($tokens[$index + 1]->getContent(), " \t");
  11986. if ('' !== $trimmedContent) {
  11987. $tokens[$index + 1] = new Token([T_WHITESPACE, $trimmedContent]);
  11988. } else {
  11989. $tokens->clearAt($index + 1);
  11990. }
  11991. }
  11992. }
  11993. }
  11994. }
  11995. }
  11996. <?php
  11997. namespace PhpCsFixer\Fixer\Comment;
  11998. use PhpCsFixer\AbstractFixer;
  11999. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  12000. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  12001. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  12002. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  12003. use PhpCsFixer\FixerDefinition\CodeSample;
  12004. use PhpCsFixer\FixerDefinition\FixerDefinition;
  12005. use PhpCsFixer\Preg;
  12006. use PhpCsFixer\Tokenizer\Analyzer\CommentsAnalyzer;
  12007. use PhpCsFixer\Tokenizer\Token;
  12008. use PhpCsFixer\Tokenizer\Tokens;
  12009. use PhpCsFixer\Utils;
  12010. final class CommentToPhpdocFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface, WhitespacesAwareFixerInterface
  12011. {
  12012. private $ignoredTags = [];
  12013. public function isCandidate(Tokens $tokens)
  12014. {
  12015. return $tokens->isTokenKindFound(T_COMMENT);
  12016. }
  12017. public function isRisky()
  12018. {
  12019. return true;
  12020. }
  12021. public function getPriority()
  12022. {
  12023. return 26;
  12024. }
  12025. public function getDefinition()
  12026. {
  12027. return new FixerDefinition(
  12028. 'Comments with annotation should be docblock when used on structural elements.',
  12029. [new CodeSample("<?php /* header */ \$x = true; /* @var bool \$isFoo */ \$isFoo = true;\n")],
  12030. null,
  12031. 'Risky as new docblocks might mean more, e.g. a Doctrine entity might have a new column in database.'
  12032. );
  12033. }
  12034. public function configure(array $configuration = null)
  12035. {
  12036. parent::configure($configuration);
  12037. $this->ignoredTags = array_map(
  12038. static function ($tag) {
  12039. return strtolower($tag);
  12040. },
  12041. $this->configuration['ignored_tags']
  12042. );
  12043. }
  12044. protected function createConfigurationDefinition()
  12045. {
  12046. return new FixerConfigurationResolver([
  12047. (new FixerOptionBuilder('ignored_tags', sprintf('List of ignored tags')))
  12048. ->setAllowedTypes(['array'])
  12049. ->setDefault([])
  12050. ->getOption(),
  12051. ]);
  12052. }
  12053. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  12054. {
  12055. $commentsAnalyzer = new CommentsAnalyzer();
  12056. for ($index = 0, $limit = \count($tokens); $index < $limit; ++$index) {
  12057. $token = $tokens[$index];
  12058. if (!$token->isGivenKind(T_COMMENT)) {
  12059. continue;
  12060. }
  12061. if ($commentsAnalyzer->isHeaderComment($tokens, $index)) {
  12062. continue;
  12063. }
  12064. if (!$commentsAnalyzer->isBeforeStructuralElement($tokens, $index)) {
  12065. continue;
  12066. }
  12067. $commentIndices = $commentsAnalyzer->getCommentBlockIndices($tokens, $index);
  12068. if ($this->isCommentCandidate($tokens, $commentIndices)) {
  12069. $this->fixComment($tokens, $commentIndices);
  12070. }
  12071. $index = max($commentIndices);
  12072. }
  12073. }
  12074. private function isCommentCandidate(Tokens $tokens, array $indices)
  12075. {
  12076. return array_reduce(
  12077. $indices,
  12078. function ($carry, $index) use ($tokens) {
  12079. if ($carry) {
  12080. return true;
  12081. }
  12082. if (1 !== Preg::match('~(?:#|//|/\*+|\R(?:\s*\*)?)\s*\@([a-zA-Z0-9_\\\\-]+)(?=\s|\(|$)~', $tokens[$index]->getContent(), $matches)) {
  12083. return false;
  12084. }
  12085. return !\in_array(strtolower($matches[1]), $this->ignoredTags, true);
  12086. },
  12087. false
  12088. );
  12089. }
  12090. private function fixComment(Tokens $tokens, $indices)
  12091. {
  12092. if (1 === \count($indices)) {
  12093. $this->fixCommentSingleLine($tokens, reset($indices));
  12094. } else {
  12095. $this->fixCommentMultiLine($tokens, $indices);
  12096. }
  12097. }
  12098. private function fixCommentSingleLine(Tokens $tokens, $index)
  12099. {
  12100. $message = $this->getMessage($tokens[$index]->getContent());
  12101. if ('' !== trim(substr($message, 0, 1))) {
  12102. $message = ' '.$message;
  12103. }
  12104. if ('' !== trim(substr($message, -1))) {
  12105. $message .= ' ';
  12106. }
  12107. $tokens[$index] = new Token([T_DOC_COMMENT, '/**'.$message.'*/']);
  12108. }
  12109. private function fixCommentMultiLine(Tokens $tokens, array $indices)
  12110. {
  12111. $startIndex = reset($indices);
  12112. $indent = Utils::calculateTrailingWhitespaceIndent($tokens[$startIndex - 1]);
  12113. $newContent = '/**'.$this->whitespacesConfig->getLineEnding();
  12114. $count = max($indices);
  12115. for ($index = $startIndex; $index <= $count; ++$index) {
  12116. if (!$tokens[$index]->isComment()) {
  12117. continue;
  12118. }
  12119. if (false !== strpos($tokens[$index]->getContent(), '*/')) {
  12120. return;
  12121. }
  12122. $newContent .= $indent.' *'.$this->getMessage($tokens[$index]->getContent()).$this->whitespacesConfig->getLineEnding();
  12123. }
  12124. for ($index = $startIndex; $index <= $count; ++$index) {
  12125. $tokens->clearAt($index);
  12126. }
  12127. $newContent .= $indent.' */';
  12128. $tokens->insertAt($startIndex, new Token([T_DOC_COMMENT, $newContent]));
  12129. }
  12130. private function getMessage($content)
  12131. {
  12132. if (0 === strpos($content, '#')) {
  12133. return substr($content, 1);
  12134. }
  12135. if (0 === strpos($content, '//')) {
  12136. return substr($content, 2);
  12137. }
  12138. return rtrim(ltrim($content, '/*'), '*/');
  12139. }
  12140. }
  12141. <?php
  12142. namespace PhpCsFixer\Fixer\Comment;
  12143. use PhpCsFixer\AbstractFixer;
  12144. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  12145. use PhpCsFixer\FixerConfiguration\AllowedValueSubset;
  12146. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  12147. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  12148. use PhpCsFixer\FixerDefinition\CodeSample;
  12149. use PhpCsFixer\FixerDefinition\FixerDefinition;
  12150. use PhpCsFixer\Preg;
  12151. use PhpCsFixer\Tokenizer\Token;
  12152. use PhpCsFixer\Tokenizer\Tokens;
  12153. final class SingleLineCommentStyleFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface
  12154. {
  12155. private $asteriskEnabled;
  12156. private $hashEnabled;
  12157. public function configure(array $configuration = null)
  12158. {
  12159. parent::configure($configuration);
  12160. $this->asteriskEnabled = \in_array('asterisk', $this->configuration['comment_types'], true);
  12161. $this->hashEnabled = \in_array('hash', $this->configuration['comment_types'], true);
  12162. }
  12163. public function getDefinition()
  12164. {
  12165. return new FixerDefinition(
  12166. 'Single-line comments and multi-line comments with only one line of actual content should use the `//` syntax.',
  12167. [
  12168. new CodeSample(
  12169. '<?php
  12170. /* asterisk comment */
  12171. $a = 1;
  12172. # hash comment
  12173. $b = 2;
  12174. /*
  12175. * multi-line
  12176. * comment
  12177. */
  12178. $c = 3;
  12179. '
  12180. ),
  12181. new CodeSample(
  12182. '<?php
  12183. /* first comment */
  12184. $a = 1;
  12185. /*
  12186. * second comment
  12187. */
  12188. $b = 2;
  12189. /*
  12190. * third
  12191. * comment
  12192. */
  12193. $c = 3;
  12194. ',
  12195. ['comment_types' => ['asterisk']]
  12196. ),
  12197. new CodeSample(
  12198. "<?php # comment\n",
  12199. ['comment_types' => ['hash']]
  12200. ),
  12201. ]
  12202. );
  12203. }
  12204. public function isCandidate(Tokens $tokens)
  12205. {
  12206. return $tokens->isTokenKindFound(T_COMMENT);
  12207. }
  12208. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  12209. {
  12210. foreach ($tokens as $index => $token) {
  12211. if (!$token->isGivenKind(T_COMMENT)) {
  12212. continue;
  12213. }
  12214. $content = $token->getContent();
  12215. $commentContent = substr($content, 2, -2) ?: '';
  12216. if ($this->hashEnabled && '#' === $content[0]) {
  12217. $tokens[$index] = new Token([$token->getId(), '//'.substr($content, 1)]);
  12218. continue;
  12219. }
  12220. if (
  12221. !$this->asteriskEnabled
  12222. || false !== strpos($commentContent, '?>')
  12223. || '/*' !== substr($content, 0, 2)
  12224. || 1 === Preg::match('/[^\s\*].*\R.*[^\s\*]/s', $commentContent)
  12225. ) {
  12226. continue;
  12227. }
  12228. $nextTokenIndex = $index + 1;
  12229. if (isset($tokens[$nextTokenIndex])) {
  12230. $nextToken = $tokens[$nextTokenIndex];
  12231. if (!$nextToken->isWhitespace() || 1 !== Preg::match('/\R/', $nextToken->getContent())) {
  12232. continue;
  12233. }
  12234. $tokens[$nextTokenIndex] = new Token([$nextToken->getId(), ltrim($nextToken->getContent(), " \t")]);
  12235. }
  12236. $content = '//';
  12237. if (1 === Preg::match('/[^\s\*]/', $commentContent)) {
  12238. $content = '// '.Preg::replace('/[\s\*]*([^\s\*](?:.+[^\s\*])?)[\s\*]*/', '\1', $commentContent);
  12239. }
  12240. $tokens[$index] = new Token([$token->getId(), $content]);
  12241. }
  12242. }
  12243. protected function createConfigurationDefinition()
  12244. {
  12245. return new FixerConfigurationResolver([
  12246. (new FixerOptionBuilder('comment_types', 'List of comment types to fix'))
  12247. ->setAllowedTypes(['array'])
  12248. ->setAllowedValues([new AllowedValueSubset(['asterisk', 'hash'])])
  12249. ->setDefault(['asterisk', 'hash'])
  12250. ->getOption(),
  12251. ]);
  12252. }
  12253. }
  12254. <?php
  12255. namespace PhpCsFixer\Fixer\Comment;
  12256. use PhpCsFixer\AbstractFixer;
  12257. use PhpCsFixer\ConfigurationException\InvalidFixerConfigurationException;
  12258. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  12259. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  12260. use PhpCsFixer\FixerConfiguration\AliasedFixerOptionBuilder;
  12261. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  12262. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  12263. use PhpCsFixer\FixerDefinition\CodeSample;
  12264. use PhpCsFixer\FixerDefinition\FixerDefinition;
  12265. use PhpCsFixer\Preg;
  12266. use PhpCsFixer\Tokenizer\Token;
  12267. use PhpCsFixer\Tokenizer\Tokens;
  12268. use Symfony\Component\OptionsResolver\Options;
  12269. final class HeaderCommentFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface, WhitespacesAwareFixerInterface
  12270. {
  12271. const HEADER_PHPDOC = 'PHPDoc';
  12272. const HEADER_COMMENT = 'comment';
  12273. const HEADER_LOCATION_AFTER_OPEN = 1;
  12274. const HEADER_LOCATION_AFTER_DECLARE_STRICT = 2;
  12275. const HEADER_LINE_SEPARATION_BOTH = 1;
  12276. const HEADER_LINE_SEPARATION_TOP = 2;
  12277. const HEADER_LINE_SEPARATION_BOTTOM = 3;
  12278. const HEADER_LINE_SEPARATION_NONE = 4;
  12279. public function getDefinition()
  12280. {
  12281. return new FixerDefinition(
  12282. 'Add, replace or remove header comment.',
  12283. [
  12284. new CodeSample(
  12285. '<?php
  12286. declare(strict_types=1);
  12287. namespace A\B;
  12288. echo 1;
  12289. ',
  12290. [
  12291. 'header' => 'Made with love.',
  12292. ]
  12293. ),
  12294. new CodeSample(
  12295. '<?php
  12296. declare(strict_types=1);
  12297. namespace A\B;
  12298. echo 1;
  12299. ',
  12300. [
  12301. 'header' => 'Made with love.',
  12302. 'comment_type' => 'PHPDoc',
  12303. 'location' => 'after_open',
  12304. 'separate' => 'bottom',
  12305. ]
  12306. ),
  12307. new CodeSample(
  12308. '<?php
  12309. declare(strict_types=1);
  12310. namespace A\B;
  12311. echo 1;
  12312. ',
  12313. [
  12314. 'header' => 'Made with love.',
  12315. 'comment_type' => 'comment',
  12316. 'location' => 'after_declare_strict',
  12317. ]
  12318. ),
  12319. ]
  12320. );
  12321. }
  12322. public function isCandidate(Tokens $tokens)
  12323. {
  12324. return isset($tokens[0]) && $tokens[0]->isGivenKind(T_OPEN_TAG) && $tokens->isMonolithicPhp();
  12325. }
  12326. public function getPriority()
  12327. {
  12328. return -30;
  12329. }
  12330. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  12331. {
  12332. $location = $this->configuration['location'];
  12333. $locationIndexes = [];
  12334. foreach (['after_open', 'after_declare_strict'] as $possibleLocation) {
  12335. $locationIndex = $this->findHeaderCommentInsertionIndex($tokens, $possibleLocation);
  12336. if (!isset($locationIndexes[$locationIndex]) || $possibleLocation === $location) {
  12337. $locationIndexes[$locationIndex] = $possibleLocation;
  12338. continue;
  12339. }
  12340. }
  12341. foreach (array_values($locationIndexes) as $possibleLocation) {
  12342. $headerNewIndex = $this->findHeaderCommentInsertionIndex($tokens, $possibleLocation);
  12343. $headerCurrentIndex = $this->findHeaderCommentCurrentIndex($tokens, $headerNewIndex - 1);
  12344. if (null === $headerCurrentIndex) {
  12345. if ('' === $this->configuration['header'] || $possibleLocation !== $location) {
  12346. continue;
  12347. }
  12348. $this->insertHeader($tokens, $headerNewIndex);
  12349. } elseif ($this->getHeaderAsComment() !== $tokens[$headerCurrentIndex]->getContent() || $possibleLocation !== $location) {
  12350. $this->removeHeader($tokens, $headerCurrentIndex);
  12351. if ('' === $this->configuration['header']) {
  12352. continue;
  12353. }
  12354. if ($possibleLocation === $location) {
  12355. $this->insertHeader($tokens, $headerNewIndex);
  12356. }
  12357. } else {
  12358. $this->fixWhiteSpaceAroundHeader($tokens, $headerCurrentIndex);
  12359. }
  12360. }
  12361. }
  12362. protected function createConfigurationDefinition()
  12363. {
  12364. $fixerName = $this->getName();
  12365. return new FixerConfigurationResolver([
  12366. (new FixerOptionBuilder('header', 'Proper header content.'))
  12367. ->setAllowedTypes(['string'])
  12368. ->setNormalizer(static function (Options $options, $value) use ($fixerName) {
  12369. if ('' === trim($value)) {
  12370. return '';
  12371. }
  12372. if (false !== strpos($value, '*/')) {
  12373. throw new InvalidFixerConfigurationException($fixerName, 'Cannot use \'*/\' in header.');
  12374. }
  12375. return $value;
  12376. })
  12377. ->getOption(),
  12378. (new AliasedFixerOptionBuilder(
  12379. new FixerOptionBuilder('comment_type', 'Comment syntax type.'),
  12380. 'commentType'
  12381. ))
  12382. ->setAllowedValues([self::HEADER_PHPDOC, self::HEADER_COMMENT])
  12383. ->setDefault(self::HEADER_COMMENT)
  12384. ->getOption(),
  12385. (new FixerOptionBuilder('location', 'The location of the inserted header.'))
  12386. ->setAllowedValues(['after_open', 'after_declare_strict'])
  12387. ->setDefault('after_declare_strict')
  12388. ->getOption(),
  12389. (new FixerOptionBuilder('separate', 'Whether the header should be separated from the file content with a new line.'))
  12390. ->setAllowedValues(['both', 'top', 'bottom', 'none'])
  12391. ->setDefault('both')
  12392. ->getOption(),
  12393. ]);
  12394. }
  12395. private function getHeaderAsComment()
  12396. {
  12397. $lineEnding = $this->whitespacesConfig->getLineEnding();
  12398. $comment = (self::HEADER_COMMENT === $this->configuration['comment_type'] ? '/*' : '/**').$lineEnding;
  12399. $lines = explode("\n", str_replace("\r", '', $this->configuration['header']));
  12400. foreach ($lines as $line) {
  12401. $comment .= rtrim(' * '.$line).$lineEnding;
  12402. }
  12403. return $comment.' */';
  12404. }
  12405. private function findHeaderCommentCurrentIndex(Tokens $tokens, $headerNewIndex)
  12406. {
  12407. $index = $tokens->getNextNonWhitespace($headerNewIndex);
  12408. if (null === $index || !$tokens[$index]->isComment()) {
  12409. return null;
  12410. }
  12411. $next = $index + 1;
  12412. if (!isset($tokens[$next]) || \in_array($this->configuration['separate'], ['top', 'none'], true) || !$tokens[$index]->isGivenKind(T_DOC_COMMENT)) {
  12413. return $index;
  12414. }
  12415. if ($tokens[$next]->isWhitespace()) {
  12416. if (!Preg::match('/^\h*\R\h*$/D', $tokens[$next]->getContent())) {
  12417. return $index;
  12418. }
  12419. ++$next;
  12420. }
  12421. if (!isset($tokens[$next]) || !$tokens[$next]->isClassy() && !$tokens[$next]->isGivenKind(T_FUNCTION)) {
  12422. return $index;
  12423. }
  12424. return $this->getHeaderAsComment() === $tokens[$index]->getContent() ? $index : null;
  12425. }
  12426. private function findHeaderCommentInsertionIndex(Tokens $tokens, $location)
  12427. {
  12428. if ('after_open' === $location) {
  12429. return 1;
  12430. }
  12431. $index = $tokens->getNextMeaningfulToken(0);
  12432. if (null === $index) {
  12433. return 1;
  12434. }
  12435. if (!$tokens[$index]->isGivenKind(T_DECLARE)) {
  12436. return 1;
  12437. }
  12438. $next = $tokens->getNextMeaningfulToken($index);
  12439. if (null === $next || !$tokens[$next]->equals('(')) {
  12440. return 1;
  12441. }
  12442. $next = $tokens->getNextMeaningfulToken($next);
  12443. if (null === $next || !$tokens[$next]->equals([T_STRING, 'strict_types'], false)) {
  12444. return 1;
  12445. }
  12446. $next = $tokens->getNextMeaningfulToken($next);
  12447. if (null === $next || !$tokens[$next]->equals('=')) {
  12448. return 1;
  12449. }
  12450. $next = $tokens->getNextMeaningfulToken($next);
  12451. if (null === $next || !$tokens[$next]->isGivenKind(T_LNUMBER)) {
  12452. return 1;
  12453. }
  12454. $next = $tokens->getNextMeaningfulToken($next);
  12455. if (null === $next || !$tokens[$next]->equals(')')) {
  12456. return 1;
  12457. }
  12458. $next = $tokens->getNextMeaningfulToken($next);
  12459. if (null === $next || !$tokens[$next]->equals(';')) {
  12460. return 1;
  12461. }
  12462. return $next + 1;
  12463. }
  12464. private function fixWhiteSpaceAroundHeader(Tokens $tokens, $headerIndex)
  12465. {
  12466. $lineEnding = $this->whitespacesConfig->getLineEnding();
  12467. if (
  12468. ('both' === $this->configuration['separate'] || 'bottom' === $this->configuration['separate'])
  12469. && null !== $tokens->getNextMeaningfulToken($headerIndex)
  12470. ) {
  12471. $expectedLineCount = 2;
  12472. } else {
  12473. $expectedLineCount = 1;
  12474. }
  12475. if ($headerIndex === \count($tokens) - 1) {
  12476. $tokens->insertAt($headerIndex + 1, new Token([T_WHITESPACE, str_repeat($lineEnding, $expectedLineCount)]));
  12477. } else {
  12478. $lineBreakCount = $this->getLineBreakCount($tokens, $headerIndex, 1);
  12479. if ($lineBreakCount < $expectedLineCount) {
  12480. $missing = str_repeat($lineEnding, $expectedLineCount - $lineBreakCount);
  12481. if ($tokens[$headerIndex + 1]->isWhitespace()) {
  12482. $tokens[$headerIndex + 1] = new Token([T_WHITESPACE, $missing.$tokens[$headerIndex + 1]->getContent()]);
  12483. } else {
  12484. $tokens->insertAt($headerIndex + 1, new Token([T_WHITESPACE, $missing]));
  12485. }
  12486. } elseif ($lineBreakCount > $expectedLineCount && $tokens[$headerIndex + 1]->isWhitespace()) {
  12487. $newLinesToRemove = $lineBreakCount - $expectedLineCount;
  12488. $tokens[$headerIndex + 1] = new Token([
  12489. T_WHITESPACE,
  12490. Preg::replace("/^\\R{{$newLinesToRemove}}/", '', $tokens[$headerIndex + 1]->getContent()),
  12491. ]);
  12492. }
  12493. }
  12494. $expectedLineCount = 'both' === $this->configuration['separate'] || 'top' === $this->configuration['separate'] ? 2 : 1;
  12495. $prev = $tokens->getPrevNonWhitespace($headerIndex);
  12496. $regex = '/\h$/';
  12497. if ($tokens[$prev]->isGivenKind(T_OPEN_TAG) && Preg::match($regex, $tokens[$prev]->getContent())) {
  12498. $tokens[$prev] = new Token([T_OPEN_TAG, Preg::replace($regex, $lineEnding, $tokens[$prev]->getContent())]);
  12499. }
  12500. $lineBreakCount = $this->getLineBreakCount($tokens, $headerIndex, -1);
  12501. if ($lineBreakCount < $expectedLineCount) {
  12502. $tokens->insertAt($headerIndex, new Token([T_WHITESPACE, str_repeat($lineEnding, $expectedLineCount - $lineBreakCount)]));
  12503. }
  12504. }
  12505. private function getLineBreakCount(Tokens $tokens, $index, $direction)
  12506. {
  12507. $whitespace = '';
  12508. for ($index += $direction; isset($tokens[$index]); $index += $direction) {
  12509. $token = $tokens[$index];
  12510. if ($token->isWhitespace()) {
  12511. $whitespace .= $token->getContent();
  12512. continue;
  12513. }
  12514. if (-1 === $direction && $token->isGivenKind(T_OPEN_TAG)) {
  12515. $whitespace .= $token->getContent();
  12516. }
  12517. if ('' !== $token->getContent()) {
  12518. break;
  12519. }
  12520. }
  12521. return substr_count($whitespace, "\n");
  12522. }
  12523. private function removeHeader(Tokens $tokens, $index)
  12524. {
  12525. $prevIndex = $index - 1;
  12526. $prevToken = $tokens[$prevIndex];
  12527. $newlineRemoved = false;
  12528. if ($prevToken->isWhitespace()) {
  12529. $content = $prevToken->getContent();
  12530. if (Preg::match('/\R/', $content)) {
  12531. $newlineRemoved = true;
  12532. }
  12533. $content = Preg::replace('/\R?\h*$/', '', $content);
  12534. if ('' !== $content) {
  12535. $tokens[$prevIndex] = new Token([T_WHITESPACE, $content]);
  12536. } else {
  12537. $tokens->clearAt($prevIndex);
  12538. }
  12539. }
  12540. $nextIndex = $index + 1;
  12541. $nextToken = isset($tokens[$nextIndex]) ? $tokens[$nextIndex] : null;
  12542. if (!$newlineRemoved && null !== $nextToken && $nextToken->isWhitespace()) {
  12543. $content = Preg::replace('/^\R/', '', $nextToken->getContent());
  12544. if ('' !== $content) {
  12545. $tokens[$nextIndex] = new Token([T_WHITESPACE, $content]);
  12546. } else {
  12547. $tokens->clearAt($nextIndex);
  12548. }
  12549. }
  12550. $tokens->clearTokenAndMergeSurroundingWhitespace($index);
  12551. }
  12552. private function insertHeader(Tokens $tokens, $index)
  12553. {
  12554. $tokens->insertAt($index, new Token([self::HEADER_COMMENT === $this->configuration['comment_type'] ? T_COMMENT : T_DOC_COMMENT, $this->getHeaderAsComment()]));
  12555. $this->fixWhiteSpaceAroundHeader($tokens, $index);
  12556. }
  12557. }
  12558. <?php
  12559. namespace PhpCsFixer\Fixer;
  12560. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  12561. interface ConfigurationDefinitionFixerInterface extends ConfigurableFixerInterface
  12562. {
  12563. public function getConfigurationDefinition();
  12564. }
  12565. <?php
  12566. namespace PhpCsFixer\Fixer\Alias;
  12567. use PhpCsFixer\AbstractFixer;
  12568. use PhpCsFixer\FixerDefinition\CodeSample;
  12569. use PhpCsFixer\FixerDefinition\FixerDefinition;
  12570. use PhpCsFixer\Preg;
  12571. use PhpCsFixer\PregException;
  12572. use PhpCsFixer\Tokenizer\Analyzer\FunctionsAnalyzer;
  12573. use PhpCsFixer\Tokenizer\Token;
  12574. use PhpCsFixer\Tokenizer\Tokens;
  12575. use PhpCsFixer\Utils;
  12576. final class EregToPregFixer extends AbstractFixer
  12577. {
  12578. private static $functions = [
  12579. ['ereg', 'preg_match', ''],
  12580. ['eregi', 'preg_match', 'i'],
  12581. ['ereg_replace', 'preg_replace', ''],
  12582. ['eregi_replace', 'preg_replace', 'i'],
  12583. ['split', 'preg_split', ''],
  12584. ['spliti', 'preg_split', 'i'],
  12585. ];
  12586. private static $delimiters = ['/', '#', '!'];
  12587. public function getDefinition()
  12588. {
  12589. return new FixerDefinition(
  12590. 'Replace deprecated `ereg` regular expression functions with `preg`.',
  12591. [new CodeSample("<?php \$x = ereg('[A-Z]');\n")],
  12592. null,
  12593. 'Risky if the `ereg` function is overridden.'
  12594. );
  12595. }
  12596. public function isCandidate(Tokens $tokens)
  12597. {
  12598. return $tokens->isTokenKindFound(T_STRING);
  12599. }
  12600. public function isRisky()
  12601. {
  12602. return true;
  12603. }
  12604. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  12605. {
  12606. $end = $tokens->count() - 1;
  12607. $functionsAnalyzer = new FunctionsAnalyzer();
  12608. foreach (self::$functions as $map) {
  12609. $seq = [[T_STRING, $map[0]], '(', [T_CONSTANT_ENCAPSED_STRING]];
  12610. $currIndex = 0;
  12611. while (null !== $currIndex) {
  12612. $match = $tokens->findSequence($seq, $currIndex, $end, false);
  12613. if (null === $match) {
  12614. break;
  12615. }
  12616. $match = array_keys($match);
  12617. $currIndex = $match[2];
  12618. if (!$functionsAnalyzer->isGlobalFunctionCall($tokens, $match[0])) {
  12619. continue;
  12620. }
  12621. $next = $tokens->getNextMeaningfulToken($match[2]);
  12622. if (null === $next || !$tokens[$next]->equalsAny([',', ')'])) {
  12623. continue;
  12624. }
  12625. $regexTokenContent = $tokens[$match[2]]->getContent();
  12626. $string = substr($regexTokenContent, 1, -1);
  12627. $quote = $regexTokenContent[0];
  12628. $delim = $this->getBestDelimiter($string);
  12629. $preg = $delim.addcslashes($string, $delim).$delim.'D'.$map[2];
  12630. if (!$this->checkPreg($preg)) {
  12631. continue;
  12632. }
  12633. $tokens[$match[0]] = new Token([T_STRING, $map[1]]);
  12634. $tokens[$match[2]] = new Token([T_CONSTANT_ENCAPSED_STRING, $quote.$preg.$quote]);
  12635. }
  12636. }
  12637. }
  12638. private function checkPreg($pattern)
  12639. {
  12640. try {
  12641. Preg::match($pattern, '');
  12642. return true;
  12643. } catch (PregException $e) {
  12644. return false;
  12645. }
  12646. }
  12647. private function getBestDelimiter($pattern)
  12648. {
  12649. $delimiters = [];
  12650. foreach (self::$delimiters as $k => $d) {
  12651. if (false === strpos($pattern, $d)) {
  12652. return $d;
  12653. }
  12654. $delimiters[$d] = [substr_count($pattern, $d), $k];
  12655. }
  12656. uasort($delimiters, static function ($a, $b) {
  12657. if ($a[0] === $b[0]) {
  12658. return Utils::cmpInt($a, $b);
  12659. }
  12660. return $a[0] < $b[0] ? -1 : 1;
  12661. });
  12662. return key($delimiters);
  12663. }
  12664. }
  12665. <?php
  12666. namespace PhpCsFixer\Fixer\Alias;
  12667. use PhpCsFixer\AbstractFunctionReferenceFixer;
  12668. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  12669. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverRootless;
  12670. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  12671. use PhpCsFixer\FixerDefinition\CodeSample;
  12672. use PhpCsFixer\FixerDefinition\FixerDefinition;
  12673. use PhpCsFixer\Tokenizer\Analyzer\ArgumentsAnalyzer;
  12674. use PhpCsFixer\Tokenizer\Token;
  12675. use PhpCsFixer\Tokenizer\Tokens;
  12676. use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException;
  12677. final class RandomApiMigrationFixer extends AbstractFunctionReferenceFixer implements ConfigurationDefinitionFixerInterface
  12678. {
  12679. private static $argumentCounts = [
  12680. 'getrandmax' => [0],
  12681. 'mt_rand' => [1, 2],
  12682. 'rand' => [0, 2],
  12683. 'srand' => [0, 1],
  12684. ];
  12685. public function configure(array $configuration = null)
  12686. {
  12687. parent::configure($configuration);
  12688. foreach ($this->configuration['replacements'] as $functionName => $replacement) {
  12689. $this->configuration['replacements'][$functionName] = [
  12690. 'alternativeName' => $replacement,
  12691. 'argumentCount' => self::$argumentCounts[$functionName],
  12692. ];
  12693. }
  12694. }
  12695. public function getDefinition()
  12696. {
  12697. return new FixerDefinition(
  12698. 'Replaces `rand`, `srand`, `getrandmax` functions calls with their `mt_*` analogs.',
  12699. [
  12700. new CodeSample("<?php\n\$a = getrandmax();\n\$a = rand(\$b, \$c);\n\$a = srand();\n"),
  12701. new CodeSample(
  12702. "<?php\n\$a = getrandmax();\n\$a = rand(\$b, \$c);\n\$a = srand();\n",
  12703. ['replacements' => ['getrandmax' => 'mt_getrandmax']]
  12704. ),
  12705. ],
  12706. null,
  12707. 'Risky when the configured functions are overridden.'
  12708. );
  12709. }
  12710. public function isCandidate(Tokens $tokens)
  12711. {
  12712. return $tokens->isTokenKindFound(T_STRING);
  12713. }
  12714. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  12715. {
  12716. $argumentsAnalyzer = new ArgumentsAnalyzer();
  12717. foreach ($this->configuration['replacements'] as $functionIdentity => $functionReplacement) {
  12718. if ($functionIdentity === $functionReplacement['alternativeName']) {
  12719. continue;
  12720. }
  12721. $currIndex = 0;
  12722. while (null !== $currIndex) {
  12723. $boundaries = $this->find($functionIdentity, $tokens, $currIndex, $tokens->count() - 1);
  12724. if (null === $boundaries) {
  12725. continue 2;
  12726. }
  12727. list($functionName, $openParenthesis, $closeParenthesis) = $boundaries;
  12728. $count = $argumentsAnalyzer->countArguments($tokens, $openParenthesis, $closeParenthesis);
  12729. if (!\in_array($count, $functionReplacement['argumentCount'], true)) {
  12730. continue 2;
  12731. }
  12732. $currIndex = $openParenthesis;
  12733. $tokens[$functionName] = new Token([T_STRING, $functionReplacement['alternativeName']]);
  12734. if (0 === $count && 'random_int' === $functionReplacement['alternativeName']) {
  12735. $tokens->insertAt($currIndex + 1, [
  12736. new Token([T_LNUMBER, '0']),
  12737. new Token(','),
  12738. new Token([T_WHITESPACE, ' ']),
  12739. new Token([T_STRING, 'getrandmax']),
  12740. new Token('('),
  12741. new Token(')'),
  12742. ]);
  12743. $currIndex += 6;
  12744. }
  12745. }
  12746. }
  12747. }
  12748. protected function createConfigurationDefinition()
  12749. {
  12750. return new FixerConfigurationResolverRootless('replacements', [
  12751. (new FixerOptionBuilder('replacements', 'Mapping between replaced functions with the new ones.'))
  12752. ->setAllowedTypes(['array'])
  12753. ->setAllowedValues([static function ($value) {
  12754. foreach ($value as $functionName => $replacement) {
  12755. if (!\array_key_exists($functionName, self::$argumentCounts)) {
  12756. throw new InvalidOptionsException(sprintf(
  12757. 'Function "%s" is not handled by the fixer.',
  12758. $functionName
  12759. ));
  12760. }
  12761. if (!\is_string($replacement)) {
  12762. throw new InvalidOptionsException(sprintf(
  12763. 'Replacement for function "%s" must be a string, "%s" given.',
  12764. $functionName,
  12765. \is_object($replacement) ? \get_class($replacement) : \gettype($replacement)
  12766. ));
  12767. }
  12768. }
  12769. return true;
  12770. }])
  12771. ->setDefault([
  12772. 'getrandmax' => 'mt_getrandmax',
  12773. 'rand' => 'mt_rand',
  12774. 'srand' => 'mt_srand',
  12775. ])
  12776. ->getOption(),
  12777. ], $this->getName());
  12778. }
  12779. }
  12780. <?php
  12781. namespace PhpCsFixer\Fixer\Alias;
  12782. use PhpCsFixer\AbstractFixer;
  12783. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  12784. use PhpCsFixer\FixerConfiguration\AllowedValueSubset;
  12785. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  12786. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  12787. use PhpCsFixer\FixerDefinition\CodeSample;
  12788. use PhpCsFixer\FixerDefinition\FixerDefinition;
  12789. use PhpCsFixer\Tokenizer\Analyzer\FunctionsAnalyzer;
  12790. use PhpCsFixer\Tokenizer\Token;
  12791. use PhpCsFixer\Tokenizer\Tokens;
  12792. /**
  12793. @gmail
  12794. */
  12795. final class NoAliasFunctionsFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface
  12796. {
  12797. private $aliases = [];
  12798. private static $internalSet = [
  12799. 'chop' => 'rtrim',
  12800. 'close' => 'closedir',
  12801. 'doubleval' => 'floatval',
  12802. 'fputs' => 'fwrite',
  12803. 'get_required_files' => 'get_included_files',
  12804. 'ini_alter' => 'ini_set',
  12805. 'is_double' => 'is_float',
  12806. 'is_integer' => 'is_int',
  12807. 'is_long' => 'is_int',
  12808. 'is_real' => 'is_float',
  12809. 'is_writeable' => 'is_writable',
  12810. 'join' => 'implode',
  12811. 'key_exists' => 'array_key_exists',
  12812. 'magic_quotes_runtime' => 'set_magic_quotes_runtime',
  12813. 'pos' => 'current',
  12814. 'show_source' => 'highlight_file',
  12815. 'sizeof' => 'count',
  12816. 'strchr' => 'strstr',
  12817. 'user_error' => 'trigger_error',
  12818. ];
  12819. private static $imapSet = [
  12820. 'imap_create' => 'imap_createmailbox',
  12821. 'imap_fetchtext' => 'imap_body',
  12822. 'imap_header' => 'imap_headerinfo',
  12823. 'imap_listmailbox' => 'imap_list',
  12824. 'imap_listsubscribed' => 'imap_lsub',
  12825. 'imap_rename' => 'imap_renamemailbox',
  12826. 'imap_scan' => 'imap_listscan',
  12827. 'imap_scanmailbox' => 'imap_listscan',
  12828. ];
  12829. private static $mbregSet = [
  12830. 'mbereg' => 'mb_ereg',
  12831. 'mbereg_match' => 'mb_ereg_match',
  12832. 'mbereg_replace' => 'mb_ereg_replace',
  12833. 'mbereg_search' => 'mb_ereg_search',
  12834. 'mbereg_search_getpos' => 'mb_ereg_search_getpos',
  12835. 'mbereg_search_getregs' => 'mb_ereg_search_getregs',
  12836. 'mbereg_search_init' => 'mb_ereg_search_init',
  12837. 'mbereg_search_pos' => 'mb_ereg_search_pos',
  12838. 'mbereg_search_regs' => 'mb_ereg_search_regs',
  12839. 'mbereg_search_setpos' => 'mb_ereg_search_setpos',
  12840. 'mberegi' => 'mb_eregi',
  12841. 'mberegi_replace' => 'mb_eregi_replace',
  12842. 'mbregex_encoding' => 'mb_regex_encoding',
  12843. 'mbsplit' => 'mb_split',
  12844. ];
  12845. public function configure(array $configuration = null)
  12846. {
  12847. parent::configure($configuration);
  12848. $this->aliases = [];
  12849. foreach ($this->configuration['sets'] as $set) {
  12850. if ('@all' === $set) {
  12851. $this->aliases = self::$internalSet;
  12852. $this->aliases = array_merge($this->aliases, self::$imapSet);
  12853. $this->aliases = array_merge($this->aliases, self::$mbregSet);
  12854. break;
  12855. }
  12856. if ('@internal' === $set) {
  12857. $this->aliases = array_merge($this->aliases, self::$internalSet);
  12858. } elseif ('@IMAP' === $set) {
  12859. $this->aliases = array_merge($this->aliases, self::$imapSet);
  12860. } elseif ('@mbreg' === $set) {
  12861. $this->aliases = array_merge($this->aliases, self::$mbregSet);
  12862. }
  12863. }
  12864. }
  12865. public function getDefinition()
  12866. {
  12867. return new FixerDefinition(
  12868. 'Master functions shall be used instead of aliases.',
  12869. [
  12870. new CodeSample(
  12871. '<?php
  12872. $a = chop($b);
  12873. close($b);
  12874. $a = doubleval($b);
  12875. $a = fputs($b, $c);
  12876. $a = get_required_files();
  12877. ini_alter($b, $c);
  12878. $a = is_double($b);
  12879. $a = is_integer($b);
  12880. $a = is_long($b);
  12881. $a = is_real($b);
  12882. $a = is_writeable($b);
  12883. $a = join($glue, $pieces);
  12884. $a = key_exists($key, $array);
  12885. magic_quotes_runtime($new_setting);
  12886. $a = pos($array);
  12887. $a = show_source($filename, true);
  12888. $a = sizeof($b);
  12889. $a = strchr($haystack, $needle);
  12890. $a = imap_header($imap_stream, 1);
  12891. user_error($message);
  12892. mbereg_search_getregs();
  12893. '
  12894. ),
  12895. new CodeSample(
  12896. '<?php
  12897. $a = is_double($b);
  12898. mbereg_search_getregs();
  12899. ',
  12900. ['sets' => ['@mbreg']]
  12901. ),
  12902. ],
  12903. null,
  12904. 'Risky when any of the alias functions are overridden.'
  12905. );
  12906. }
  12907. public function getPriority()
  12908. {
  12909. return 0;
  12910. }
  12911. public function isCandidate(Tokens $tokens)
  12912. {
  12913. return $tokens->isTokenKindFound(T_STRING);
  12914. }
  12915. public function isRisky()
  12916. {
  12917. return true;
  12918. }
  12919. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  12920. {
  12921. $functionsAnalyzer = new FunctionsAnalyzer();
  12922. foreach ($tokens->findGivenKind(T_STRING) as $index => $token) {
  12923. $tokenContent = strtolower($token->getContent());
  12924. if (!isset($this->aliases[$tokenContent])) {
  12925. continue;
  12926. }
  12927. $nextToken = $tokens[$tokens->getNextMeaningfulToken($index)];
  12928. if (!$nextToken->equals('(')) {
  12929. continue;
  12930. }
  12931. if (!$functionsAnalyzer->isGlobalFunctionCall($tokens, $index)) {
  12932. continue;
  12933. }
  12934. $tokens[$index] = new Token([T_STRING, $this->aliases[$tokenContent]]);
  12935. }
  12936. }
  12937. protected function createConfigurationDefinition()
  12938. {
  12939. $sets = ['@internal', '@IMAP', '@mbreg', '@all'];
  12940. return new FixerConfigurationResolver([
  12941. (new FixerOptionBuilder('sets', 'List of sets to fix. Defined sets are `@internal` (native functions), `@IMAP` (IMAP functions), `@mbreg` (from `ext-mbstring`) `@all` (all listed sets).'))
  12942. ->setAllowedTypes(['array'])
  12943. ->setAllowedValues([new AllowedValueSubset($sets)])
  12944. ->setDefault(['@internal', '@IMAP'])
  12945. ->getOption(),
  12946. ]);
  12947. }
  12948. }
  12949. <?php
  12950. namespace PhpCsFixer\Fixer\Alias;
  12951. use PhpCsFixer\AbstractFixer;
  12952. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  12953. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  12954. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  12955. use PhpCsFixer\FixerDefinition\CodeSample;
  12956. use PhpCsFixer\FixerDefinition\FixerDefinition;
  12957. use PhpCsFixer\Tokenizer\CT;
  12958. use PhpCsFixer\Tokenizer\Token;
  12959. use PhpCsFixer\Tokenizer\Tokens;
  12960. final class NoMixedEchoPrintFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface
  12961. {
  12962. public static $defaultConfig = ['use' => 'echo'];
  12963. private $callBack;
  12964. private $candidateTokenType;
  12965. public function configure(array $configuration = null)
  12966. {
  12967. parent::configure($configuration);
  12968. if ('echo' === $this->configuration['use']) {
  12969. $this->candidateTokenType = T_PRINT;
  12970. $this->callBack = 'fixPrintToEcho';
  12971. } else {
  12972. $this->candidateTokenType = T_ECHO;
  12973. $this->callBack = 'fixEchoToPrint';
  12974. }
  12975. }
  12976. public function getDefinition()
  12977. {
  12978. return new FixerDefinition(
  12979. 'Either language construct `print` or `echo` should be used.',
  12980. [
  12981. new CodeSample("<?php print 'example';\n"),
  12982. new CodeSample("<?php echo('example');\n", ['use' => 'print']),
  12983. ]
  12984. );
  12985. }
  12986. public function getPriority()
  12987. {
  12988. return -10;
  12989. }
  12990. public function isCandidate(Tokens $tokens)
  12991. {
  12992. return $tokens->isTokenKindFound($this->candidateTokenType);
  12993. }
  12994. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  12995. {
  12996. $callBack = $this->callBack;
  12997. foreach ($tokens as $index => $token) {
  12998. if ($token->isGivenKind($this->candidateTokenType)) {
  12999. $this->{$callBack}($tokens, $index);
  13000. }
  13001. }
  13002. }
  13003. protected function createConfigurationDefinition()
  13004. {
  13005. return new FixerConfigurationResolver([
  13006. (new FixerOptionBuilder('use', 'The desired language construct.'))
  13007. ->setAllowedValues(['print', 'echo'])
  13008. ->setDefault('echo')
  13009. ->getOption(),
  13010. ]);
  13011. }
  13012. private function fixEchoToPrint(Tokens $tokens, $index)
  13013. {
  13014. $nextTokenIndex = $tokens->getNextMeaningfulToken($index);
  13015. $endTokenIndex = $tokens->getNextTokenOfKind($index, [';', [T_CLOSE_TAG]]);
  13016. $canBeConverted = true;
  13017. for ($i = $nextTokenIndex; $i < $endTokenIndex; ++$i) {
  13018. if ($tokens[$i]->equalsAny(['(', [CT::T_ARRAY_SQUARE_BRACE_OPEN]])) {
  13019. $blockType = Tokens::detectBlockType($tokens[$i]);
  13020. $i = $tokens->findBlockEnd($blockType['type'], $i);
  13021. }
  13022. if ($tokens[$i]->equals(',')) {
  13023. $canBeConverted = false;
  13024. break;
  13025. }
  13026. }
  13027. if (false === $canBeConverted) {
  13028. return;
  13029. }
  13030. $tokens[$index] = new Token([T_PRINT, 'print']);
  13031. }
  13032. private function fixPrintToEcho(Tokens $tokens, $index)
  13033. {
  13034. $prevToken = $tokens[$tokens->getPrevMeaningfulToken($index)];
  13035. if (!$prevToken->equalsAny([';', '{', '}', [T_OPEN_TAG]])) {
  13036. return;
  13037. }
  13038. $tokens[$index] = new Token([T_ECHO, 'echo']);
  13039. }
  13040. }
  13041. <?php
  13042. namespace PhpCsFixer\Fixer\Alias;
  13043. use PhpCsFixer\AbstractFunctionReferenceFixer;
  13044. use PhpCsFixer\FixerDefinition\CodeSample;
  13045. use PhpCsFixer\FixerDefinition\FixerDefinition;
  13046. use PhpCsFixer\Tokenizer\Analyzer\ArgumentsAnalyzer;
  13047. use PhpCsFixer\Tokenizer\Token;
  13048. use PhpCsFixer\Tokenizer\Tokens;
  13049. final class SetTypeToCastFixer extends AbstractFunctionReferenceFixer
  13050. {
  13051. public function getDefinition()
  13052. {
  13053. return new FixerDefinition(
  13054. 'Cast shall be used, not `settype`.',
  13055. [
  13056. new CodeSample(
  13057. '<?php
  13058. settype($foo, "integer");
  13059. settype($bar, "string");
  13060. settype($bar, "null");
  13061. '
  13062. ),
  13063. ],
  13064. null,
  13065. 'Risky when the `settype` function is overridden or when used as the 2nd or 3rd expression in a `for` loop .'
  13066. );
  13067. }
  13068. public function isCandidate(Tokens $tokens)
  13069. {
  13070. return $tokens->isAllTokenKindsFound([T_CONSTANT_ENCAPSED_STRING, T_STRING, T_VARIABLE]);
  13071. }
  13072. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  13073. {
  13074. $map = [
  13075. 'array' => [T_ARRAY_CAST, '(array)'],
  13076. 'bool' => [T_BOOL_CAST, '(bool)'],
  13077. 'boolean' => [T_BOOL_CAST, '(bool)'],
  13078. 'double' => [T_DOUBLE_CAST, '(float)'],
  13079. 'float' => [T_DOUBLE_CAST, '(float)'],
  13080. 'int' => [T_INT_CAST, '(int)'],
  13081. 'integer' => [T_INT_CAST, '(int)'],
  13082. 'object' => [T_OBJECT_CAST, '(object)'],
  13083. 'string' => [T_STRING_CAST, '(string)'],
  13084. ];
  13085. $argumentsAnalyzer = new ArgumentsAnalyzer();
  13086. foreach (array_reverse($this->findSettypeCalls($tokens)) as $candidate) {
  13087. $functionNameIndex = $candidate[0];
  13088. $arguments = $argumentsAnalyzer->getArguments($tokens, $candidate[1], $candidate[2]);
  13089. if (2 !== \count($arguments)) {
  13090. continue;
  13091. }
  13092. $prev = $tokens->getPrevMeaningfulToken($functionNameIndex);
  13093. if (!$tokens[$prev]->isGivenKind(T_OPEN_TAG) && !$tokens[$prev]->equalsAny([';', '{'])) {
  13094. continue;
  13095. }
  13096. reset($arguments);
  13097. $firstArgumentStart = key($arguments);
  13098. if ($tokens[$firstArgumentStart]->isComment() || $tokens[$firstArgumentStart]->isWhitespace()) {
  13099. $firstArgumentStart = $tokens->getNextMeaningfulToken($firstArgumentStart);
  13100. }
  13101. if (!$tokens[$firstArgumentStart]->isGivenKind(T_VARIABLE)) {
  13102. continue;
  13103. }
  13104. $commaIndex = $tokens->getNextMeaningfulToken($firstArgumentStart);
  13105. if (null === $commaIndex || !$tokens[$commaIndex]->equals(',')) {
  13106. continue;
  13107. }
  13108. next($arguments);
  13109. $secondArgumentStart = key($arguments);
  13110. $secondArgumentEnd = $arguments[$secondArgumentStart];
  13111. if ($tokens[$secondArgumentStart]->isComment() || $tokens[$secondArgumentStart]->isWhitespace()) {
  13112. $secondArgumentStart = $tokens->getNextMeaningfulToken($secondArgumentStart);
  13113. }
  13114. if (
  13115. !$tokens[$secondArgumentStart]->isGivenKind(T_CONSTANT_ENCAPSED_STRING)
  13116. || $tokens->getNextMeaningfulToken($secondArgumentStart) < $secondArgumentEnd
  13117. ) {
  13118. continue;
  13119. }
  13120. $type = strtolower(trim($tokens[$secondArgumentStart]->getContent(), '"\'"'));
  13121. if ('null' !== $type && !isset($map[$type])) {
  13122. continue;
  13123. }
  13124. $argumentToken = $tokens[$firstArgumentStart];
  13125. $this->removeSettypeCall(
  13126. $tokens,
  13127. $functionNameIndex,
  13128. $candidate[1],
  13129. $firstArgumentStart,
  13130. $commaIndex,
  13131. $secondArgumentStart,
  13132. $candidate[2]
  13133. );
  13134. if ('null' === $type) {
  13135. $this->findSettypeNullCall($tokens, $functionNameIndex, $argumentToken);
  13136. } else {
  13137. $this->fixSettypeCall($tokens, $functionNameIndex, $argumentToken, new Token($map[$type]));
  13138. }
  13139. }
  13140. }
  13141. private function findSettypeCalls(Tokens $tokens)
  13142. {
  13143. $candidates = [];
  13144. $end = \count($tokens);
  13145. for ($i = 1; $i < $end; ++$i) {
  13146. $candidate = $this->find('settype', $tokens, $i, $end);
  13147. if (null === $candidate) {
  13148. break;
  13149. }
  13150. $i = $candidate[1];
  13151. $candidates[] = $candidate;
  13152. }
  13153. return $candidates;
  13154. }
  13155. private function removeSettypeCall(
  13156. Tokens $tokens,
  13157. $functionNameIndex,
  13158. $openParenthesisIndex,
  13159. $firstArgumentStart,
  13160. $commaIndex,
  13161. $secondArgumentStart,
  13162. $closeParenthesisIndex
  13163. ) {
  13164. $tokens->clearTokenAndMergeSurroundingWhitespace($closeParenthesisIndex);
  13165. $prevIndex = $tokens->getPrevMeaningfulToken($closeParenthesisIndex);
  13166. if ($tokens[$prevIndex]->equals(',')) {
  13167. $tokens->clearTokenAndMergeSurroundingWhitespace($prevIndex);
  13168. }
  13169. $tokens->clearTokenAndMergeSurroundingWhitespace($secondArgumentStart);
  13170. $tokens->clearTokenAndMergeSurroundingWhitespace($commaIndex);
  13171. $tokens->clearTokenAndMergeSurroundingWhitespace($firstArgumentStart);
  13172. $tokens->clearTokenAndMergeSurroundingWhitespace($openParenthesisIndex);
  13173. $tokens->clearAt($functionNameIndex);
  13174. $tokens->clearEmptyTokens();
  13175. }
  13176. private function fixSettypeCall(
  13177. Tokens $tokens,
  13178. $functionNameIndex,
  13179. Token $argumentToken,
  13180. Token $castToken
  13181. ) {
  13182. $tokens->insertAt(
  13183. $functionNameIndex,
  13184. [
  13185. clone $argumentToken,
  13186. new Token([T_WHITESPACE, ' ']),
  13187. new Token('='),
  13188. new Token([T_WHITESPACE, ' ']),
  13189. $castToken,
  13190. new Token([T_WHITESPACE, ' ']),
  13191. clone $argumentToken,
  13192. ]
  13193. );
  13194. $tokens->removeTrailingWhitespace($functionNameIndex + 6);
  13195. }
  13196. private function findSettypeNullCall(
  13197. Tokens $tokens,
  13198. $functionNameIndex,
  13199. Token $argumentToken
  13200. ) {
  13201. $tokens->insertAt(
  13202. $functionNameIndex,
  13203. [
  13204. clone $argumentToken,
  13205. new Token([T_WHITESPACE, ' ']),
  13206. new Token('='),
  13207. new Token([T_WHITESPACE, ' ']),
  13208. new Token([T_STRING, 'null']),
  13209. ]
  13210. );
  13211. $tokens->removeTrailingWhitespace($functionNameIndex + 4);
  13212. }
  13213. }
  13214. <?php
  13215. namespace PhpCsFixer\Fixer\Alias;
  13216. use PhpCsFixer\AbstractFunctionReferenceFixer;
  13217. use PhpCsFixer\FixerDefinition\CodeSample;
  13218. use PhpCsFixer\FixerDefinition\FixerDefinition;
  13219. use PhpCsFixer\Tokenizer\Analyzer\ArgumentsAnalyzer;
  13220. use PhpCsFixer\Tokenizer\CT;
  13221. use PhpCsFixer\Tokenizer\Token;
  13222. use PhpCsFixer\Tokenizer\Tokens;
  13223. final class PowToExponentiationFixer extends AbstractFunctionReferenceFixer
  13224. {
  13225. public function isCandidate(Tokens $tokens)
  13226. {
  13227. return $tokens->count() > 7 && $tokens->isTokenKindFound(T_STRING);
  13228. }
  13229. public function getDefinition()
  13230. {
  13231. return new FixerDefinition(
  13232. 'Converts `pow` to the `**` operator.',
  13233. [
  13234. new CodeSample(
  13235. "<?php\n pow(\$a, 1);\n"
  13236. ),
  13237. ],
  13238. null,
  13239. 'Risky when the function `pow` is overridden.'
  13240. );
  13241. }
  13242. public function getPriority()
  13243. {
  13244. return 3;
  13245. }
  13246. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  13247. {
  13248. $candidates = $this->findPowCalls($tokens);
  13249. $argumentsAnalyzer = new ArgumentsAnalyzer();
  13250. $numberOfTokensAdded = 0;
  13251. $previousCloseParenthesisIndex = \count($tokens);
  13252. foreach (array_reverse($candidates) as $candidate) {
  13253. if ($previousCloseParenthesisIndex < $candidate[2]) {
  13254. $previousCloseParenthesisIndex = $candidate[2];
  13255. $candidate[2] += $numberOfTokensAdded;
  13256. } else {
  13257. $previousCloseParenthesisIndex = $candidate[2];
  13258. $numberOfTokensAdded = 0;
  13259. }
  13260. $arguments = $argumentsAnalyzer->getArguments($tokens, $candidate[1], $candidate[2]);
  13261. if (2 !== \count($arguments)) {
  13262. continue;
  13263. }
  13264. $numberOfTokensAdded += $this->fixPowToExponentiation(
  13265. $tokens,
  13266. $candidate[0],
  13267. $candidate[1],
  13268. $candidate[2],
  13269. $arguments
  13270. );
  13271. }
  13272. }
  13273. private function findPowCalls(Tokens $tokens)
  13274. {
  13275. $candidates = [];
  13276. $end = \count($tokens) - 6;
  13277. for ($i = 1; $i < $end; ++$i) {
  13278. $candidate = $this->find('pow', $tokens, $i, $end);
  13279. if (null === $candidate) {
  13280. break;
  13281. }
  13282. $i = $candidate[1];
  13283. $candidates[] = $candidate;
  13284. }
  13285. return $candidates;
  13286. }
  13287. private function fixPowToExponentiation(Tokens $tokens, $functionNameIndex, $openParenthesisIndex, $closeParenthesisIndex, array $arguments)
  13288. {
  13289. $tokens[$tokens->getNextTokenOfKind(reset($arguments), [','])] = new Token([T_POW, '**']);
  13290. $tokens->clearAt($closeParenthesisIndex);
  13291. $previousIndex = $tokens->getPrevMeaningfulToken($closeParenthesisIndex);
  13292. if ($tokens[$previousIndex]->equals(',')) {
  13293. $tokens->clearAt($previousIndex);
  13294. }
  13295. $added = 0;
  13296. foreach (array_reverse($arguments, true) as $argumentStartIndex => $argumentEndIndex) {
  13297. if ($this->isParenthesisNeeded($tokens, $argumentStartIndex, $argumentEndIndex)) {
  13298. $tokens->insertAt($argumentEndIndex + 1, new Token(')'));
  13299. $tokens->insertAt($argumentStartIndex, new Token('('));
  13300. $added += 2;
  13301. }
  13302. }
  13303. $tokens->clearAt($openParenthesisIndex);
  13304. $tokens->clearAt($functionNameIndex);
  13305. $prev = $tokens->getPrevMeaningfulToken($functionNameIndex);
  13306. if ($tokens[$prev]->isGivenKind(T_NS_SEPARATOR)) {
  13307. $tokens->clearAt($prev);
  13308. }
  13309. return $added;
  13310. }
  13311. private function isParenthesisNeeded(Tokens $tokens, $argumentStartIndex, $argumentEndIndex)
  13312. {
  13313. static $allowedKinds = [
  13314. T_DNUMBER, T_LNUMBER, T_VARIABLE, T_STRING, T_OBJECT_OPERATOR, T_CONSTANT_ENCAPSED_STRING, T_DOUBLE_CAST,
  13315. T_INT_CAST, T_INC, T_DEC, T_NS_SEPARATOR, T_WHITESPACE, T_DOUBLE_COLON, T_LINE, T_COMMENT, T_DOC_COMMENT,
  13316. CT::T_NAMESPACE_OPERATOR,
  13317. ];
  13318. for ($i = $argumentStartIndex; $i <= $argumentEndIndex; ++$i) {
  13319. if ($tokens[$i]->isGivenKind($allowedKinds) || $tokens->isEmptyAt($i)) {
  13320. continue;
  13321. }
  13322. if (null !== $blockType = Tokens::detectBlockType($tokens[$i])) {
  13323. $i = $tokens->findBlockEnd($blockType['type'], $i);
  13324. continue;
  13325. }
  13326. if ($tokens[$i]->equals('$')) {
  13327. $i = $tokens->getNextMeaningfulToken($i);
  13328. if ($tokens[$i]->isGivenKind(CT::T_DYNAMIC_VAR_BRACE_OPEN)) {
  13329. $i = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_DYNAMIC_VAR_BRACE, $i);
  13330. continue;
  13331. }
  13332. }
  13333. if ($tokens[$i]->equals('+') && $tokens->getPrevMeaningfulToken($i) < $argumentStartIndex) {
  13334. continue;
  13335. }
  13336. return true;
  13337. }
  13338. return false;
  13339. }
  13340. }
  13341. <?php
  13342. namespace PhpCsFixer\Fixer\Alias;
  13343. use PhpCsFixer\AbstractFunctionReferenceFixer;
  13344. use PhpCsFixer\FixerDefinition\CodeSample;
  13345. use PhpCsFixer\FixerDefinition\FixerDefinition;
  13346. use PhpCsFixer\Tokenizer\Analyzer\ArgumentsAnalyzer;
  13347. use PhpCsFixer\Tokenizer\Token;
  13348. use PhpCsFixer\Tokenizer\Tokens;
  13349. final class MbStrFunctionsFixer extends AbstractFunctionReferenceFixer
  13350. {
  13351. private static $functionsMap = [
  13352. 'str_split' => ['alternativeName' => 'mb_str_split', 'argumentCount' => [1, 2, 3]],
  13353. 'stripos' => ['alternativeName' => 'mb_stripos', 'argumentCount' => [2, 3]],
  13354. 'stristr' => ['alternativeName' => 'mb_stristr', 'argumentCount' => [2, 3]],
  13355. 'strlen' => ['alternativeName' => 'mb_strlen', 'argumentCount' => [1]],
  13356. 'strpos' => ['alternativeName' => 'mb_strpos', 'argumentCount' => [2, 3]],
  13357. 'strrchr' => ['alternativeName' => 'mb_strrchr', 'argumentCount' => [2]],
  13358. 'strripos' => ['alternativeName' => 'mb_strripos', 'argumentCount' => [2, 3]],
  13359. 'strrpos' => ['alternativeName' => 'mb_strrpos', 'argumentCount' => [2, 3]],
  13360. 'strstr' => ['alternativeName' => 'mb_strstr', 'argumentCount' => [2, 3]],
  13361. 'strtolower' => ['alternativeName' => 'mb_strtolower', 'argumentCount' => [1]],
  13362. 'strtoupper' => ['alternativeName' => 'mb_strtoupper', 'argumentCount' => [1]],
  13363. 'substr' => ['alternativeName' => 'mb_substr', 'argumentCount' => [2, 3]],
  13364. 'substr_count' => ['alternativeName' => 'mb_substr_count', 'argumentCount' => [2, 3, 4]],
  13365. ];
  13366. private $functions;
  13367. public function __construct()
  13368. {
  13369. parent::__construct();
  13370. $this->functions = array_filter(
  13371. self::$functionsMap,
  13372. static function (array $mapping) {
  13373. return \function_exists($mapping['alternativeName']) && (new \ReflectionFunction($mapping['alternativeName']))->isInternal();
  13374. }
  13375. );
  13376. }
  13377. public function getDefinition()
  13378. {
  13379. return new FixerDefinition(
  13380. 'Replace non multibyte-safe functions with corresponding mb function.',
  13381. [
  13382. new CodeSample(
  13383. '<?php
  13384. $a = strlen($a);
  13385. $a = strpos($a, $b);
  13386. $a = strrpos($a, $b);
  13387. $a = substr($a, $b);
  13388. $a = strtolower($a);
  13389. $a = strtoupper($a);
  13390. $a = stripos($a, $b);
  13391. $a = strripos($a, $b);
  13392. $a = strstr($a, $b);
  13393. $a = stristr($a, $b);
  13394. $a = strrchr($a, $b);
  13395. $a = substr_count($a, $b);
  13396. '
  13397. ),
  13398. ],
  13399. null,
  13400. 'Risky when any of the functions are overridden.'
  13401. );
  13402. }
  13403. public function isCandidate(Tokens $tokens)
  13404. {
  13405. return $tokens->isTokenKindFound(T_STRING);
  13406. }
  13407. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  13408. {
  13409. $argumentsAnalyzer = new ArgumentsAnalyzer();
  13410. foreach ($this->functions as $functionIdentity => $functionReplacement) {
  13411. $currIndex = 0;
  13412. while (null !== $currIndex) {
  13413. $boundaries = $this->find($functionIdentity, $tokens, $currIndex, $tokens->count() - 1);
  13414. if (null === $boundaries) {
  13415. continue 2;
  13416. }
  13417. list($functionName, $openParenthesis, $closeParenthesis) = $boundaries;
  13418. $count = $argumentsAnalyzer->countArguments($tokens, $openParenthesis, $closeParenthesis);
  13419. if (!\in_array($count, $functionReplacement['argumentCount'], true)) {
  13420. continue 2;
  13421. }
  13422. $currIndex = $openParenthesis;
  13423. $tokens[$functionName] = new Token([T_STRING, $functionReplacement['alternativeName']]);
  13424. }
  13425. }
  13426. }
  13427. }
  13428. <?php
  13429. namespace PhpCsFixer\Fixer\Alias;
  13430. use PhpCsFixer\AbstractFixer;
  13431. use PhpCsFixer\FixerDefinition\CodeSample;
  13432. use PhpCsFixer\FixerDefinition\FixerDefinition;
  13433. use PhpCsFixer\Preg;
  13434. use PhpCsFixer\Tokenizer\Token;
  13435. use PhpCsFixer\Tokenizer\Tokens;
  13436. final class BacktickToShellExecFixer extends AbstractFixer
  13437. {
  13438. public function isCandidate(Tokens $tokens)
  13439. {
  13440. return $tokens->isTokenKindFound('`');
  13441. }
  13442. public function getDefinition()
  13443. {
  13444. return new FixerDefinition(
  13445. 'Converts backtick operators to `shell_exec` calls.',
  13446. [
  13447. new CodeSample(
  13448. <<<'EOT'
  13449. <?php
  13450. $plain = `ls -lah`;
  13451. $withVar = `ls -lah $var1 ${var2} {$var3} {$var4[0]} {$var5->call()}`;
  13452. EOT
  13453. ),
  13454. ],
  13455. '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.'
  13456. );
  13457. }
  13458. public function getPriority()
  13459. {
  13460. return 2;
  13461. }
  13462. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  13463. {
  13464. $backtickStarted = false;
  13465. $backtickTokens = [];
  13466. for ($index = $tokens->count() - 1; $index > 0; --$index) {
  13467. $token = $tokens[$index];
  13468. if (!$token->equals('`')) {
  13469. if ($backtickStarted) {
  13470. $backtickTokens[$index] = $token;
  13471. }
  13472. continue;
  13473. }
  13474. $backtickTokens[$index] = $token;
  13475. if ($backtickStarted) {
  13476. $this->fixBackticks($tokens, $backtickTokens);
  13477. $backtickTokens = [];
  13478. }
  13479. $backtickStarted = !$backtickStarted;
  13480. }
  13481. }
  13482. private function fixBackticks(Tokens $tokens, array $backtickTokens)
  13483. {
  13484. ksort($backtickTokens);
  13485. $openingBacktickIndex = key($backtickTokens);
  13486. end($backtickTokens);
  13487. $closingBacktickIndex = key($backtickTokens);
  13488. array_shift($backtickTokens);
  13489. array_pop($backtickTokens);
  13490. $count = \count($backtickTokens);
  13491. $newTokens = [
  13492. new Token([T_STRING, 'shell_exec']),
  13493. new Token('('),
  13494. ];
  13495. if (1 !== $count) {
  13496. $newTokens[] = new Token('"');
  13497. }
  13498. foreach ($backtickTokens as $token) {
  13499. if (!$token->isGivenKind(T_ENCAPSED_AND_WHITESPACE)) {
  13500. $newTokens[] = $token;
  13501. continue;
  13502. }
  13503. $content = $token->getContent();
  13504. if (Preg::match('/[`"\']/u', $content)) {
  13505. return;
  13506. }
  13507. $kind = T_ENCAPSED_AND_WHITESPACE;
  13508. if (1 === $count) {
  13509. $content = '"'.$content.'"';
  13510. $kind = T_CONSTANT_ENCAPSED_STRING;
  13511. }
  13512. $newTokens[] = new Token([$kind, $content]);
  13513. }
  13514. if (1 !== $count) {
  13515. $newTokens[] = new Token('"');
  13516. }
  13517. $newTokens[] = new Token(')');
  13518. $tokens->overrideRange($openingBacktickIndex, $closingBacktickIndex, $newTokens);
  13519. }
  13520. }
  13521. <?php
  13522. namespace PhpCsFixer\Fixer\PhpUnit;
  13523. use PhpCsFixer\AbstractFixer;
  13524. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  13525. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  13526. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  13527. use PhpCsFixer\FixerDefinition\CodeSample;
  13528. use PhpCsFixer\FixerDefinition\FixerDefinition;
  13529. use PhpCsFixer\Indicator\PhpUnitTestCaseIndicator;
  13530. use PhpCsFixer\Tokenizer\Analyzer\ArgumentsAnalyzer;
  13531. use PhpCsFixer\Tokenizer\Token;
  13532. use PhpCsFixer\Tokenizer\Tokens;
  13533. final class PhpUnitMockFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface
  13534. {
  13535. private $fixCreatePartialMock;
  13536. public function getDefinition()
  13537. {
  13538. return new FixerDefinition(
  13539. 'Usages of `->getMock` and `->getMockWithoutInvokingTheOriginalConstructor` methods MUST be replaced by `->createMock` or `->createPartialMock` methods.',
  13540. [
  13541. new CodeSample(
  13542. '<?php
  13543. final class MyTest extends \PHPUnit_Framework_TestCase
  13544. {
  13545. public function testFoo()
  13546. {
  13547. $mock = $this->getMockWithoutInvokingTheOriginalConstructor("Foo");
  13548. $mock1 = $this->getMock("Foo");
  13549. $mock1 = $this->getMock("Bar", ["aaa"]);
  13550. $mock1 = $this->getMock("Baz", ["aaa"], ["argument"]); // version with more than 2 params is not supported
  13551. }
  13552. }
  13553. '
  13554. ),
  13555. new CodeSample(
  13556. '<?php
  13557. final class MyTest extends \PHPUnit_Framework_TestCase
  13558. {
  13559. public function testFoo()
  13560. {
  13561. $mock1 = $this->getMock("Foo");
  13562. $mock1 = $this->getMock("Bar", ["aaa"]); // version with multiple params is not supported
  13563. }
  13564. }
  13565. ',
  13566. ['target' => PhpUnitTargetVersion::VERSION_5_4]
  13567. ),
  13568. ],
  13569. null,
  13570. 'Risky when PHPUnit classes are overridden or not accessible, or when project has PHPUnit incompatibilities.'
  13571. );
  13572. }
  13573. public function isCandidate(Tokens $tokens)
  13574. {
  13575. return $tokens->isTokenKindFound(T_CLASS);
  13576. }
  13577. public function isRisky()
  13578. {
  13579. return true;
  13580. }
  13581. public function configure(array $configuration = null)
  13582. {
  13583. parent::configure($configuration);
  13584. $this->fixCreatePartialMock = PhpUnitTargetVersion::fulfills($this->configuration['target'], PhpUnitTargetVersion::VERSION_5_5);
  13585. }
  13586. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  13587. {
  13588. $phpUnitTestCaseIndicator = new PhpUnitTestCaseIndicator();
  13589. $argumentsAnalyzer = new ArgumentsAnalyzer();
  13590. foreach ($phpUnitTestCaseIndicator->findPhpUnitClasses($tokens) as $indexes) {
  13591. for ($index = $indexes[0]; $index < $indexes[1]; ++$index) {
  13592. if (!$tokens[$index]->isGivenKind(T_OBJECT_OPERATOR)) {
  13593. continue;
  13594. }
  13595. $index = $tokens->getNextMeaningfulToken($index);
  13596. if ($tokens[$index]->equals([T_STRING, 'getMockWithoutInvokingTheOriginalConstructor'], false)) {
  13597. $tokens[$index] = new Token([T_STRING, 'createMock']);
  13598. } elseif ($tokens[$index]->equals([T_STRING, 'getMock'], false)) {
  13599. $openingParenthesis = $tokens->getNextMeaningfulToken($index);
  13600. $closingParenthesis = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $openingParenthesis);
  13601. $argumentsCount = $argumentsAnalyzer->countArguments($tokens, $openingParenthesis, $closingParenthesis);
  13602. if (1 === $argumentsCount) {
  13603. $tokens[$index] = new Token([T_STRING, 'createMock']);
  13604. } elseif (2 === $argumentsCount && true === $this->fixCreatePartialMock) {
  13605. $tokens[$index] = new Token([T_STRING, 'createPartialMock']);
  13606. }
  13607. }
  13608. }
  13609. }
  13610. }
  13611. protected function createConfigurationDefinition()
  13612. {
  13613. return new FixerConfigurationResolver([
  13614. (new FixerOptionBuilder('target', 'Target version of PHPUnit.'))
  13615. ->setAllowedTypes(['string'])
  13616. ->setAllowedValues([PhpUnitTargetVersion::VERSION_5_4, PhpUnitTargetVersion::VERSION_5_5, PhpUnitTargetVersion::VERSION_NEWEST])
  13617. ->setDefault(PhpUnitTargetVersion::VERSION_NEWEST)
  13618. ->getOption(),
  13619. ]);
  13620. }
  13621. }
  13622. <?php
  13623. namespace PhpCsFixer\Fixer\PhpUnit;
  13624. use PhpCsFixer\AbstractFixer;
  13625. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  13626. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  13627. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  13628. use PhpCsFixer\FixerDefinition\CodeSample;
  13629. use PhpCsFixer\FixerDefinition\FixerDefinition;
  13630. use PhpCsFixer\Preg;
  13631. use PhpCsFixer\Tokenizer\Token;
  13632. use PhpCsFixer\Tokenizer\Tokens;
  13633. final class PhpUnitNamespacedFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface
  13634. {
  13635. private $originalClassRegEx;
  13636. private $classMap;
  13637. public function getDefinition()
  13638. {
  13639. $codeSample = '<?php
  13640. final class MyTest extends \PHPUnit_Framework_TestCase
  13641. {
  13642. public function testSomething()
  13643. {
  13644. PHPUnit_Framework_Assert::assertTrue(true);
  13645. }
  13646. }
  13647. ';
  13648. return new FixerDefinition(
  13649. 'PHPUnit classes MUST be used in namespaced version, e.g. `\PHPUnit\Framework\TestCase` instead of `\PHPUnit_Framework_TestCase`.',
  13650. [
  13651. new CodeSample($codeSample),
  13652. new CodeSample($codeSample, ['target' => PhpUnitTargetVersion::VERSION_4_8]),
  13653. ],
  13654. "PHPUnit v6 has finally fully switched to namespaces.\n"
  13655. ."You could start preparing the upgrade by switching from non-namespaced TestCase to namespaced one.\n"
  13656. .'Forward compatibility layer (`\PHPUnit\Framework\TestCase` class) was backported to PHPUnit v4.8.35 and PHPUnit v5.4.0.'."\n"
  13657. .'Extended forward compatibility layer (`PHPUnit\Framework\Assert`, `PHPUnit\Framework\BaseTestListener`, `PHPUnit\Framework\TestListener` classes) was introduced in v5.7.0.'."\n",
  13658. 'Risky when PHPUnit classes are overridden or not accessible, or when project has PHPUnit incompatibilities.'
  13659. );
  13660. }
  13661. public function isCandidate(Tokens $tokens)
  13662. {
  13663. return $tokens->isTokenKindFound(T_STRING);
  13664. }
  13665. public function isRisky()
  13666. {
  13667. return true;
  13668. }
  13669. public function configure(array $configuration = null)
  13670. {
  13671. parent::configure($configuration);
  13672. if (PhpUnitTargetVersion::fulfills($this->configuration['target'], PhpUnitTargetVersion::VERSION_6_0)) {
  13673. $this->originalClassRegEx = '/^PHPUnit_\w+$/i';
  13674. $this->classMap = [
  13675. 'PHPUnit_Extensions_PhptTestCase' => 'PHPUnit\Runner\PhptTestCase',
  13676. 'PHPUnit_Framework_Constraint' => 'PHPUnit\Framework\Constraint\Constraint',
  13677. 'PHPUnit_Framework_Constraint_StringMatches' => 'PHPUnit\Framework\Constraint\StringMatchesFormatDescription',
  13678. 'PHPUnit_Framework_Constraint_JsonMatches_ErrorMessageProvider' => 'PHPUnit\Framework\Constraint\JsonMatchesErrorMessageProvider',
  13679. 'PHPUnit_Framework_Constraint_PCREMatch' => 'PHPUnit\Framework\Constraint\RegularExpression',
  13680. 'PHPUnit_Framework_Constraint_ExceptionMessageRegExp' => 'PHPUnit\Framework\Constraint\ExceptionMessageRegularExpression',
  13681. 'PHPUnit_Framework_Constraint_And' => 'PHPUnit\Framework\Constraint\LogicalAnd',
  13682. 'PHPUnit_Framework_Constraint_Or' => 'PHPUnit\Framework\Constraint\LogicalOr',
  13683. 'PHPUnit_Framework_Constraint_Not' => 'PHPUnit\Framework\Constraint\LogicalNot',
  13684. 'PHPUnit_Framework_Constraint_Xor' => 'PHPUnit\Framework\Constraint\LogicalXor',
  13685. 'PHPUnit_Framework_Error' => 'PHPUnit\Framework\Error\Error',
  13686. 'PHPUnit_Framework_TestSuite_DataProvider' => 'PHPUnit\Framework\DataProviderTestSuite',
  13687. 'PHPUnit_Framework_MockObject_Invocation_Static' => 'PHPUnit\Framework\MockObject\Invocation\StaticInvocation',
  13688. 'PHPUnit_Framework_MockObject_Invocation_Object' => 'PHPUnit\Framework\MockObject\Invocation\ObjectInvocation',
  13689. 'PHPUnit_Framework_MockObject_Stub_Return' => 'PHPUnit\Framework\MockObject\Stub\ReturnStub',
  13690. 'PHPUnit_Runner_Filter_Group_Exclude' => 'PHPUnit\Runner\Filter\ExcludeGroupFilterIterator',
  13691. 'PHPUnit_Runner_Filter_Group_Include' => 'PHPUnit\Runner\Filter\IncludeGroupFilterIterator',
  13692. 'PHPUnit_Runner_Filter_Test' => 'PHPUnit\Runner\Filter\NameFilterIterator',
  13693. 'PHPUnit_Util_PHP' => 'PHPUnit\Util\PHP\AbstractPhpProcess',
  13694. 'PHPUnit_Util_PHP_Default' => 'PHPUnit\Util\PHP\DefaultPhpProcess',
  13695. 'PHPUnit_Util_PHP_Windows' => 'PHPUnit\Util\PHP\WindowsPhpProcess',
  13696. 'PHPUnit_Util_Regex' => 'PHPUnit\Util\RegularExpression',
  13697. 'PHPUnit_Util_TestDox_ResultPrinter_XML' => 'PHPUnit\Util\TestDox\XmlResultPrinter',
  13698. 'PHPUnit_Util_TestDox_ResultPrinter_HTML' => 'PHPUnit\Util\TestDox\HtmlResultPrinter',
  13699. 'PHPUnit_Util_TestDox_ResultPrinter_Text' => 'PHPUnit\Util\TestDox\TextResultPrinter',
  13700. 'PHPUnit_Util_TestSuiteIterator' => 'PHPUnit\Framework\TestSuiteIterator',
  13701. 'PHPUnit_Util_XML' => 'PHPUnit\Util\Xml',
  13702. ];
  13703. } elseif (PhpUnitTargetVersion::fulfills($this->configuration['target'], PhpUnitTargetVersion::VERSION_5_7)) {
  13704. $this->originalClassRegEx = '/^PHPUnit_Framework_TestCase|PHPUnit_Framework_Assert|PHPUnit_Framework_BaseTestListener|PHPUnit_Framework_TestListener$/i';
  13705. $this->classMap = [];
  13706. } else {
  13707. $this->originalClassRegEx = '/^PHPUnit_Framework_TestCase$/i';
  13708. $this->classMap = [];
  13709. }
  13710. }
  13711. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  13712. {
  13713. $importedOriginalClassesMap = [];
  13714. $currIndex = 0;
  13715. while (null !== $currIndex) {
  13716. $currIndex = $tokens->getNextTokenOfKind($currIndex, [[T_STRING]]);
  13717. if (null === $currIndex) {
  13718. break;
  13719. }
  13720. $originalClass = $tokens[$currIndex]->getContent();
  13721. if (1 !== Preg::match($this->originalClassRegEx, $originalClass)) {
  13722. ++$currIndex;
  13723. continue;
  13724. }
  13725. $substituteTokens = $this->generateReplacement($originalClass);
  13726. $tokens->clearAt($currIndex);
  13727. $tokens->insertAt(
  13728. $currIndex,
  13729. isset($importedOriginalClassesMap[$originalClass]) ? $substituteTokens[$substituteTokens->getSize() - 1] : $substituteTokens
  13730. );
  13731. $prevIndex = $tokens->getPrevMeaningfulToken($currIndex);
  13732. if ($tokens[$prevIndex]->isGivenKind(T_USE)) {
  13733. $importedOriginalClassesMap[$originalClass] = true;
  13734. } elseif ($tokens[$prevIndex]->isGivenKind(T_NS_SEPARATOR)) {
  13735. $prevIndex = $tokens->getPrevMeaningfulToken($prevIndex);
  13736. if ($tokens[$prevIndex]->isGivenKind(T_USE)) {
  13737. $importedOriginalClassesMap[$originalClass] = true;
  13738. }
  13739. }
  13740. }
  13741. }
  13742. protected function createConfigurationDefinition()
  13743. {
  13744. return new FixerConfigurationResolver([
  13745. (new FixerOptionBuilder('target', 'Target version of PHPUnit.'))
  13746. ->setAllowedTypes(['string'])
  13747. ->setAllowedValues([PhpUnitTargetVersion::VERSION_4_8, PhpUnitTargetVersion::VERSION_5_7, PhpUnitTargetVersion::VERSION_6_0, PhpUnitTargetVersion::VERSION_NEWEST])
  13748. ->setDefault(PhpUnitTargetVersion::VERSION_NEWEST)
  13749. ->getOption(),
  13750. ]);
  13751. }
  13752. private function generateReplacement($originalClassName)
  13753. {
  13754. $delimiter = '_';
  13755. $string = $originalClassName;
  13756. if (isset($this->classMap[$originalClassName])) {
  13757. $delimiter = '\\';
  13758. $string = $this->classMap[$originalClassName];
  13759. }
  13760. $parts = explode($delimiter, $string);
  13761. $tokensArray = [];
  13762. while (!empty($parts)) {
  13763. $tokensArray[] = new Token([T_STRING, array_shift($parts)]);
  13764. if (!empty($parts)) {
  13765. $tokensArray[] = new Token([T_NS_SEPARATOR, '\\']);
  13766. }
  13767. }
  13768. return Tokens::fromArray($tokensArray);
  13769. }
  13770. }
  13771. <?php
  13772. namespace PhpCsFixer\Fixer\PhpUnit;
  13773. use PhpCsFixer\AbstractFixer;
  13774. use PhpCsFixer\FixerDefinition\CodeSample;
  13775. use PhpCsFixer\FixerDefinition\FixerDefinition;
  13776. use PhpCsFixer\Indicator\PhpUnitTestCaseIndicator;
  13777. use PhpCsFixer\Tokenizer\Token;
  13778. use PhpCsFixer\Tokenizer\Tokens;
  13779. /**
  13780. @gmail
  13781. */
  13782. final class PhpUnitMockShortWillReturnFixer extends AbstractFixer
  13783. {
  13784. const RETURN_METHODS_MAP = [
  13785. 'returnargument' => 'willReturnArgument',
  13786. 'returncallback' => 'willReturnCallback',
  13787. 'returnself' => 'willReturnSelf',
  13788. 'returnvalue' => 'willReturn',
  13789. 'returnvaluemap' => 'willReturnMap',
  13790. ];
  13791. public function getDefinition()
  13792. {
  13793. return new FixerDefinition(
  13794. 'Usage of PHPUnit\'s mock e.g. `->will($this->returnValue(..))` must be replaced by its shorter equivalent such as `->willReturn(...)`.',
  13795. [
  13796. new CodeSample('<?php
  13797. final class MyTest extends \PHPUnit_Framework_TestCase
  13798. {
  13799. public function testSomeTest()
  13800. {
  13801. $someMock = $this->createMock(Some::class);
  13802. $someMock->method("some")->will($this->returnSelf());
  13803. $someMock->method("some")->will($this->returnValue("example"));
  13804. $someMock->method("some")->will($this->returnArgument(2));
  13805. $someMock->method("some")->will($this->returnCallback("str_rot13"));
  13806. $someMock->method("some")->will($this->returnValueMap(["a","b","c"]));
  13807. }
  13808. }
  13809. '),
  13810. ],
  13811. null,
  13812. 'Risky when PHPUnit classes are overridden or not accessible, or when project has PHPUnit incompatibilities.'
  13813. );
  13814. }
  13815. public function isCandidate(Tokens $tokens)
  13816. {
  13817. return $tokens->isAllTokenKindsFound([T_CLASS, T_OBJECT_OPERATOR, T_STRING]);
  13818. }
  13819. public function isRisky()
  13820. {
  13821. return true;
  13822. }
  13823. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  13824. {
  13825. $phpUnitTestCaseIndicator = new PhpUnitTestCaseIndicator();
  13826. foreach ($phpUnitTestCaseIndicator->findPhpUnitClasses($tokens) as $indexes) {
  13827. $this->fixWillReturn($tokens, $indexes[0], $indexes[1]);
  13828. }
  13829. }
  13830. private function fixWillReturn(Tokens $tokens, $startIndex, $endIndex)
  13831. {
  13832. for ($index = $startIndex; $index < $endIndex; ++$index) {
  13833. if (!$tokens[$index]->isGivenKind(T_OBJECT_OPERATOR)) {
  13834. continue;
  13835. }
  13836. $functionToReplaceIndex = $tokens->getNextMeaningfulToken($index);
  13837. if (!$tokens[$functionToReplaceIndex]->equals([T_STRING, 'will'], false)) {
  13838. continue;
  13839. }
  13840. $functionToReplaceOpeningBraceIndex = $tokens->getNextMeaningfulToken($functionToReplaceIndex);
  13841. if (!$tokens[$functionToReplaceOpeningBraceIndex]->equals('(')) {
  13842. continue;
  13843. }
  13844. $classReferenceIndex = $tokens->getNextMeaningfulToken($functionToReplaceOpeningBraceIndex);
  13845. $objectOperatorIndex = $tokens->getNextMeaningfulToken($classReferenceIndex);
  13846. if (
  13847. !($tokens[$classReferenceIndex]->equals([T_VARIABLE, '$this'], false) && $tokens[$objectOperatorIndex]->equals([T_OBJECT_OPERATOR, '->']))
  13848. && !($tokens[$classReferenceIndex]->equals([T_STRING, 'self'], false) && $tokens[$objectOperatorIndex]->equals([T_DOUBLE_COLON, '::']))
  13849. && !($tokens[$classReferenceIndex]->equals([T_STATIC, 'static'], false) && $tokens[$objectOperatorIndex]->equals([T_DOUBLE_COLON, '::']))
  13850. ) {
  13851. continue;
  13852. }
  13853. $functionToRemoveIndex = $tokens->getNextMeaningfulToken($objectOperatorIndex);
  13854. if (!$tokens[$functionToRemoveIndex]->isGivenKind(T_STRING) || !\array_key_exists(strtolower($tokens[$functionToRemoveIndex]->getContent()), self::RETURN_METHODS_MAP)) {
  13855. continue;
  13856. }
  13857. $openingBraceIndex = $tokens->getNextMeaningfulToken($functionToRemoveIndex);
  13858. if (!$tokens[$openingBraceIndex]->equals('(')) {
  13859. continue;
  13860. }
  13861. $closingBraceIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $openingBraceIndex);
  13862. $tokens[$functionToReplaceIndex] = new Token([T_STRING, self::RETURN_METHODS_MAP[strtolower($tokens[$functionToRemoveIndex]->getContent())]]);
  13863. $tokens->clearTokenAndMergeSurroundingWhitespace($classReferenceIndex);
  13864. $tokens->clearTokenAndMergeSurroundingWhitespace($objectOperatorIndex);
  13865. $tokens->clearTokenAndMergeSurroundingWhitespace($functionToRemoveIndex);
  13866. $tokens->clearTokenAndMergeSurroundingWhitespace($openingBraceIndex);
  13867. $tokens->clearTokenAndMergeSurroundingWhitespace($closingBraceIndex);
  13868. }
  13869. }
  13870. }
  13871. <?php
  13872. namespace PhpCsFixer\Fixer\PhpUnit;
  13873. use PhpCsFixer\AbstractFixer;
  13874. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  13875. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  13876. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  13877. use PhpCsFixer\FixerDefinition\CodeSample;
  13878. use PhpCsFixer\FixerDefinition\FixerDefinition;
  13879. use PhpCsFixer\Indicator\PhpUnitTestCaseIndicator;
  13880. use PhpCsFixer\Tokenizer\Token;
  13881. use PhpCsFixer\Tokenizer\Tokens;
  13882. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  13883. final class PhpUnitDedicateAssertInternalTypeFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface
  13884. {
  13885. private $typeToDedicatedAssertMap = [
  13886. 'array' => 'assertIsArray',
  13887. 'boolean' => 'assertIsBool',
  13888. 'bool' => 'assertIsBool',
  13889. 'double' => 'assertIsFloat',
  13890. 'float' => 'assertIsFloat',
  13891. 'integer' => 'assertIsInt',
  13892. 'int' => 'assertIsInt',
  13893. 'null' => 'assertNull',
  13894. 'numeric' => 'assertIsNumeric',
  13895. 'object' => 'assertIsObject',
  13896. 'real' => 'assertIsFloat',
  13897. 'resource' => 'assertIsResource',
  13898. 'string' => 'assertIsString',
  13899. 'scalar' => 'assertIsScalar',
  13900. 'callable' => 'assertIsCallable',
  13901. 'iterable' => 'assertIsIterable',
  13902. ];
  13903. public function getDefinition()
  13904. {
  13905. return new FixerDefinition(
  13906. 'PHPUnit assertions like `assertIsArray` should be used over `assertInternalType`.',
  13907. [
  13908. new CodeSample(
  13909. '<?php
  13910. final class MyTest extends \PHPUnit\Framework\TestCase
  13911. {
  13912. public function testMe()
  13913. {
  13914. $this->assertInternalType("array", $var);
  13915. $this->assertInternalType("boolean", $var);
  13916. }
  13917. }
  13918. '
  13919. ),
  13920. ],
  13921. null,
  13922. 'Risky when PHPUnit methods are overridden or when project has PHPUnit incompatibilities.'
  13923. );
  13924. }
  13925. public function isCandidate(Tokens $tokens)
  13926. {
  13927. return $tokens->isAllTokenKindsFound([T_CLASS, T_FUNCTION]);
  13928. }
  13929. public function isRisky()
  13930. {
  13931. return true;
  13932. }
  13933. public function getPriority()
  13934. {
  13935. return -16;
  13936. }
  13937. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  13938. {
  13939. $phpUnitTestCaseIndicator = new PhpUnitTestCaseIndicator();
  13940. foreach ($phpUnitTestCaseIndicator->findPhpUnitClasses($tokens) as $indexes) {
  13941. $this->updateAssertInternalTypeMethods($tokens, $indexes[0], $indexes[1]);
  13942. }
  13943. }
  13944. protected function createConfigurationDefinition()
  13945. {
  13946. return new FixerConfigurationResolver([
  13947. (new FixerOptionBuilder('target', 'Target version of PHPUnit.'))
  13948. ->setAllowedTypes(['string'])
  13949. ->setAllowedValues([PhpUnitTargetVersion::VERSION_7_5, PhpUnitTargetVersion::VERSION_NEWEST])
  13950. ->setDefault(PhpUnitTargetVersion::VERSION_NEWEST)
  13951. ->getOption(),
  13952. ]);
  13953. }
  13954. private function updateAssertInternalTypeMethods(Tokens $tokens, $startIndex, $endIndex)
  13955. {
  13956. $anonymousClassIndexes = [];
  13957. $tokenAnalyzer = new TokensAnalyzer($tokens);
  13958. for ($index = $startIndex; $index < $endIndex; ++$index) {
  13959. if (!$tokens[$index]->isClassy() || !$tokenAnalyzer->isAnonymousClass($index)) {
  13960. continue;
  13961. }
  13962. $openingBraceIndex = $tokens->getNextTokenOfKind($index, ['{']);
  13963. $closingBraceIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $openingBraceIndex);
  13964. $anonymousClassIndexes[$closingBraceIndex] = $openingBraceIndex;
  13965. }
  13966. for ($index = $endIndex - 1; $index > $startIndex; --$index) {
  13967. if (isset($anonymousClassIndexes[$index])) {
  13968. $index = $anonymousClassIndexes[$index];
  13969. continue;
  13970. }
  13971. if (!$tokens[$index]->isGivenKind(T_STRING)) {
  13972. continue;
  13973. }
  13974. $functionName = strtolower($tokens[$index]->getContent());
  13975. if ('assertinternaltype' !== $functionName && 'assertnotinternaltype' !== $functionName) {
  13976. continue;
  13977. }
  13978. $bracketTokenIndex = $tokens->getNextMeaningfulToken($index);
  13979. if (!$tokens[$bracketTokenIndex]->equals('(')) {
  13980. continue;
  13981. }
  13982. $expectedTypeTokenIndex = $tokens->getNextMeaningfulToken($bracketTokenIndex);
  13983. $expectedTypeToken = $tokens[$expectedTypeTokenIndex];
  13984. if (!$expectedTypeToken->equals([T_CONSTANT_ENCAPSED_STRING])) {
  13985. continue;
  13986. }
  13987. $expectedType = trim($expectedTypeToken->getContent(), '\'"');
  13988. if (!isset($this->typeToDedicatedAssertMap[$expectedType])) {
  13989. continue;
  13990. }
  13991. $commaTokenIndex = $tokens->getNextMeaningfulToken($expectedTypeTokenIndex);
  13992. if (!$tokens[$commaTokenIndex]->equals(',')) {
  13993. continue;
  13994. }
  13995. $newAssertion = $this->typeToDedicatedAssertMap[$expectedType];
  13996. if ('assertnotinternaltype' === $functionName) {
  13997. $newAssertion = str_replace('Is', 'IsNot', $newAssertion);
  13998. $newAssertion = str_replace('Null', 'NotNull', $newAssertion);
  13999. }
  14000. $nextMeaningfulTokenIndex = $tokens->getNextMeaningfulToken($commaTokenIndex);
  14001. $tokens->overrideRange($index, $nextMeaningfulTokenIndex - 1, [
  14002. new Token([T_STRING, $newAssertion]),
  14003. new Token('('),
  14004. ]);
  14005. }
  14006. }
  14007. }
  14008. <?php
  14009. namespace PhpCsFixer\Fixer\PhpUnit;
  14010. use PhpCsFixer\AbstractFixer;
  14011. use PhpCsFixer\DocBlock\DocBlock;
  14012. use PhpCsFixer\DocBlock\Line;
  14013. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  14014. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  14015. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  14016. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  14017. use PhpCsFixer\FixerDefinition\CodeSample;
  14018. use PhpCsFixer\FixerDefinition\FixerDefinition;
  14019. use PhpCsFixer\Indicator\PhpUnitTestCaseIndicator;
  14020. use PhpCsFixer\Preg;
  14021. use PhpCsFixer\Tokenizer\Token;
  14022. use PhpCsFixer\Tokenizer\Tokens;
  14023. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  14024. final class PhpUnitTestAnnotationFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface, WhitespacesAwareFixerInterface
  14025. {
  14026. public function isRisky()
  14027. {
  14028. return true;
  14029. }
  14030. public function getDefinition()
  14031. {
  14032. return new FixerDefinition(
  14033. 'Adds or removes @test annotations from tests, following configuration.',
  14034. [
  14035. new CodeSample('<?php
  14036. class Test extends \\PhpUnit\\FrameWork\\TestCase
  14037. {
  14038. /**
  14039. * @test
  14040. */
  14041. public function itDoesSomething() {} }'.$this->whitespacesConfig->getLineEnding()),
  14042. new CodeSample('<?php
  14043. class Test extends \\PhpUnit\\FrameWork\\TestCase
  14044. {
  14045. public function testItDoesSomething() {}}'.$this->whitespacesConfig->getLineEnding(), ['style' => 'annotation']),
  14046. ],
  14047. null,
  14048. 'This fixer may change the name of your tests, and could cause incompatibility with'.
  14049. ' abstract classes or interfaces.'
  14050. );
  14051. }
  14052. public function getPriority()
  14053. {
  14054. return 10;
  14055. }
  14056. public function isCandidate(Tokens $tokens)
  14057. {
  14058. return $tokens->isAllTokenKindsFound([T_CLASS, T_FUNCTION]);
  14059. }
  14060. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  14061. {
  14062. $phpUnitTestCaseIndicator = new PhpUnitTestCaseIndicator();
  14063. foreach ($phpUnitTestCaseIndicator->findPhpUnitClasses($tokens) as $indexes) {
  14064. if ('annotation' === $this->configuration['style']) {
  14065. $this->applyTestAnnotation($tokens, $indexes[0], $indexes[1]);
  14066. } else {
  14067. $this->applyTestPrefix($tokens, $indexes[0], $indexes[1]);
  14068. }
  14069. }
  14070. }
  14071. protected function createConfigurationDefinition()
  14072. {
  14073. return new FixerConfigurationResolver([
  14074. (new FixerOptionBuilder('style', 'Whether to use the @test annotation or not.'))
  14075. ->setAllowedValues(['prefix', 'annotation'])
  14076. ->setDefault('prefix')
  14077. ->getOption(),
  14078. (new FixerOptionBuilder('case', 'Whether to camel or snake case when adding the test prefix'))
  14079. ->setAllowedValues(['camel', 'snake'])
  14080. ->setDefault('camel')
  14081. ->setDeprecationMessage('Use `php_unit_method_casing` fixer instead.')
  14082. ->getOption(),
  14083. ]);
  14084. }
  14085. private function applyTestAnnotation(Tokens $tokens, $startIndex, $endIndex)
  14086. {
  14087. for ($i = $endIndex - 1; $i > $startIndex; --$i) {
  14088. if (!$this->isTestMethod($tokens, $i)) {
  14089. continue;
  14090. }
  14091. $functionNameIndex = $tokens->getNextMeaningfulToken($i);
  14092. $functionName = $tokens[$functionNameIndex]->getContent();
  14093. if ($this->hasTestPrefix($functionName) && !$this->hasProperTestAnnotation($tokens, $i)) {
  14094. $newFunctionName = $this->removeTestPrefix($functionName);
  14095. $tokens[$functionNameIndex] = new Token([T_STRING, $newFunctionName]);
  14096. }
  14097. $docBlockIndex = $this->getDocBlockIndex($tokens, $i);
  14098. if (!$this->hasDocBlock($tokens, $i)) {
  14099. $this->createDocBlock($tokens, $docBlockIndex);
  14100. continue;
  14101. }
  14102. $lines = $this->updateDocBlock($tokens, $docBlockIndex);
  14103. $lines = $this->addTestAnnotation($lines, $tokens, $docBlockIndex);
  14104. $lines = implode('', $lines);
  14105. $tokens[$docBlockIndex] = new Token([T_DOC_COMMENT, $lines]);
  14106. }
  14107. }
  14108. private function applyTestPrefix(Tokens $tokens, $startIndex, $endIndex)
  14109. {
  14110. for ($i = $endIndex - 1; $i > $startIndex; --$i) {
  14111. if (!$this->isTestMethod($tokens, $i) || !$this->hasDocBlock($tokens, $i)) {
  14112. continue;
  14113. }
  14114. $docBlockIndex = $this->getDocBlockIndex($tokens, $i);
  14115. $lines = $this->updateDocBlock($tokens, $docBlockIndex);
  14116. $lines = implode('', $lines);
  14117. $tokens[$docBlockIndex] = new Token([T_DOC_COMMENT, $lines]);
  14118. $functionNameIndex = $tokens->getNextMeaningfulToken($i);
  14119. $functionName = $tokens[$functionNameIndex]->getContent();
  14120. if ($this->hasTestPrefix($functionName)) {
  14121. continue;
  14122. }
  14123. $newFunctionName = $this->addTestPrefix($functionName);
  14124. $tokens[$functionNameIndex] = new Token([T_STRING, $newFunctionName]);
  14125. }
  14126. }
  14127. private function isTestMethod(Tokens $tokens, $index)
  14128. {
  14129. if (!$this->isMethod($tokens, $index)) {
  14130. return false;
  14131. }
  14132. $functionNameIndex = $tokens->getNextMeaningfulToken($index);
  14133. $functionName = $tokens[$functionNameIndex]->getContent();
  14134. if ($this->hasTestPrefix($functionName)) {
  14135. return true;
  14136. }
  14137. if (!$this->hasDocBlock($tokens, $index)) {
  14138. return false;
  14139. }
  14140. $docBlockIndex = $this->getDocBlockIndex($tokens, $index);
  14141. $doc = $tokens[$docBlockIndex]->getContent();
  14142. if (false === strpos($doc, '@test')) {
  14143. return false;
  14144. }
  14145. return true;
  14146. }
  14147. private function isMethod(Tokens $tokens, $index)
  14148. {
  14149. $tokensAnalyzer = new TokensAnalyzer($tokens);
  14150. return $tokens[$index]->isGivenKind(T_FUNCTION) && !$tokensAnalyzer->isLambda($index);
  14151. }
  14152. private function hasDocBlock(Tokens $tokens, $index)
  14153. {
  14154. $docBlockIndex = $this->getDocBlockIndex($tokens, $index);
  14155. return $tokens[$docBlockIndex]->isGivenKind(T_DOC_COMMENT);
  14156. }
  14157. private function getDocBlockIndex(Tokens $tokens, $index)
  14158. {
  14159. do {
  14160. $index = $tokens->getPrevNonWhitespace($index);
  14161. } while ($tokens[$index]->isGivenKind([T_PUBLIC, T_PROTECTED, T_PRIVATE, T_FINAL, T_ABSTRACT, T_COMMENT]));
  14162. return $index;
  14163. }
  14164. private function hasTestPrefix($functionName)
  14165. {
  14166. return 0 === strpos($functionName, 'test');
  14167. }
  14168. private function hasProperTestAnnotation(Tokens $tokens, $index)
  14169. {
  14170. $docBlockIndex = $this->getDocBlockIndex($tokens, $index);
  14171. $doc = $tokens[$docBlockIndex]->getContent();
  14172. return 1 === Preg::match('/\*\s+@test\b/', $doc);
  14173. }
  14174. private function removeTestPrefix($functionName)
  14175. {
  14176. $remainder = Preg::replace('/^test(?=[A-Z_])_?/', '', $functionName);
  14177. if ('' === $remainder) {
  14178. return $functionName;
  14179. }
  14180. return lcfirst($remainder);
  14181. }
  14182. private function addTestPrefix($functionName)
  14183. {
  14184. if ('camel' !== $this->configuration['case']) {
  14185. return 'test_'.$functionName;
  14186. }
  14187. return'test'.ucfirst($functionName);
  14188. }
  14189. private function detectIndent(Tokens $tokens, $index)
  14190. {
  14191. if (!$tokens[$index - 1]->isWhitespace()) {
  14192. return '';
  14193. }
  14194. $explodedContent = explode($this->whitespacesConfig->getLineEnding(), $tokens[$index - 1]->getContent());
  14195. return end($explodedContent);
  14196. }
  14197. private function createDocBlock(Tokens $tokens, $docBlockIndex)
  14198. {
  14199. $lineEnd = $this->whitespacesConfig->getLineEnding();
  14200. $originalIndent = $this->detectIndent($tokens, $tokens->getNextNonWhitespace($docBlockIndex));
  14201. $toInsert = [
  14202. new Token([T_DOC_COMMENT, '/**'.$lineEnd."{$originalIndent} * @test".$lineEnd."{$originalIndent} */"]),
  14203. new Token([T_WHITESPACE, $lineEnd.$originalIndent]),
  14204. ];
  14205. $index = $tokens->getNextMeaningfulToken($docBlockIndex);
  14206. $tokens->insertAt($index, $toInsert);
  14207. }
  14208. private function updateDocBlock(Tokens $tokens, $docBlockIndex)
  14209. {
  14210. $doc = new DocBlock($tokens[$docBlockIndex]->getContent());
  14211. $lines = $doc->getLines();
  14212. return $this->updateLines($lines, $tokens, $docBlockIndex);
  14213. }
  14214. private function updateLines($lines, Tokens $tokens, $docBlockIndex)
  14215. {
  14216. $needsAnnotation = 'annotation' === $this->configuration['style'];
  14217. $doc = new DocBlock($tokens[$docBlockIndex]->getContent());
  14218. for ($i = 0; $i < \count($lines); ++$i) {
  14219. if ($needsAnnotation && ($lines[$i]->isTheStart() && $lines[$i]->isTheEnd())) {
  14220. if (!$this->doesDocBlockContainTest($doc)) {
  14221. $lines = $this->splitUpDocBlock($lines, $tokens, $docBlockIndex);
  14222. return $this->updateLines($lines, $tokens, $docBlockIndex);
  14223. }
  14224. }
  14225. if (!$needsAnnotation &&
  14226. false !== strpos($lines[$i]->getContent(), ' @test') &&
  14227. false === strpos($lines[$i]->getContent(), '@testWith') &&
  14228. false === strpos($lines[$i]->getContent(), '@testdox')
  14229. ) {
  14230. $lines[$i] = new Line(str_replace(' @test', '', $lines[$i]->getContent()));
  14231. }
  14232. if (false === strpos($lines[$i]->getContent(), '@depends')) {
  14233. continue;
  14234. }
  14235. $lines[$i] = $this->updateDependsAnnotation($lines[$i]);
  14236. }
  14237. return $lines;
  14238. }
  14239. private function splitUpDocBlock($lines, Tokens $tokens, $docBlockIndex)
  14240. {
  14241. $lineContent = $this->getSingleLineDocBlockEntry($lines);
  14242. $lineEnd = $this->whitespacesConfig->getLineEnding();
  14243. $originalIndent = $this->detectIndent($tokens, $tokens->getNextNonWhitespace($docBlockIndex));
  14244. return [
  14245. new Line('/**'.$lineEnd),
  14246. new Line($originalIndent.' * '.$lineContent.$lineEnd),
  14247. new Line($originalIndent.' */'),
  14248. ];
  14249. }
  14250. private function getSingleLineDocBlockEntry($line)
  14251. {
  14252. $line = $line[0];
  14253. $line = str_replace('*/', '', $line);
  14254. $line = trim($line);
  14255. $line = str_split($line);
  14256. $i = \count($line);
  14257. do {
  14258. --$i;
  14259. } while ('*' !== $line[$i] && '*' !== $line[$i - 1] && '/' !== $line[$i - 2]);
  14260. if (' ' === $line[$i]) {
  14261. ++$i;
  14262. }
  14263. $line = \array_slice($line, $i);
  14264. return implode('', $line);
  14265. }
  14266. private function updateDependsAnnotation(Line $line)
  14267. {
  14268. if ('annotation' === $this->configuration['style']) {
  14269. return $this->removeTestPrefixFromDependsAnnotation($line);
  14270. }
  14271. return $this->addTestPrefixToDependsAnnotation($line);
  14272. }
  14273. private function removeTestPrefixFromDependsAnnotation(Line $line)
  14274. {
  14275. $line = str_split($line->getContent());
  14276. $dependsIndex = $this->findWhereDependsFunctionNameStarts($line);
  14277. $dependsFunctionName = implode('', \array_slice($line, $dependsIndex));
  14278. if ($this->hasTestPrefix($dependsFunctionName)) {
  14279. $dependsFunctionName = $this->removeTestPrefix($dependsFunctionName);
  14280. }
  14281. array_splice($line, $dependsIndex);
  14282. return new Line(implode('', $line).$dependsFunctionName);
  14283. }
  14284. private function addTestPrefixToDependsAnnotation(Line $line)
  14285. {
  14286. $line = str_split($line->getContent());
  14287. $dependsIndex = $this->findWhereDependsFunctionNameStarts($line);
  14288. $dependsFunctionName = implode('', \array_slice($line, $dependsIndex));
  14289. if (!$this->hasTestPrefix($dependsFunctionName)) {
  14290. $dependsFunctionName = $this->addTestPrefix($dependsFunctionName);
  14291. }
  14292. array_splice($line, $dependsIndex);
  14293. return new Line(implode('', $line).$dependsFunctionName);
  14294. }
  14295. private function findWhereDependsFunctionNameStarts(array $line)
  14296. {
  14297. $counter = \count($line);
  14298. do {
  14299. --$counter;
  14300. } while (' ' !== $line[$counter]);
  14301. return $counter + 1;
  14302. }
  14303. private function addTestAnnotation($lines, Tokens $tokens, $docBlockIndex)
  14304. {
  14305. $doc = new DocBlock($tokens[$docBlockIndex]->getContent());
  14306. if (!$this->doesDocBlockContainTest($doc)) {
  14307. $originalIndent = $this->detectIndent($tokens, $docBlockIndex);
  14308. $lineEnd = $this->whitespacesConfig->getLineEnding();
  14309. array_splice($lines, -1, 0, $originalIndent.' *'.$lineEnd.$originalIndent.' * @test'.$lineEnd);
  14310. }
  14311. return $lines;
  14312. }
  14313. private function doesDocBlockContainTest(DocBlock $doc)
  14314. {
  14315. return !empty($doc->getAnnotationsOfType('test'));
  14316. }
  14317. }
  14318. <?php
  14319. namespace PhpCsFixer\Fixer\PhpUnit;
  14320. use PhpCsFixer\AbstractFixer;
  14321. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  14322. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  14323. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  14324. use PhpCsFixer\FixerDefinition\CodeSample;
  14325. use PhpCsFixer\FixerDefinition\FixerDefinition;
  14326. use PhpCsFixer\Indicator\PhpUnitTestCaseIndicator;
  14327. use PhpCsFixer\Tokenizer\Analyzer\FunctionsAnalyzer;
  14328. use PhpCsFixer\Tokenizer\Token;
  14329. use PhpCsFixer\Tokenizer\Tokens;
  14330. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  14331. use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException;
  14332. final class PhpUnitTestCaseStaticMethodCallsFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface
  14333. {
  14334. const CALL_TYPE_THIS = 'this';
  14335. const CALL_TYPE_SELF = 'self';
  14336. const CALL_TYPE_STATIC = 'static';
  14337. private $allowedValues = [
  14338. self::CALL_TYPE_THIS => true,
  14339. self::CALL_TYPE_SELF => true,
  14340. self::CALL_TYPE_STATIC => true,
  14341. ];
  14342. private $staticMethods = [
  14343. 'anything' => true,
  14344. 'arrayHasKey' => true,
  14345. 'assertArrayHasKey' => true,
  14346. 'assertArrayNotHasKey' => true,
  14347. 'assertArraySubset' => true,
  14348. 'assertAttributeContains' => true,
  14349. 'assertAttributeContainsOnly' => true,
  14350. 'assertAttributeCount' => true,
  14351. 'assertAttributeEmpty' => true,
  14352. 'assertAttributeEquals' => true,
  14353. 'assertAttributeGreaterThan' => true,
  14354. 'assertAttributeGreaterThanOrEqual' => true,
  14355. 'assertAttributeInstanceOf' => true,
  14356. 'assertAttributeInternalType' => true,
  14357. 'assertAttributeLessThan' => true,
  14358. 'assertAttributeLessThanOrEqual' => true,
  14359. 'assertAttributeNotContains' => true,
  14360. 'assertAttributeNotContainsOnly' => true,
  14361. 'assertAttributeNotCount' => true,
  14362. 'assertAttributeNotEmpty' => true,
  14363. 'assertAttributeNotEquals' => true,
  14364. 'assertAttributeNotInstanceOf' => true,
  14365. 'assertAttributeNotInternalType' => true,
  14366. 'assertAttributeNotSame' => true,
  14367. 'assertAttributeSame' => true,
  14368. 'assertClassHasAttribute' => true,
  14369. 'assertClassHasStaticAttribute' => true,
  14370. 'assertClassNotHasAttribute' => true,
  14371. 'assertClassNotHasStaticAttribute' => true,
  14372. 'assertContains' => true,
  14373. 'assertContainsEquals' => true,
  14374. 'assertContainsOnly' => true,
  14375. 'assertContainsOnlyInstancesOf' => true,
  14376. 'assertCount' => true,
  14377. 'assertDirectoryExists' => true,
  14378. 'assertDirectoryIsReadable' => true,
  14379. 'assertDirectoryIsWritable' => true,
  14380. 'assertDirectoryNotExists' => true,
  14381. 'assertDirectoryNotIsReadable' => true,
  14382. 'assertDirectoryNotIsWritable' => true,
  14383. 'assertEmpty' => true,
  14384. 'assertEqualXMLStructure' => true,
  14385. 'assertEquals' => true,
  14386. 'assertEqualsCanonicalizing' => true,
  14387. 'assertEqualsIgnoringCase' => true,
  14388. 'assertEqualsWithDelta' => true,
  14389. 'assertFalse' => true,
  14390. 'assertFileEquals' => true,
  14391. 'assertFileExists' => true,
  14392. 'assertFileIsReadable' => true,
  14393. 'assertFileIsWritable' => true,
  14394. 'assertFileNotEquals' => true,
  14395. 'assertFileNotExists' => true,
  14396. 'assertFileNotIsReadable' => true,
  14397. 'assertFileNotIsWritable' => true,
  14398. 'assertFinite' => true,
  14399. 'assertGreaterThan' => true,
  14400. 'assertGreaterThanOrEqual' => true,
  14401. 'assertInfinite' => true,
  14402. 'assertInstanceOf' => true,
  14403. 'assertInternalType' => true,
  14404. 'assertIsArray' => true,
  14405. 'assertIsBool' => true,
  14406. 'assertIsCallable' => true,
  14407. 'assertIsFloat' => true,
  14408. 'assertIsInt' => true,
  14409. 'assertIsIterable' => true,
  14410. 'assertIsNotArray' => true,
  14411. 'assertIsNotBool' => true,
  14412. 'assertIsNotCallable' => true,
  14413. 'assertIsNotFloat' => true,
  14414. 'assertIsNotInt' => true,
  14415. 'assertIsNotIterable' => true,
  14416. 'assertIsNotNumeric' => true,
  14417. 'assertIsNotObject' => true,
  14418. 'assertIsNotResource' => true,
  14419. 'assertIsNotScalar' => true,
  14420. 'assertIsNotString' => true,
  14421. 'assertIsNumeric' => true,
  14422. 'assertIsObject' => true,
  14423. 'assertIsReadable' => true,
  14424. 'assertIsResource' => true,
  14425. 'assertIsScalar' => true,
  14426. 'assertIsString' => true,
  14427. 'assertIsWritable' => true,
  14428. 'assertJson' => true,
  14429. 'assertJsonFileEqualsJsonFile' => true,
  14430. 'assertJsonFileNotEqualsJsonFile' => true,
  14431. 'assertJsonStringEqualsJsonFile' => true,
  14432. 'assertJsonStringEqualsJsonString' => true,
  14433. 'assertJsonStringNotEqualsJsonFile' => true,
  14434. 'assertJsonStringNotEqualsJsonString' => true,
  14435. 'assertLessThan' => true,
  14436. 'assertLessThanOrEqual' => true,
  14437. 'assertNan' => true,
  14438. 'assertNotContains' => true,
  14439. 'assertNotContainsEquals' => true,
  14440. 'assertNotContainsOnly' => true,
  14441. 'assertNotCount' => true,
  14442. 'assertNotEmpty' => true,
  14443. 'assertNotEquals' => true,
  14444. 'assertNotEqualsCanonicalizing' => true,
  14445. 'assertNotEqualsIgnoringCase' => true,
  14446. 'assertNotEqualsWithDelta' => true,
  14447. 'assertNotFalse' => true,
  14448. 'assertNotInstanceOf' => true,
  14449. 'assertNotInternalType' => true,
  14450. 'assertNotIsReadable' => true,
  14451. 'assertNotIsWritable' => true,
  14452. 'assertNotNull' => true,
  14453. 'assertNotRegExp' => true,
  14454. 'assertNotSame' => true,
  14455. 'assertNotSameSize' => true,
  14456. 'assertNotTrue' => true,
  14457. 'assertNull' => true,
  14458. 'assertObjectHasAttribute' => true,
  14459. 'assertObjectNotHasAttribute' => true,
  14460. 'assertRegExp' => true,
  14461. 'assertSame' => true,
  14462. 'assertSameSize' => true,
  14463. 'assertStringContainsString' => true,
  14464. 'assertStringContainsStringIgnoringCase' => true,
  14465. 'assertStringEndsNotWith' => true,
  14466. 'assertStringEndsWith' => true,
  14467. 'assertStringEqualsFile' => true,
  14468. 'assertStringMatchesFormat' => true,
  14469. 'assertStringMatchesFormatFile' => true,
  14470. 'assertStringNotContainsString' => true,
  14471. 'assertStringNotContainsStringIgnoringCase' => true,
  14472. 'assertStringNotEqualsFile' => true,
  14473. 'assertStringNotMatchesFormat' => true,
  14474. 'assertStringNotMatchesFormatFile' => true,
  14475. 'assertStringStartsNotWith' => true,
  14476. 'assertStringStartsWith' => true,
  14477. 'assertThat' => true,
  14478. 'assertTrue' => true,
  14479. 'assertXmlFileEqualsXmlFile' => true,
  14480. 'assertXmlFileNotEqualsXmlFile' => true,
  14481. 'assertXmlStringEqualsXmlFile' => true,
  14482. 'assertXmlStringEqualsXmlString' => true,
  14483. 'assertXmlStringNotEqualsXmlFile' => true,
  14484. 'assertXmlStringNotEqualsXmlString' => true,
  14485. 'attribute' => true,
  14486. 'attributeEqualTo' => true,
  14487. 'callback' => true,
  14488. 'classHasAttribute' => true,
  14489. 'classHasStaticAttribute' => true,
  14490. 'contains' => true,
  14491. 'containsOnly' => true,
  14492. 'containsOnlyInstancesOf' => true,
  14493. 'countOf' => true,
  14494. 'directoryExists' => true,
  14495. 'equalTo' => true,
  14496. 'fail' => true,
  14497. 'fileExists' => true,
  14498. 'getCount' => true,
  14499. 'getObjectAttribute' => true,
  14500. 'getStaticAttribute' => true,
  14501. 'greaterThan' => true,
  14502. 'greaterThanOrEqual' => true,
  14503. 'identicalTo' => true,
  14504. 'isEmpty' => true,
  14505. 'isFalse' => true,
  14506. 'isFinite' => true,
  14507. 'isInfinite' => true,
  14508. 'isInstanceOf' => true,
  14509. 'isJson' => true,
  14510. 'isNan' => true,
  14511. 'isNull' => true,
  14512. 'isReadable' => true,
  14513. 'isTrue' => true,
  14514. 'isType' => true,
  14515. 'isWritable' => true,
  14516. 'lessThan' => true,
  14517. 'lessThanOrEqual' => true,
  14518. 'logicalAnd' => true,
  14519. 'logicalNot' => true,
  14520. 'logicalOr' => true,
  14521. 'logicalXor' => true,
  14522. 'markTestIncomplete' => true,
  14523. 'markTestSkipped' => true,
  14524. 'matches' => true,
  14525. 'matchesRegularExpression' => true,
  14526. 'objectHasAttribute' => true,
  14527. 'readAttribute' => true,
  14528. 'resetCount' => true,
  14529. 'stringContains' => true,
  14530. 'stringEndsWith' => true,
  14531. 'stringStartsWith' => true,
  14532. 'any' => true,
  14533. 'at' => true,
  14534. 'atLeast' => true,
  14535. 'atLeastOnce' => true,
  14536. 'atMost' => true,
  14537. 'exactly' => true,
  14538. 'never' => true,
  14539. 'onConsecutiveCalls' => true,
  14540. 'once' => true,
  14541. 'returnArgument' => true,
  14542. 'returnCallback' => true,
  14543. 'returnSelf' => true,
  14544. 'returnValue' => true,
  14545. 'returnValueMap' => true,
  14546. 'setUpBeforeClass' => true,
  14547. 'tearDownAfterClass' => true,
  14548. 'throwException' => true,
  14549. ];
  14550. private $conversionMap = [
  14551. self::CALL_TYPE_THIS => [[T_OBJECT_OPERATOR, '->'], [T_VARIABLE, '$this']],
  14552. self::CALL_TYPE_SELF => [[T_DOUBLE_COLON, '::'], [T_STRING, 'self']],
  14553. self::CALL_TYPE_STATIC => [[T_DOUBLE_COLON, '::'], [T_STATIC, 'static']],
  14554. ];
  14555. public function getDefinition()
  14556. {
  14557. $codeSample = '<?php
  14558. final class MyTest extends \PHPUnit_Framework_TestCase
  14559. {
  14560. public function testMe()
  14561. {
  14562. $this->assertSame(1, 2);
  14563. self::assertSame(1, 2);
  14564. static::assertSame(1, 2);
  14565. }
  14566. }
  14567. ';
  14568. return new FixerDefinition(
  14569. 'Calls to `PHPUnit\Framework\TestCase` static methods must all be of the same type, either `$this->`, `self::` or `static::`.',
  14570. [
  14571. new CodeSample($codeSample),
  14572. new CodeSample($codeSample, ['call_type' => self::CALL_TYPE_THIS]),
  14573. ],
  14574. null,
  14575. 'Risky when PHPUnit methods are overridden or not accessible, or when project has PHPUnit incompatibilities.'
  14576. );
  14577. }
  14578. public function getPriority()
  14579. {
  14580. return 0;
  14581. }
  14582. public function isCandidate(Tokens $tokens)
  14583. {
  14584. return $tokens->isAllTokenKindsFound([T_CLASS, T_STRING]);
  14585. }
  14586. public function isRisky()
  14587. {
  14588. return true;
  14589. }
  14590. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  14591. {
  14592. $phpUnitTestCaseIndicator = new PhpUnitTestCaseIndicator();
  14593. foreach ($phpUnitTestCaseIndicator->findPhpUnitClasses($tokens) as $indexes) {
  14594. $this->fixPhpUnitClass($tokens, $indexes[0], $indexes[1]);
  14595. }
  14596. }
  14597. protected function createConfigurationDefinition()
  14598. {
  14599. $thisFixer = $this;
  14600. return new FixerConfigurationResolver([
  14601. (new FixerOptionBuilder('call_type', 'The call type to use for referring to PHPUnit methods.'))
  14602. ->setAllowedTypes(['string'])
  14603. ->setAllowedValues(array_keys($this->allowedValues))
  14604. ->setDefault('static')
  14605. ->getOption(),
  14606. (new FixerOptionBuilder('methods', 'Dictionary of `method` => `call_type` values that differ from the default strategy.'))
  14607. ->setAllowedTypes(['array'])
  14608. ->setAllowedValues([static function ($option) use ($thisFixer) {
  14609. foreach ($option as $method => $value) {
  14610. if (!isset($thisFixer->staticMethods[$method])) {
  14611. throw new InvalidOptionsException(
  14612. sprintf(
  14613. 'Unexpected "methods" key, expected any of "%s", got "%s".',
  14614. implode('", "', array_keys($thisFixer->staticMethods)),
  14615. \is_object($method) ? \get_class($method) : \gettype($method).'#'.$method
  14616. )
  14617. );
  14618. }
  14619. if (!isset($thisFixer->allowedValues[$value])) {
  14620. throw new InvalidOptionsException(
  14621. sprintf(
  14622. 'Unexpected value for method "%s", expected any of "%s", got "%s".',
  14623. $method,
  14624. implode('", "', array_keys($thisFixer->allowedValues)),
  14625. \is_object($value) ? \get_class($value) : (null === $value ? 'null' : \gettype($value).'#'.$value)
  14626. )
  14627. );
  14628. }
  14629. }
  14630. return true;
  14631. }])
  14632. ->setDefault([])
  14633. ->getOption(),
  14634. ]);
  14635. }
  14636. private function fixPhpUnitClass(Tokens $tokens, $startIndex, $endIndex)
  14637. {
  14638. $analyzer = new TokensAnalyzer($tokens);
  14639. for ($index = $startIndex; $index < $endIndex; ++$index) {
  14640. if ($tokens[$index]->isGivenKind(T_CLASS)) {
  14641. $index = $this->findEndOfNextBlock($tokens, $index);
  14642. continue;
  14643. }
  14644. $callType = $this->configuration['call_type'];
  14645. if ($tokens[$index]->isGivenKind(T_FUNCTION)) {
  14646. if ($analyzer->isLambda($index)) {
  14647. $index = $this->findEndOfNextBlock($tokens, $index);
  14648. continue;
  14649. }
  14650. if ('this' === $callType) {
  14651. $attributes = $analyzer->getMethodAttributes($index);
  14652. if (false !== $attributes['static']) {
  14653. $index = $this->findEndOfNextBlock($tokens, $index);
  14654. continue;
  14655. }
  14656. }
  14657. }
  14658. if (!$tokens[$index]->isGivenKind(T_STRING) || !isset($this->staticMethods[$tokens[$index]->getContent()])) {
  14659. continue;
  14660. }
  14661. $nextIndex = $tokens->getNextMeaningfulToken($index);
  14662. if (!$tokens[$nextIndex]->equals('(')) {
  14663. $index = $nextIndex;
  14664. continue;
  14665. }
  14666. $methodName = $tokens[$index]->getContent();
  14667. if (isset($this->configuration['methods'][$methodName])) {
  14668. $callType = $this->configuration['methods'][$methodName];
  14669. }
  14670. $operatorIndex = $tokens->getPrevMeaningfulToken($index);
  14671. $referenceIndex = $tokens->getPrevMeaningfulToken($operatorIndex);
  14672. if (!$this->needsConversion($tokens, $index, $referenceIndex, $callType)) {
  14673. continue;
  14674. }
  14675. $tokens[$operatorIndex] = new Token($this->conversionMap[$callType][0]);
  14676. $tokens[$referenceIndex] = new Token($this->conversionMap[$callType][1]);
  14677. }
  14678. }
  14679. private function needsConversion(Tokens $tokens, $index, $referenceIndex, $callType)
  14680. {
  14681. $functionsAnalyzer = new FunctionsAnalyzer();
  14682. return $functionsAnalyzer->isTheSameClassCall($tokens, $index)
  14683. && !$tokens[$referenceIndex]->equals($this->conversionMap[$callType][1], false);
  14684. }
  14685. private function findEndOfNextBlock(Tokens $tokens, $index)
  14686. {
  14687. $index = $tokens->getNextTokenOfKind($index, ['{']);
  14688. return $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $index);
  14689. }
  14690. }
  14691. <?php
  14692. namespace PhpCsFixer\Fixer\PhpUnit;
  14693. use PhpCsFixer\AbstractFixer;
  14694. use PhpCsFixer\FixerDefinition\CodeSample;
  14695. use PhpCsFixer\FixerDefinition\FixerDefinition;
  14696. use PhpCsFixer\Indicator\PhpUnitTestCaseIndicator;
  14697. use PhpCsFixer\Tokenizer\Token;
  14698. use PhpCsFixer\Tokenizer\Tokens;
  14699. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  14700. final class PhpUnitSetUpTearDownVisibilityFixer extends AbstractFixer
  14701. {
  14702. public function getDefinition()
  14703. {
  14704. return new FixerDefinition(
  14705. 'Changes the visibility of the `setUp()` and `tearDown()` functions of PHPUnit to `protected`, to match the PHPUnit TestCase.',
  14706. [
  14707. new CodeSample(
  14708. '<?php
  14709. final class MyTest extends \PHPUnit_Framework_TestCase
  14710. {
  14711. private $hello;
  14712. public function setUp()
  14713. {
  14714. $this->hello = "hello";
  14715. }
  14716. public function tearDown()
  14717. {
  14718. $this->hello = null;
  14719. }
  14720. }
  14721. '
  14722. ),
  14723. ],
  14724. null,
  14725. 'This fixer may change functions named `setUp()` or `tearDown()` outside of PHPUnit tests, '.
  14726. 'when a class is wrongly seen as a PHPUnit test.'
  14727. );
  14728. }
  14729. public function isCandidate(Tokens $tokens)
  14730. {
  14731. return $tokens->isAllTokenKindsFound([T_CLASS, T_FUNCTION]);
  14732. }
  14733. public function isRisky()
  14734. {
  14735. return true;
  14736. }
  14737. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  14738. {
  14739. $phpUnitTestCaseIndicator = new PhpUnitTestCaseIndicator();
  14740. foreach ($phpUnitTestCaseIndicator->findPhpUnitClasses($tokens) as $indexes) {
  14741. $this->fixSetUpAndTearDown($tokens, $indexes[0], $indexes[1]);
  14742. }
  14743. }
  14744. private function fixSetUpAndTearDown(Tokens $tokens, $startIndex, $endIndex)
  14745. {
  14746. $counter = 0;
  14747. $tokensAnalyzer = new TokensAnalyzer($tokens);
  14748. for ($i = $endIndex - 1; $i > $startIndex; --$i) {
  14749. if (2 === $counter) {
  14750. break;
  14751. }
  14752. if (!$this->isSetupOrTearDownMethod($tokens, $i)) {
  14753. continue;
  14754. }
  14755. ++$counter;
  14756. $visibility = $tokensAnalyzer->getMethodAttributes($i)['visibility'];
  14757. if (T_PUBLIC === $visibility) {
  14758. $index = $tokens->getPrevTokenOfKind($i, [[T_PUBLIC]]);
  14759. $tokens[$index] = new Token([T_PROTECTED, 'protected']);
  14760. continue;
  14761. }
  14762. if (null === $visibility) {
  14763. $tokens->insertAt($i, [new Token([T_PROTECTED, 'protected']), new Token([T_WHITESPACE, ' '])]);
  14764. }
  14765. }
  14766. }
  14767. private function isSetupOrTearDownMethod(Tokens $tokens, $index)
  14768. {
  14769. $tokensAnalyzer = new TokensAnalyzer($tokens);
  14770. $isMethod = $tokens[$index]->isGivenKind(T_FUNCTION) && !$tokensAnalyzer->isLambda($index);
  14771. if (!$isMethod) {
  14772. return false;
  14773. }
  14774. $functionNameIndex = $tokens->getNextMeaningfulToken($index);
  14775. $functionName = strtolower($tokens[$functionNameIndex]->getContent());
  14776. return 'setup' === $functionName || 'teardown' === $functionName;
  14777. }
  14778. }
  14779. <?php
  14780. namespace PhpCsFixer\Fixer\PhpUnit;
  14781. use PhpCsFixer\AbstractFixer;
  14782. use PhpCsFixer\DocBlock\DocBlock;
  14783. use PhpCsFixer\FixerDefinition\CodeSample;
  14784. use PhpCsFixer\FixerDefinition\FixerDefinition;
  14785. use PhpCsFixer\Preg;
  14786. use PhpCsFixer\Tokenizer\Token;
  14787. use PhpCsFixer\Tokenizer\Tokens;
  14788. final class PhpUnitOrderedCoversFixer extends AbstractFixer
  14789. {
  14790. public function getDefinition()
  14791. {
  14792. return new FixerDefinition(
  14793. 'Order `@covers` annotation of PHPUnit tests.',
  14794. [
  14795. new CodeSample(
  14796. '<?php
  14797. /**
  14798. * @covers Foo
  14799. * @covers Bar
  14800. */
  14801. final class MyTest extends \PHPUnit_Framework_TestCase
  14802. {}
  14803. '
  14804. ),
  14805. ]
  14806. );
  14807. }
  14808. public function getPriority()
  14809. {
  14810. return -10;
  14811. }
  14812. public function isCandidate(Tokens $tokens)
  14813. {
  14814. return $tokens->isAllTokenKindsFound([T_CLASS, T_DOC_COMMENT]);
  14815. }
  14816. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  14817. {
  14818. for ($index = $tokens->count() - 1; $index > 0; --$index) {
  14819. if (!$tokens[$index]->isGivenKind(T_DOC_COMMENT) || 0 === Preg::match('/@covers\s.+@covers\s/s', $tokens[$index]->getContent())) {
  14820. continue;
  14821. }
  14822. $docBlock = new DocBlock($tokens[$index]->getContent());
  14823. $covers = $docBlock->getAnnotationsOfType('covers');
  14824. $coversMap = [];
  14825. foreach ($covers as $annotation) {
  14826. $rawContent = $annotation->getContent();
  14827. $comparableContent = Preg::replace('/\*\s*@covers\s+(.+)/', '\1', strtolower(trim($rawContent)));
  14828. $coversMap[$comparableContent] = $rawContent;
  14829. }
  14830. $orderedCoversMap = $coversMap;
  14831. ksort($orderedCoversMap, SORT_STRING);
  14832. if ($orderedCoversMap === $coversMap) {
  14833. continue;
  14834. }
  14835. $lines = $docBlock->getLines();
  14836. foreach (array_reverse($covers) as $annotation) {
  14837. array_splice(
  14838. $lines,
  14839. $annotation->getStart(),
  14840. $annotation->getEnd() - $annotation->getStart() + 1,
  14841. array_pop($orderedCoversMap)
  14842. );
  14843. }
  14844. $tokens[$index] = new Token([T_DOC_COMMENT, implode('', $lines)]);
  14845. }
  14846. }
  14847. }
  14848. <?php
  14849. namespace PhpCsFixer\Fixer\PhpUnit;
  14850. use PhpCsFixer\AbstractFixer;
  14851. use PhpCsFixer\DocBlock\Annotation;
  14852. use PhpCsFixer\DocBlock\DocBlock;
  14853. use PhpCsFixer\DocBlock\Line;
  14854. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  14855. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  14856. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  14857. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  14858. use PhpCsFixer\FixerDefinition\CodeSample;
  14859. use PhpCsFixer\FixerDefinition\FixerDefinition;
  14860. use PhpCsFixer\Indicator\PhpUnitTestCaseIndicator;
  14861. use PhpCsFixer\Tokenizer\Token;
  14862. use PhpCsFixer\Tokenizer\Tokens;
  14863. use SplFileInfo;
  14864. final class PhpUnitSizeClassFixer extends AbstractFixer implements WhitespacesAwareFixerInterface, ConfigurationDefinitionFixerInterface
  14865. {
  14866. public function getDefinition()
  14867. {
  14868. return new FixerDefinition(
  14869. 'All PHPUnit test cases should have `@small`, `@medium` or `@large` annotation to enable run time limits.',
  14870. [
  14871. new CodeSample("<?php\nclass MyTest extends TestCase {}\n"),
  14872. new CodeSample("<?php\nclass MyTest extends TestCase {}\n", ['group' => 'medium']),
  14873. ],
  14874. 'The special groups [small, medium, large] provides a way to identify tests that are taking long to be executed.'
  14875. );
  14876. }
  14877. public function isCandidate(Tokens $tokens)
  14878. {
  14879. return $tokens->isAllTokenKindsFound([T_CLASS, T_STRING]);
  14880. }
  14881. protected function applyFix(SplFileInfo $file, Tokens $tokens)
  14882. {
  14883. $phpUnitTestCaseIndicator = new PhpUnitTestCaseIndicator();
  14884. foreach ($phpUnitTestCaseIndicator->findPhpUnitClasses($tokens, true) as $indexes) {
  14885. $this->markClassSize($tokens, $indexes[0]);
  14886. }
  14887. }
  14888. protected function createConfigurationDefinition()
  14889. {
  14890. return new FixerConfigurationResolver([
  14891. (new FixerOptionBuilder('group', 'Define a specific group to be used in case no group is already in use'))
  14892. ->setAllowedValues(['small', 'medium', 'large'])
  14893. ->setDefault('small')
  14894. ->getOption(),
  14895. ]);
  14896. }
  14897. private function markClassSize(Tokens $tokens, $startIndex)
  14898. {
  14899. $classIndex = $tokens->getPrevTokenOfKind($startIndex, [[T_CLASS]]);
  14900. if ($this->isAbstractClass($tokens, $classIndex)) {
  14901. return;
  14902. }
  14903. $docBlockIndex = $this->getDocBlockIndex($tokens, $classIndex);
  14904. if ($this->hasDocBlock($tokens, $classIndex)) {
  14905. $this->updateDocBlockIfNeeded($tokens, $docBlockIndex);
  14906. return;
  14907. }
  14908. $this->createDocBlock($tokens, $docBlockIndex);
  14909. }
  14910. private function isAbstractClass(Tokens $tokens, $i)
  14911. {
  14912. $typeIndex = $tokens->getPrevMeaningfulToken($i);
  14913. return $tokens[$typeIndex]->isGivenKind(T_ABSTRACT);
  14914. }
  14915. private function createDocBlock(Tokens $tokens, $docBlockIndex)
  14916. {
  14917. $lineEnd = $this->whitespacesConfig->getLineEnding();
  14918. $originalIndent = $this->detectIndent($tokens, $tokens->getNextNonWhitespace($docBlockIndex));
  14919. $group = $this->configuration['group'];
  14920. $toInsert = [
  14921. new Token([T_DOC_COMMENT, '/**'.$lineEnd."{$originalIndent} * @".$group.$lineEnd."{$originalIndent} */"]),
  14922. new Token([T_WHITESPACE, $lineEnd.$originalIndent]),
  14923. ];
  14924. $index = $tokens->getNextMeaningfulToken($docBlockIndex);
  14925. $tokens->insertAt($index, $toInsert);
  14926. }
  14927. private function updateDocBlockIfNeeded(Tokens $tokens, $docBlockIndex)
  14928. {
  14929. $doc = new DocBlock($tokens[$docBlockIndex]->getContent());
  14930. if (!empty($this->filterDocBlock($doc))) {
  14931. return;
  14932. }
  14933. $doc = $this->makeDocBlockMultiLineIfNeeded($doc, $tokens, $docBlockIndex);
  14934. $lines = $this->addSizeAnnotation($doc, $tokens, $docBlockIndex);
  14935. $lines = implode('', $lines);
  14936. $tokens[$docBlockIndex] = new Token([T_DOC_COMMENT, $lines]);
  14937. }
  14938. private function hasDocBlock(Tokens $tokens, $index)
  14939. {
  14940. $docBlockIndex = $this->getDocBlockIndex($tokens, $index);
  14941. return $tokens[$docBlockIndex]->isGivenKind(T_DOC_COMMENT);
  14942. }
  14943. private function getDocBlockIndex(Tokens $tokens, $index)
  14944. {
  14945. do {
  14946. $index = $tokens->getPrevNonWhitespace($index);
  14947. } while ($tokens[$index]->isGivenKind([T_PUBLIC, T_PROTECTED, T_PRIVATE, T_FINAL, T_ABSTRACT, T_COMMENT]));
  14948. return $index;
  14949. }
  14950. private function detectIndent(Tokens $tokens, $index)
  14951. {
  14952. if (!$tokens[$index - 1]->isWhitespace()) {
  14953. return '';
  14954. }
  14955. $explodedContent = explode($this->whitespacesConfig->getLineEnding(), $tokens[$index - 1]->getContent());
  14956. return end($explodedContent);
  14957. }
  14958. private function addSizeAnnotation(DocBlock $docBlock, Tokens $tokens, $docBlockIndex)
  14959. {
  14960. $lines = $docBlock->getLines();
  14961. $originalIndent = $this->detectIndent($tokens, $docBlockIndex);
  14962. $lineEnd = $this->whitespacesConfig->getLineEnding();
  14963. $group = $this->configuration['group'];
  14964. array_splice($lines, -1, 0, $originalIndent.' *'.$lineEnd.$originalIndent.' * @'.$group.$lineEnd);
  14965. return $lines;
  14966. }
  14967. private function makeDocBlockMultiLineIfNeeded(DocBlock $doc, Tokens $tokens, $docBlockIndex)
  14968. {
  14969. $lines = $doc->getLines();
  14970. if (1 === \count($lines) && empty($this->filterDocBlock($doc))) {
  14971. $lines = $this->splitUpDocBlock($lines, $tokens, $docBlockIndex);
  14972. return new DocBlock(implode('', $lines));
  14973. }
  14974. return $doc;
  14975. }
  14976. private function splitUpDocBlock($lines, Tokens $tokens, $docBlockIndex)
  14977. {
  14978. $lineContent = $this->getSingleLineDocBlockEntry($lines);
  14979. $lineEnd = $this->whitespacesConfig->getLineEnding();
  14980. $originalIndent = $this->detectIndent($tokens, $tokens->getNextNonWhitespace($docBlockIndex));
  14981. return [
  14982. new Line('/**'.$lineEnd),
  14983. new Line($originalIndent.' * '.$lineContent.$lineEnd),
  14984. new Line($originalIndent.' */'),
  14985. ];
  14986. }
  14987. private function getSingleLineDocBlockEntry($line)
  14988. {
  14989. $line = $line[0];
  14990. $line = str_replace('*/', '', $line);
  14991. $line = trim($line);
  14992. $line = str_split($line);
  14993. $i = \count($line);
  14994. do {
  14995. --$i;
  14996. } while ('*' !== $line[$i] && '*' !== $line[$i - 1] && '/' !== $line[$i - 2]);
  14997. if (' ' === $line[$i]) {
  14998. ++$i;
  14999. }
  15000. $line = \array_slice($line, $i);
  15001. return implode('', $line);
  15002. }
  15003. private function filterDocBlock(DocBlock $doc)
  15004. {
  15005. return array_filter([
  15006. $doc->getAnnotationsOfType('small'),
  15007. $doc->getAnnotationsOfType('large'),
  15008. $doc->getAnnotationsOfType('medium'),
  15009. ]);
  15010. }
  15011. }
  15012. <?php
  15013. namespace PhpCsFixer\Fixer\PhpUnit;
  15014. use PhpCsFixer\AbstractFixer;
  15015. use PhpCsFixer\DocBlock\Annotation;
  15016. use PhpCsFixer\DocBlock\DocBlock;
  15017. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  15018. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  15019. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  15020. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  15021. use PhpCsFixer\FixerDefinition\CodeSample;
  15022. use PhpCsFixer\FixerDefinition\FixerDefinition;
  15023. use PhpCsFixer\Indicator\PhpUnitTestCaseIndicator;
  15024. use PhpCsFixer\Preg;
  15025. use PhpCsFixer\Tokenizer\Token;
  15026. use PhpCsFixer\Tokenizer\Tokens;
  15027. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  15028. final class PhpUnitNoExpectationAnnotationFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface, WhitespacesAwareFixerInterface
  15029. {
  15030. private $fixMessageRegExp;
  15031. public function configure(array $configuration = null)
  15032. {
  15033. parent::configure($configuration);
  15034. $this->fixMessageRegExp = PhpUnitTargetVersion::fulfills($this->configuration['target'], PhpUnitTargetVersion::VERSION_4_3);
  15035. }
  15036. public function getDefinition()
  15037. {
  15038. return new FixerDefinition(
  15039. 'Usages of `@expectedException*` annotations MUST be replaced by `->setExpectedException*` methods.',
  15040. [
  15041. new CodeSample(
  15042. '<?php
  15043. final class MyTest extends \PHPUnit_Framework_TestCase
  15044. {
  15045. /**
  15046. * @expectedException FooException
  15047. * @expectedExceptionMessageRegExp /foo.*$/
  15048. * @expectedExceptionCode 123
  15049. */
  15050. function testAaa()
  15051. {
  15052. aaa();
  15053. }
  15054. }
  15055. '
  15056. ),
  15057. new CodeSample(
  15058. '<?php
  15059. final class MyTest extends \PHPUnit_Framework_TestCase
  15060. {
  15061. /**
  15062. * @expectedException FooException
  15063. * @expectedExceptionCode 123
  15064. */
  15065. function testBbb()
  15066. {
  15067. bbb();
  15068. }
  15069. /**
  15070. * @expectedException FooException
  15071. * @expectedExceptionMessageRegExp /foo.*$/
  15072. */
  15073. function testCcc()
  15074. {
  15075. ccc();
  15076. }
  15077. }
  15078. ',
  15079. ['target' => PhpUnitTargetVersion::VERSION_3_2]
  15080. ),
  15081. ],
  15082. null,
  15083. 'Risky when PHPUnit classes are overridden or not accessible, or when project has PHPUnit incompatibilities.'
  15084. );
  15085. }
  15086. public function getPriority()
  15087. {
  15088. return 10;
  15089. }
  15090. public function isCandidate(Tokens $tokens)
  15091. {
  15092. return $tokens->isAllTokenKindsFound([T_CLASS, T_DOC_COMMENT]);
  15093. }
  15094. public function isRisky()
  15095. {
  15096. return true;
  15097. }
  15098. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  15099. {
  15100. $phpUnitTestCaseIndicator = new PhpUnitTestCaseIndicator();
  15101. foreach ($phpUnitTestCaseIndicator->findPhpUnitClasses($tokens) as $indexes) {
  15102. $this->fixPhpUnitClass($tokens, $indexes[0], $indexes[1]);
  15103. }
  15104. }
  15105. protected function createConfigurationDefinition()
  15106. {
  15107. return new FixerConfigurationResolver([
  15108. (new FixerOptionBuilder('target', 'Target version of PHPUnit.'))
  15109. ->setAllowedTypes(['string'])
  15110. ->setAllowedValues([PhpUnitTargetVersion::VERSION_3_2, PhpUnitTargetVersion::VERSION_4_3, PhpUnitTargetVersion::VERSION_NEWEST])
  15111. ->setDefault(PhpUnitTargetVersion::VERSION_NEWEST)
  15112. ->getOption(),
  15113. (new FixerOptionBuilder('use_class_const', 'Use ::class notation.'))
  15114. ->setAllowedTypes(['bool'])
  15115. ->setDefault(true)
  15116. ->getOption(),
  15117. ]);
  15118. }
  15119. private function detectIndent(Tokens $tokens, $index)
  15120. {
  15121. if (!$tokens[$index - 1]->isWhitespace()) {
  15122. return '';
  15123. }
  15124. $explodedContent = explode("\n", $tokens[$index - 1]->getContent());
  15125. return end($explodedContent);
  15126. }
  15127. private function fixPhpUnitClass(Tokens $tokens, $startIndex, $endIndex)
  15128. {
  15129. $tokensAnalyzer = new TokensAnalyzer($tokens);
  15130. for ($i = $endIndex - 1; $i > $startIndex; --$i) {
  15131. if (!$tokens[$i]->isGivenKind(T_FUNCTION) || $tokensAnalyzer->isLambda($i)) {
  15132. continue;
  15133. }
  15134. $functionIndex = $i;
  15135. $docBlockIndex = $i;
  15136. $braceIndex = $tokens->getNextTokenOfKind($functionIndex, [';', '{']);
  15137. if (!$tokens[$braceIndex]->equals('{')) {
  15138. continue;
  15139. }
  15140. do {
  15141. $docBlockIndex = $tokens->getPrevNonWhitespace($docBlockIndex);
  15142. } while ($tokens[$docBlockIndex]->isGivenKind([T_PUBLIC, T_PROTECTED, T_PRIVATE, T_FINAL, T_ABSTRACT, T_COMMENT]));
  15143. if (!$tokens[$docBlockIndex]->isGivenKind(T_DOC_COMMENT)) {
  15144. continue;
  15145. }
  15146. $doc = new DocBlock($tokens[$docBlockIndex]->getContent());
  15147. $annotations = [];
  15148. foreach ($doc->getAnnotationsOfType([
  15149. 'expectedException',
  15150. 'expectedExceptionCode',
  15151. 'expectedExceptionMessage',
  15152. 'expectedExceptionMessageRegExp',
  15153. ]) as $annotation) {
  15154. $tag = $annotation->getTag()->getName();
  15155. $content = $this->extractContentFromAnnotation($annotation);
  15156. $annotations[$tag] = $content;
  15157. $annotation->remove();
  15158. }
  15159. if (!isset($annotations['expectedException'])) {
  15160. continue;
  15161. }
  15162. if (!$this->fixMessageRegExp && isset($annotations['expectedExceptionMessageRegExp'])) {
  15163. continue;
  15164. }
  15165. $originalIndent = $this->detectIndent($tokens, $docBlockIndex);
  15166. $paramList = $this->annotationsToParamList($annotations);
  15167. $newMethodsCode = '<?php $this->'
  15168. .(isset($annotations['expectedExceptionMessageRegExp']) ? 'setExpectedExceptionRegExp' : 'setExpectedException')
  15169. .'('
  15170. .implode(', ', $paramList)
  15171. .');';
  15172. $newMethods = Tokens::fromCode($newMethodsCode);
  15173. $newMethods[0] = new Token([
  15174. T_WHITESPACE,
  15175. $this->whitespacesConfig->getLineEnding().$originalIndent.$this->whitespacesConfig->getIndent(),
  15176. ]);
  15177. $tokens[$docBlockIndex] = new Token([T_DOC_COMMENT, $doc->getContent()]);
  15178. $tokens->insertAt($braceIndex + 1, $newMethods);
  15179. $whitespaceIndex = $braceIndex + $newMethods->getSize() + 1;
  15180. $tokens[$whitespaceIndex] = new Token([
  15181. T_WHITESPACE,
  15182. $this->whitespacesConfig->getLineEnding().$tokens[$whitespaceIndex]->getContent(),
  15183. ]);
  15184. $i = $docBlockIndex;
  15185. }
  15186. }
  15187. private function extractContentFromAnnotation(Annotation $annotation)
  15188. {
  15189. $tag = $annotation->getTag()->getName();
  15190. if (1 !== Preg::match('/@'.$tag.'\s+(.+)$/s', $annotation->getContent(), $matches)) {
  15191. return '';
  15192. }
  15193. $content = $matches[1];
  15194. if (Preg::match('/\R/u', $content)) {
  15195. $content = Preg::replace('/\s*\R+\s*\*\s*/u', ' ', $content);
  15196. }
  15197. return rtrim($content);
  15198. }
  15199. private function annotationsToParamList(array $annotations)
  15200. {
  15201. $params = [];
  15202. $exceptionClass = ltrim($annotations['expectedException'], '\\');
  15203. if ($this->configuration['use_class_const']) {
  15204. $params[] = "\\{$exceptionClass}::class";
  15205. } else {
  15206. $params[] = "'{$exceptionClass}'";
  15207. }
  15208. if (isset($annotations['expectedExceptionMessage'])) {
  15209. $params[] = var_export($annotations['expectedExceptionMessage'], true);
  15210. } elseif (isset($annotations['expectedExceptionMessageRegExp'])) {
  15211. $params[] = var_export($annotations['expectedExceptionMessageRegExp'], true);
  15212. } elseif (isset($annotations['expectedExceptionCode'])) {
  15213. $params[] = 'null';
  15214. }
  15215. if (isset($annotations['expectedExceptionCode'])) {
  15216. $params[] = $annotations['expectedExceptionCode'];
  15217. }
  15218. return $params;
  15219. }
  15220. }
  15221. <?php
  15222. namespace PhpCsFixer\Fixer\PhpUnit;
  15223. use PhpCsFixer\AbstractFixer;
  15224. use PhpCsFixer\DocBlock\DocBlock;
  15225. use PhpCsFixer\DocBlock\Line;
  15226. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  15227. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  15228. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  15229. use PhpCsFixer\FixerDefinition\CodeSample;
  15230. use PhpCsFixer\FixerDefinition\FixerDefinition;
  15231. use PhpCsFixer\Indicator\PhpUnitTestCaseIndicator;
  15232. use PhpCsFixer\Preg;
  15233. use PhpCsFixer\Tokenizer\Token;
  15234. use PhpCsFixer\Tokenizer\Tokens;
  15235. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  15236. use PhpCsFixer\Utils;
  15237. final class PhpUnitMethodCasingFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface
  15238. {
  15239. const CAMEL_CASE = 'camel_case';
  15240. const SNAKE_CASE = 'snake_case';
  15241. public function getDefinition()
  15242. {
  15243. return new FixerDefinition(
  15244. 'Enforce camel (or snake) case for PHPUnit test methods, following configuration.',
  15245. [
  15246. new CodeSample(
  15247. '<?php
  15248. class MyTest extends \\PhpUnit\\FrameWork\\TestCase
  15249. {
  15250. public function test_my_code() {}
  15251. }
  15252. '
  15253. ),
  15254. new CodeSample(
  15255. '<?php
  15256. class MyTest extends \\PhpUnit\\FrameWork\\TestCase
  15257. {
  15258. public function testMyCode() {}
  15259. }
  15260. ',
  15261. ['case' => self::SNAKE_CASE]
  15262. ),
  15263. ]
  15264. );
  15265. }
  15266. public function getPriority()
  15267. {
  15268. return 0;
  15269. }
  15270. public function isCandidate(Tokens $tokens)
  15271. {
  15272. return $tokens->isAllTokenKindsFound([T_CLASS, T_FUNCTION]);
  15273. }
  15274. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  15275. {
  15276. $phpUnitTestCaseIndicator = new PhpUnitTestCaseIndicator();
  15277. foreach ($phpUnitTestCaseIndicator->findPhpUnitClasses($tokens) as $indexes) {
  15278. $this->applyCasing($tokens, $indexes[0], $indexes[1]);
  15279. }
  15280. }
  15281. protected function createConfigurationDefinition()
  15282. {
  15283. return new FixerConfigurationResolver([
  15284. (new FixerOptionBuilder('case', 'Apply camel or snake case to test methods'))
  15285. ->setAllowedValues([self::CAMEL_CASE, self::SNAKE_CASE])
  15286. ->setDefault(self::CAMEL_CASE)
  15287. ->getOption(),
  15288. ]);
  15289. }
  15290. private function applyCasing(Tokens $tokens, $startIndex, $endIndex)
  15291. {
  15292. for ($index = $endIndex - 1; $index > $startIndex; --$index) {
  15293. if (!$this->isTestMethod($tokens, $index)) {
  15294. continue;
  15295. }
  15296. $functionNameIndex = $tokens->getNextMeaningfulToken($index);
  15297. $functionName = $tokens[$functionNameIndex]->getContent();
  15298. $newFunctionName = $this->updateMethodCasing($functionName);
  15299. if ($newFunctionName !== $functionName) {
  15300. $tokens[$functionNameIndex] = new Token([T_STRING, $newFunctionName]);
  15301. }
  15302. $docBlockIndex = $this->getDocBlockIndex($tokens, $index);
  15303. if ($this->hasDocBlock($tokens, $index)) {
  15304. $this->updateDocBlock($tokens, $docBlockIndex);
  15305. }
  15306. }
  15307. }
  15308. private function updateMethodCasing($functionName)
  15309. {
  15310. if (self::CAMEL_CASE === $this->configuration['case']) {
  15311. $newFunctionName = $functionName;
  15312. $newFunctionName = ucwords($newFunctionName, '_');
  15313. $newFunctionName = str_replace('_', '', $newFunctionName);
  15314. $newFunctionName = lcfirst($newFunctionName);
  15315. } else {
  15316. $newFunctionName = Utils::camelCaseToUnderscore($functionName);
  15317. }
  15318. return $newFunctionName;
  15319. }
  15320. private function isTestMethod(Tokens $tokens, $index)
  15321. {
  15322. if (!$this->isMethod($tokens, $index)) {
  15323. return false;
  15324. }
  15325. $functionNameIndex = $tokens->getNextMeaningfulToken($index);
  15326. $functionName = $tokens[$functionNameIndex]->getContent();
  15327. if ($this->startsWith('test', $functionName)) {
  15328. return true;
  15329. }
  15330. if (!$this->hasDocBlock($tokens, $index)) {
  15331. return false;
  15332. }
  15333. $docBlockIndex = $this->getDocBlockIndex($tokens, $index);
  15334. $doc = $tokens[$docBlockIndex]->getContent();
  15335. if (false === strpos($doc, '@test')) {
  15336. return false;
  15337. }
  15338. return true;
  15339. }
  15340. private function isMethod(Tokens $tokens, $index)
  15341. {
  15342. $tokensAnalyzer = new TokensAnalyzer($tokens);
  15343. return $tokens[$index]->isGivenKind(T_FUNCTION) && !$tokensAnalyzer->isLambda($index);
  15344. }
  15345. private function startsWith($needle, $haystack)
  15346. {
  15347. return substr($haystack, 0, \strlen($needle)) === $needle;
  15348. }
  15349. private function hasDocBlock(Tokens $tokens, $index)
  15350. {
  15351. $docBlockIndex = $this->getDocBlockIndex($tokens, $index);
  15352. return $tokens[$docBlockIndex]->isGivenKind(T_DOC_COMMENT);
  15353. }
  15354. private function getDocBlockIndex(Tokens $tokens, $index)
  15355. {
  15356. do {
  15357. $index = $tokens->getPrevNonWhitespace($index);
  15358. } while ($tokens[$index]->isGivenKind([T_PUBLIC, T_PROTECTED, T_PRIVATE, T_FINAL, T_ABSTRACT, T_COMMENT]));
  15359. return $index;
  15360. }
  15361. private function updateDocBlock(Tokens $tokens, $docBlockIndex)
  15362. {
  15363. $doc = new DocBlock($tokens[$docBlockIndex]->getContent());
  15364. $lines = $doc->getLines();
  15365. $docBlockNeedsUpdate = false;
  15366. for ($inc = 0; $inc < \count($lines); ++$inc) {
  15367. $lineContent = $lines[$inc]->getContent();
  15368. if (false === strpos($lineContent, '@depends')) {
  15369. continue;
  15370. }
  15371. $newLineContent = Preg::replaceCallback('/(@depends\s+)(.+)(\b)/', function (array $matches) {
  15372. return sprintf(
  15373. '%s%s%s',
  15374. $matches[1],
  15375. $this->updateMethodCasing($matches[2]),
  15376. $matches[3]
  15377. );
  15378. }, $lineContent);
  15379. if ($newLineContent !== $lineContent) {
  15380. $lines[$inc] = new Line($newLineContent);
  15381. $docBlockNeedsUpdate = true;
  15382. }
  15383. }
  15384. if ($docBlockNeedsUpdate) {
  15385. $lines = implode('', $lines);
  15386. $tokens[$docBlockIndex] = new Token([T_DOC_COMMENT, $lines]);
  15387. }
  15388. }
  15389. }
  15390. <?php
  15391. namespace PhpCsFixer\Fixer\PhpUnit;
  15392. use Composer\Semver\Comparator;
  15393. final class PhpUnitTargetVersion
  15394. {
  15395. const VERSION_3_0 = '3.0';
  15396. const VERSION_3_2 = '3.2';
  15397. const VERSION_3_5 = '3.5';
  15398. const VERSION_4_3 = '4.3';
  15399. const VERSION_4_8 = '4.8';
  15400. const VERSION_5_0 = '5.0';
  15401. const VERSION_5_2 = '5.2';
  15402. const VERSION_5_4 = '5.4';
  15403. const VERSION_5_5 = '5.5';
  15404. const VERSION_5_6 = '5.6';
  15405. const VERSION_5_7 = '5.7';
  15406. const VERSION_6_0 = '6.0';
  15407. const VERSION_7_5 = '7.5';
  15408. const VERSION_NEWEST = 'newest';
  15409. private function __construct()
  15410. {
  15411. }
  15412. public static function fulfills($candidate, $target)
  15413. {
  15414. if (self::VERSION_NEWEST === $target) {
  15415. throw new \LogicException(sprintf('Parameter `target` shall not be provided as `%s`, determine proper target for tested PHPUnit feature instead.', self::VERSION_NEWEST));
  15416. }
  15417. if (self::VERSION_NEWEST === $candidate) {
  15418. return true;
  15419. }
  15420. return Comparator::greaterThanOrEqualTo($candidate, $target);
  15421. }
  15422. }
  15423. <?php
  15424. namespace PhpCsFixer\Fixer\PhpUnit;
  15425. use PhpCsFixer\AbstractFixer;
  15426. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  15427. use PhpCsFixer\FixerConfiguration\AllowedValueSubset;
  15428. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverRootless;
  15429. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  15430. use PhpCsFixer\FixerDefinition\CodeSample;
  15431. use PhpCsFixer\FixerDefinition\FixerDefinition;
  15432. use PhpCsFixer\Tokenizer\Analyzer\FunctionsAnalyzer;
  15433. use PhpCsFixer\Tokenizer\Token;
  15434. use PhpCsFixer\Tokenizer\Tokens;
  15435. final class PhpUnitConstructFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface
  15436. {
  15437. private static $assertionFixers = [
  15438. 'assertSame' => 'fixAssertPositive',
  15439. 'assertEquals' => 'fixAssertPositive',
  15440. 'assertNotEquals' => 'fixAssertNegative',
  15441. 'assertNotSame' => 'fixAssertNegative',
  15442. ];
  15443. public function isCandidate(Tokens $tokens)
  15444. {
  15445. return $tokens->isTokenKindFound(T_STRING);
  15446. }
  15447. public function isRisky()
  15448. {
  15449. return true;
  15450. }
  15451. public function getDefinition()
  15452. {
  15453. return new FixerDefinition(
  15454. 'PHPUnit assertion method calls like `->assertSame(true, $foo)` should be written with dedicated method like `->assertTrue($foo)`.',
  15455. [
  15456. new CodeSample(
  15457. '<?php
  15458. $this->assertEquals(false, $b);
  15459. $this->assertSame(true, $a);
  15460. $this->assertNotEquals(null, $c);
  15461. $this->assertNotSame(null, $d);
  15462. '
  15463. ),
  15464. new CodeSample(
  15465. '<?php
  15466. $this->assertEquals(false, $b);
  15467. $this->assertSame(true, $a);
  15468. $this->assertNotEquals(null, $c);
  15469. $this->assertNotSame(null, $d);
  15470. ',
  15471. ['assertions' => ['assertSame', 'assertNotSame']]
  15472. ),
  15473. ],
  15474. null,
  15475. 'Fixer could be risky if one is overriding PHPUnit\'s native methods.'
  15476. );
  15477. }
  15478. public function getPriority()
  15479. {
  15480. return -10;
  15481. }
  15482. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  15483. {
  15484. if (empty($this->configuration['assertions'])) {
  15485. return;
  15486. }
  15487. foreach ($this->configuration['assertions'] as $assertionMethod) {
  15488. $assertionFixer = self::$assertionFixers[$assertionMethod];
  15489. for ($index = 0, $limit = $tokens->count(); $index < $limit; ++$index) {
  15490. $index = $this->{$assertionFixer}($tokens, $index, $assertionMethod);
  15491. if (null === $index) {
  15492. break;
  15493. }
  15494. }
  15495. }
  15496. }
  15497. protected function createConfigurationDefinition()
  15498. {
  15499. return new FixerConfigurationResolverRootless('assertions', [
  15500. (new FixerOptionBuilder('assertions', 'List of assertion methods to fix.'))
  15501. ->setAllowedTypes(['array'])
  15502. ->setAllowedValues([new AllowedValueSubset(array_keys(self::$assertionFixers))])
  15503. ->setDefault([
  15504. 'assertEquals',
  15505. 'assertSame',
  15506. 'assertNotEquals',
  15507. 'assertNotSame',
  15508. ])
  15509. ->getOption(),
  15510. ], $this->getName());
  15511. }
  15512. private function fixAssertNegative(Tokens $tokens, $index, $method)
  15513. {
  15514. static $map = [
  15515. 'false' => 'assertNotFalse',
  15516. 'null' => 'assertNotNull',
  15517. 'true' => 'assertNotTrue',
  15518. ];
  15519. return $this->fixAssert($map, $tokens, $index, $method);
  15520. }
  15521. private function fixAssertPositive(Tokens $tokens, $index, $method)
  15522. {
  15523. static $map = [
  15524. 'false' => 'assertFalse',
  15525. 'null' => 'assertNull',
  15526. 'true' => 'assertTrue',
  15527. ];
  15528. return $this->fixAssert($map, $tokens, $index, $method);
  15529. }
  15530. private function fixAssert(array $map, Tokens $tokens, $index, $method)
  15531. {
  15532. $functionsAnalyzer = new FunctionsAnalyzer();
  15533. $sequence = $tokens->findSequence(
  15534. [
  15535. [T_STRING, $method],
  15536. '(',
  15537. ],
  15538. $index
  15539. );
  15540. if (null === $sequence) {
  15541. return null;
  15542. }
  15543. $sequenceIndexes = array_keys($sequence);
  15544. if (!$functionsAnalyzer->isTheSameClassCall($tokens, $sequenceIndexes[0])) {
  15545. return null;
  15546. }
  15547. $sequenceIndexes[2] = $tokens->getNextMeaningfulToken($sequenceIndexes[1]);
  15548. $firstParameterToken = $tokens[$sequenceIndexes[2]];
  15549. if (!$firstParameterToken->isNativeConstant()) {
  15550. return $sequenceIndexes[2];
  15551. }
  15552. $sequenceIndexes[3] = $tokens->getNextMeaningfulToken($sequenceIndexes[2]);
  15553. if (!$tokens[$sequenceIndexes[3]]->equals(',')) {
  15554. return $sequenceIndexes[3];
  15555. }
  15556. $tokens[$sequenceIndexes[0]] = new Token([T_STRING, $map[strtolower($firstParameterToken->getContent())]]);
  15557. $tokens->clearRange($sequenceIndexes[2], $tokens->getNextNonWhitespace($sequenceIndexes[3]) - 1);
  15558. return $sequenceIndexes[3];
  15559. }
  15560. }
  15561. <?php
  15562. namespace PhpCsFixer\Fixer\PhpUnit;
  15563. use PhpCsFixer\AbstractFixer;
  15564. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  15565. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  15566. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  15567. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  15568. use PhpCsFixer\FixerDefinition\CodeSample;
  15569. use PhpCsFixer\FixerDefinition\FixerDefinition;
  15570. use PhpCsFixer\Indicator\PhpUnitTestCaseIndicator;
  15571. use PhpCsFixer\Tokenizer\Analyzer\ArgumentsAnalyzer;
  15572. use PhpCsFixer\Tokenizer\Token;
  15573. use PhpCsFixer\Tokenizer\Tokens;
  15574. final class PhpUnitExpectationFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface, WhitespacesAwareFixerInterface
  15575. {
  15576. private $methodMap = [];
  15577. public function configure(array $configuration = null)
  15578. {
  15579. parent::configure($configuration);
  15580. $this->methodMap = [
  15581. 'setExpectedException' => 'expectExceptionMessage',
  15582. ];
  15583. if (PhpUnitTargetVersion::fulfills($this->configuration['target'], PhpUnitTargetVersion::VERSION_5_6)) {
  15584. $this->methodMap['setExpectedExceptionRegExp'] = 'expectExceptionMessageRegExp';
  15585. }
  15586. }
  15587. public function getDefinition()
  15588. {
  15589. return new FixerDefinition(
  15590. 'Usages of `->setExpectedException*` methods MUST be replaced by `->expectException*` methods.',
  15591. [
  15592. new CodeSample(
  15593. '<?php
  15594. final class MyTest extends \PHPUnit_Framework_TestCase
  15595. {
  15596. public function testFoo()
  15597. {
  15598. $this->setExpectedException("RuntimeException", "Msg", 123);
  15599. foo();
  15600. }
  15601. public function testBar()
  15602. {
  15603. $this->setExpectedExceptionRegExp("RuntimeException", "/Msg.*/", 123);
  15604. bar();
  15605. }
  15606. }
  15607. '
  15608. ),
  15609. new CodeSample(
  15610. '<?php
  15611. final class MyTest extends \PHPUnit_Framework_TestCase
  15612. {
  15613. public function testFoo()
  15614. {
  15615. $this->setExpectedException("RuntimeException", null, 123);
  15616. foo();
  15617. }
  15618. public function testBar()
  15619. {
  15620. $this->setExpectedExceptionRegExp("RuntimeException", "/Msg.*/", 123);
  15621. bar();
  15622. }
  15623. }
  15624. ',
  15625. ['target' => PhpUnitTargetVersion::VERSION_5_6]
  15626. ),
  15627. new CodeSample(
  15628. '<?php
  15629. final class MyTest extends \PHPUnit_Framework_TestCase
  15630. {
  15631. public function testFoo()
  15632. {
  15633. $this->setExpectedException("RuntimeException", "Msg", 123);
  15634. foo();
  15635. }
  15636. public function testBar()
  15637. {
  15638. $this->setExpectedExceptionRegExp("RuntimeException", "/Msg.*/", 123);
  15639. bar();
  15640. }
  15641. }
  15642. ',
  15643. ['target' => PhpUnitTargetVersion::VERSION_5_2]
  15644. ),
  15645. ],
  15646. null,
  15647. 'Risky when PHPUnit classes are overridden or not accessible, or when project has PHPUnit incompatibilities.'
  15648. );
  15649. }
  15650. public function getPriority()
  15651. {
  15652. return 0;
  15653. }
  15654. public function isCandidate(Tokens $tokens)
  15655. {
  15656. return $tokens->isTokenKindFound(T_CLASS);
  15657. }
  15658. public function isRisky()
  15659. {
  15660. return true;
  15661. }
  15662. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  15663. {
  15664. $phpUnitTestCaseIndicator = new PhpUnitTestCaseIndicator();
  15665. foreach ($phpUnitTestCaseIndicator->findPhpUnitClasses($tokens) as $indexes) {
  15666. $this->fixExpectation($tokens, $indexes[0], $indexes[1]);
  15667. }
  15668. }
  15669. protected function createConfigurationDefinition()
  15670. {
  15671. return new FixerConfigurationResolver([
  15672. (new FixerOptionBuilder('target', 'Target version of PHPUnit.'))
  15673. ->setAllowedTypes(['string'])
  15674. ->setAllowedValues([PhpUnitTargetVersion::VERSION_5_2, PhpUnitTargetVersion::VERSION_5_6, PhpUnitTargetVersion::VERSION_NEWEST])
  15675. ->setDefault(PhpUnitTargetVersion::VERSION_NEWEST)
  15676. ->getOption(),
  15677. ]);
  15678. }
  15679. private function fixExpectation(Tokens $tokens, $startIndex, $endIndex)
  15680. {
  15681. $argumentsAnalyzer = new ArgumentsAnalyzer();
  15682. $oldMethodSequence = [
  15683. new Token([T_VARIABLE, '$this']),
  15684. new Token([T_OBJECT_OPERATOR, '->']),
  15685. [T_STRING],
  15686. ];
  15687. for ($index = $startIndex; $startIndex < $endIndex; ++$index) {
  15688. $match = $tokens->findSequence($oldMethodSequence, $index);
  15689. if (null === $match) {
  15690. return;
  15691. }
  15692. list($thisIndex, , $index) = array_keys($match);
  15693. if (!isset($this->methodMap[$tokens[$index]->getContent()])) {
  15694. continue;
  15695. }
  15696. $openIndex = $tokens->getNextTokenOfKind($index, ['(']);
  15697. $closeIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $openIndex);
  15698. $commaIndex = $tokens->getPrevMeaningfulToken($closeIndex);
  15699. if ($tokens[$commaIndex]->equals(',')) {
  15700. $tokens->removeTrailingWhitespace($commaIndex);
  15701. $tokens->clearAt($commaIndex);
  15702. }
  15703. $arguments = $argumentsAnalyzer->getArguments($tokens, $openIndex, $closeIndex);
  15704. $argumentsCnt = \count($arguments);
  15705. $argumentsReplacements = ['expectException', $this->methodMap[$tokens[$index]->getContent()], 'expectExceptionCode'];
  15706. $indent = $this->whitespacesConfig->getLineEnding().$this->detectIndent($tokens, $thisIndex);
  15707. $isMultilineWhitespace = false;
  15708. for ($cnt = $argumentsCnt - 1; $cnt >= 1; --$cnt) {
  15709. $argStart = array_keys($arguments)[$cnt];
  15710. $argBefore = $tokens->getPrevMeaningfulToken($argStart);
  15711. if ('expectExceptionMessage' === $argumentsReplacements[$cnt]) {
  15712. $paramIndicatorIndex = $tokens->getNextMeaningfulToken($argBefore);
  15713. $afterParamIndicatorIndex = $tokens->getNextMeaningfulToken($paramIndicatorIndex);
  15714. if (
  15715. $tokens[$paramIndicatorIndex]->equals([T_STRING, 'null'], false) &&
  15716. $tokens[$afterParamIndicatorIndex]->equals(')')
  15717. ) {
  15718. if ($tokens[$argBefore + 1]->isWhitespace()) {
  15719. $tokens->clearTokenAndMergeSurroundingWhitespace($argBefore + 1);
  15720. }
  15721. $tokens->clearTokenAndMergeSurroundingWhitespace($argBefore);
  15722. $tokens->clearTokenAndMergeSurroundingWhitespace($paramIndicatorIndex);
  15723. continue;
  15724. }
  15725. }
  15726. $isMultilineWhitespace = $isMultilineWhitespace || ($tokens[$argStart]->isWhitespace() && !$tokens[$argStart]->isWhitespace(" \t"));
  15727. $tokensOverrideArgStart = [
  15728. new Token([T_WHITESPACE, $indent]),
  15729. new Token([T_VARIABLE, '$this']),
  15730. new Token([T_OBJECT_OPERATOR, '->']),
  15731. new Token([T_STRING, $argumentsReplacements[$cnt]]),
  15732. new Token('('),
  15733. ];
  15734. $tokensOverrideArgBefore = [
  15735. new Token(')'),
  15736. new Token(';'),
  15737. ];
  15738. if ($isMultilineWhitespace) {
  15739. array_push($tokensOverrideArgStart, new Token([T_WHITESPACE, $indent.$this->whitespacesConfig->getIndent()]));
  15740. array_unshift($tokensOverrideArgBefore, new Token([T_WHITESPACE, $indent]));
  15741. }
  15742. if ($tokens[$argStart]->isWhitespace()) {
  15743. $tokens->overrideRange($argStart, $argStart, $tokensOverrideArgStart);
  15744. } else {
  15745. $tokens->insertAt($argStart, $tokensOverrideArgStart);
  15746. }
  15747. $tokens->overrideRange($argBefore, $argBefore, $tokensOverrideArgBefore);
  15748. }
  15749. $tokens[$index] = new Token([T_STRING, 'expectException']);
  15750. }
  15751. }
  15752. private function detectIndent(Tokens $tokens, $index)
  15753. {
  15754. if (!$tokens[$index - 1]->isWhitespace()) {
  15755. return '';
  15756. }
  15757. $explodedContent = explode("\n", $tokens[$index - 1]->getContent());
  15758. return end($explodedContent);
  15759. }
  15760. }
  15761. <?php
  15762. namespace PhpCsFixer\Fixer\PhpUnit;
  15763. use PhpCsFixer\AbstractFixer;
  15764. use PhpCsFixer\DocBlock\DocBlock;
  15765. use PhpCsFixer\DocBlock\Line;
  15766. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  15767. use PhpCsFixer\FixerDefinition\CodeSample;
  15768. use PhpCsFixer\FixerDefinition\FixerDefinition;
  15769. use PhpCsFixer\Indicator\PhpUnitTestCaseIndicator;
  15770. use PhpCsFixer\Preg;
  15771. use PhpCsFixer\Tokenizer\Token;
  15772. use PhpCsFixer\Tokenizer\Tokens;
  15773. final class PhpUnitTestClassRequiresCoversFixer extends AbstractFixer implements WhitespacesAwareFixerInterface
  15774. {
  15775. public function getDefinition()
  15776. {
  15777. return new FixerDefinition(
  15778. 'Adds a default `@coversNothing` annotation to PHPUnit test classes that have no `@covers*` annotation.',
  15779. [
  15780. new CodeSample(
  15781. '<?php
  15782. final class MyTest extends \PHPUnit_Framework_TestCase
  15783. {
  15784. public function testSomeTest()
  15785. {
  15786. $this->assertSame(a(), b());
  15787. }
  15788. }
  15789. '
  15790. ),
  15791. ]
  15792. );
  15793. }
  15794. public function isCandidate(Tokens $tokens)
  15795. {
  15796. return $tokens->isTokenKindFound(T_CLASS);
  15797. }
  15798. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  15799. {
  15800. $phpUnitTestCaseIndicator = new PhpUnitTestCaseIndicator();
  15801. foreach ($phpUnitTestCaseIndicator->findPhpUnitClasses($tokens) as $indexes) {
  15802. $this->addRequiresCover($tokens, $indexes[0]);
  15803. }
  15804. }
  15805. private function addRequiresCover(Tokens $tokens, $startIndex)
  15806. {
  15807. $classIndex = $tokens->getPrevTokenOfKind($startIndex, [[T_CLASS]]);
  15808. $prevIndex = $tokens->getPrevMeaningfulToken($classIndex);
  15809. if ($tokens[$prevIndex]->isGivenKind(T_ABSTRACT)) {
  15810. return;
  15811. }
  15812. $index = $tokens[$prevIndex]->isGivenKind(T_FINAL) ? $prevIndex : $classIndex;
  15813. $indent = $tokens[$index - 1]->isGivenKind(T_WHITESPACE)
  15814. ? Preg::replace('/^.*\R*/', '', $tokens[$index - 1]->getContent())
  15815. : '';
  15816. $prevIndex = $tokens->getPrevNonWhitespace($index);
  15817. if ($tokens[$prevIndex]->isGivenKind(T_DOC_COMMENT)) {
  15818. $docIndex = $prevIndex;
  15819. $docContent = $tokens[$docIndex]->getContent();
  15820. if (false === strpos($docContent, "\n")) {
  15821. return;
  15822. }
  15823. $doc = new DocBlock($docContent);
  15824. if (!empty($doc->getAnnotationsOfType([
  15825. 'covers',
  15826. 'coversDefaultClass',
  15827. 'coversNothing',
  15828. ]))) {
  15829. return;
  15830. }
  15831. } else {
  15832. $docIndex = $index;
  15833. $tokens->insertAt($docIndex, [
  15834. new Token([T_DOC_COMMENT, sprintf('/**%s%s */', $this->whitespacesConfig->getLineEnding(), $indent)]),
  15835. new Token([T_WHITESPACE, sprintf('%s%s', $this->whitespacesConfig->getLineEnding(), $indent)]),
  15836. ]);
  15837. if (!$tokens[$docIndex - 1]->isGivenKind(T_WHITESPACE)) {
  15838. $extraNewLines = $this->whitespacesConfig->getLineEnding();
  15839. if (!$tokens[$docIndex - 1]->isGivenKind(T_OPEN_TAG)) {
  15840. $extraNewLines .= $this->whitespacesConfig->getLineEnding();
  15841. }
  15842. $tokens->insertAt($docIndex, [
  15843. new Token([T_WHITESPACE, $extraNewLines.$indent]),
  15844. ]);
  15845. ++$docIndex;
  15846. }
  15847. $doc = new DocBlock($tokens[$docIndex]->getContent());
  15848. }
  15849. $lines = $doc->getLines();
  15850. array_splice(
  15851. $lines,
  15852. \count($lines) - 1,
  15853. 0,
  15854. [
  15855. new Line(sprintf(
  15856. '%s * @coversNothing%s',
  15857. $indent,
  15858. $this->whitespacesConfig->getLineEnding()
  15859. )),
  15860. ]
  15861. );
  15862. $tokens[$docIndex] = new Token([T_DOC_COMMENT, implode('', $lines)]);
  15863. }
  15864. }
  15865. <?php
  15866. namespace PhpCsFixer\Fixer\PhpUnit;
  15867. use PhpCsFixer\AbstractFixer;
  15868. use PhpCsFixer\FixerDefinition\CodeSample;
  15869. use PhpCsFixer\FixerDefinition\FixerDefinition;
  15870. use PhpCsFixer\Indicator\PhpUnitTestCaseIndicator;
  15871. use PhpCsFixer\Preg;
  15872. use PhpCsFixer\Tokenizer\Token;
  15873. use PhpCsFixer\Tokenizer\Tokens;
  15874. final class PhpUnitFqcnAnnotationFixer extends AbstractFixer
  15875. {
  15876. public function getDefinition()
  15877. {
  15878. return new FixerDefinition(
  15879. 'PHPUnit annotations should be a FQCNs including a root namespace.',
  15880. [new CodeSample(
  15881. '<?php
  15882. final class MyTest extends \PHPUnit_Framework_TestCase
  15883. {
  15884. /**
  15885. * @expectedException InvalidArgumentException
  15886. * @covers Project\NameSpace\Something
  15887. * @coversDefaultClass Project\Default
  15888. * @uses Project\Test\Util
  15889. */
  15890. public function testSomeTest()
  15891. {
  15892. }
  15893. }
  15894. '
  15895. )]
  15896. );
  15897. }
  15898. public function getPriority()
  15899. {
  15900. return -9;
  15901. }
  15902. public function isCandidate(Tokens $tokens)
  15903. {
  15904. return $tokens->isAllTokenKindsFound([T_CLASS, T_DOC_COMMENT]);
  15905. }
  15906. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  15907. {
  15908. $phpUnitTestCaseIndicator = new PhpUnitTestCaseIndicator();
  15909. foreach ($phpUnitTestCaseIndicator->findPhpUnitClasses($tokens) as $indexes) {
  15910. $startIndex = $indexes[0];
  15911. $prevDocCommentIndex = $tokens->getPrevTokenOfKind($startIndex, [[T_DOC_COMMENT]]);
  15912. if (null !== $prevDocCommentIndex) {
  15913. $startIndex = $prevDocCommentIndex;
  15914. }
  15915. $this->fixPhpUnitClass($tokens, $startIndex, $indexes[1]);
  15916. }
  15917. }
  15918. private function fixPhpUnitClass(Tokens $tokens, $startIndex, $endIndex)
  15919. {
  15920. for ($index = $startIndex; $index < $endIndex; ++$index) {
  15921. if ($tokens[$index]->isGivenKind(T_DOC_COMMENT)) {
  15922. $tokens[$index] = new Token([T_DOC_COMMENT, Preg::replace(
  15923. '~^(\s*\*\s*@(?:expectedException|covers|coversDefaultClass|uses)\h+)(?!(?:self|static)::)(\w.*)$~m',
  15924. '$1\\\\$2',
  15925. $tokens[$index]->getContent()
  15926. )]);
  15927. }
  15928. }
  15929. }
  15930. }
  15931. <?php
  15932. namespace PhpCsFixer\Fixer\PhpUnit;
  15933. use PhpCsFixer\AbstractFixer;
  15934. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  15935. use PhpCsFixer\FixerConfiguration\AllowedValueSubset;
  15936. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverRootless;
  15937. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  15938. use PhpCsFixer\FixerDefinition\CodeSample;
  15939. use PhpCsFixer\FixerDefinition\FixerDefinition;
  15940. use PhpCsFixer\Tokenizer\Analyzer\FunctionsAnalyzer;
  15941. use PhpCsFixer\Tokenizer\Token;
  15942. use PhpCsFixer\Tokenizer\Tokens;
  15943. final class PhpUnitDedicateAssertFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface
  15944. {
  15945. private static $fixMap = [
  15946. 'array_key_exists' => ['assertArrayNotHasKey', 'assertArrayHasKey'],
  15947. 'empty' => ['assertNotEmpty', 'assertEmpty'],
  15948. 'file_exists' => ['assertFileNotExists', 'assertFileExists'],
  15949. 'is_array' => true,
  15950. 'is_bool' => true,
  15951. 'is_callable' => true,
  15952. 'is_dir' => ['assertDirectoryNotExists', 'assertDirectoryExists'],
  15953. 'is_double' => true,
  15954. 'is_float' => true,
  15955. 'is_infinite' => ['assertFinite', 'assertInfinite'],
  15956. 'is_int' => true,
  15957. 'is_integer' => true,
  15958. 'is_long' => true,
  15959. 'is_nan' => [false, 'assertNan'],
  15960. 'is_null' => ['assertNotNull', 'assertNull'],
  15961. 'is_numeric' => true,
  15962. 'is_object' => true,
  15963. 'is_readable' => ['assertNotIsReadable', 'assertIsReadable'],
  15964. 'is_real' => true,
  15965. 'is_resource' => true,
  15966. 'is_scalar' => true,
  15967. 'is_string' => true,
  15968. 'is_writable' => ['assertNotIsWritable', 'assertIsWritable'],
  15969. ];
  15970. private $functions = [];
  15971. public function configure(array $configuration = null)
  15972. {
  15973. parent::configure($configuration);
  15974. if (isset($this->configuration['functions'])) {
  15975. $this->functions = $this->configuration['functions'];
  15976. return;
  15977. }
  15978. $this->functions = [
  15979. 'array_key_exists',
  15980. 'file_exists',
  15981. 'is_null',
  15982. ];
  15983. if (PhpUnitTargetVersion::fulfills($this->configuration['target'], PhpUnitTargetVersion::VERSION_3_5)) {
  15984. $this->functions = array_merge($this->functions, [
  15985. 'empty',
  15986. 'is_array',
  15987. 'is_bool',
  15988. 'is_boolean',
  15989. 'is_callable',
  15990. 'is_double',
  15991. 'is_float',
  15992. 'is_int',
  15993. 'is_integer',
  15994. 'is_long',
  15995. 'is_numeric',
  15996. 'is_object',
  15997. 'is_real',
  15998. 'is_resource',
  15999. 'is_scalar',
  16000. 'is_string',
  16001. ]);
  16002. }
  16003. if (PhpUnitTargetVersion::fulfills($this->configuration['target'], PhpUnitTargetVersion::VERSION_5_0)) {
  16004. $this->functions = array_merge($this->functions, [
  16005. 'is_infinite',
  16006. 'is_nan',
  16007. ]);
  16008. }
  16009. if (PhpUnitTargetVersion::fulfills($this->configuration['target'], PhpUnitTargetVersion::VERSION_5_6)) {
  16010. $this->functions = array_merge($this->functions, [
  16011. 'is_dir',
  16012. 'is_readable',
  16013. 'is_writable',
  16014. ]);
  16015. }
  16016. }
  16017. public function isCandidate(Tokens $tokens)
  16018. {
  16019. return $tokens->isTokenKindFound(T_STRING);
  16020. }
  16021. public function isRisky()
  16022. {
  16023. return true;
  16024. }
  16025. public function getDefinition()
  16026. {
  16027. return new FixerDefinition(
  16028. 'PHPUnit assertions like `assertInternalType`, `assertFileExists`, should be used over `assertTrue`.',
  16029. [
  16030. new CodeSample(
  16031. '<?php
  16032. $this->assertTrue(is_float( $a), "my message");
  16033. $this->assertTrue(is_nan($a));
  16034. '
  16035. ),
  16036. new CodeSample(
  16037. '<?php
  16038. $this->assertTrue(is_dir($a));
  16039. $this->assertTrue(is_writable($a));
  16040. $this->assertTrue(is_readable($a));
  16041. ',
  16042. ['target' => PhpUnitTargetVersion::VERSION_5_6]
  16043. ),
  16044. ],
  16045. null,
  16046. 'Fixer could be risky if one is overriding PHPUnit\'s native methods.'
  16047. );
  16048. }
  16049. public function getPriority()
  16050. {
  16051. return -15;
  16052. }
  16053. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  16054. {
  16055. foreach ($this->getPreviousAssertCall($tokens) as $assertCall) {
  16056. if ('asserttrue' === $assertCall['loweredName'] || 'assertfalse' === $assertCall['loweredName']) {
  16057. $this->fixAssertTrueFalse($tokens, $assertCall);
  16058. continue;
  16059. }
  16060. if (
  16061. 'assertsame' === $assertCall['loweredName']
  16062. || 'assertnotsame' === $assertCall['loweredName']
  16063. || 'assertequals' === $assertCall['loweredName']
  16064. || 'assertnotequals' === $assertCall['loweredName']
  16065. ) {
  16066. $this->fixAssertSameEquals($tokens, $assertCall);
  16067. continue;
  16068. }
  16069. }
  16070. }
  16071. protected function createConfigurationDefinition()
  16072. {
  16073. $values = [
  16074. 'array_key_exists',
  16075. 'empty',
  16076. 'file_exists',
  16077. 'is_array',
  16078. 'is_bool',
  16079. 'is_callable',
  16080. 'is_double',
  16081. 'is_float',
  16082. 'is_infinite',
  16083. 'is_int',
  16084. 'is_integer',
  16085. 'is_long',
  16086. 'is_nan',
  16087. 'is_null',
  16088. 'is_numeric',
  16089. 'is_object',
  16090. 'is_real',
  16091. 'is_resource',
  16092. 'is_scalar',
  16093. 'is_string',
  16094. ];
  16095. sort($values);
  16096. return new FixerConfigurationResolverRootless('functions', [
  16097. (new FixerOptionBuilder('functions', 'List of assertions to fix (overrides `target`).'))
  16098. ->setAllowedTypes(['null', 'array'])
  16099. ->setAllowedValues([
  16100. null,
  16101. new AllowedValueSubset($values),
  16102. ])
  16103. ->setDefault(null)
  16104. ->setDeprecationMessage('Use option `target` instead.')
  16105. ->getOption(),
  16106. (new FixerOptionBuilder('target', 'Target version of PHPUnit.'))
  16107. ->setAllowedTypes(['string'])
  16108. ->setAllowedValues([
  16109. PhpUnitTargetVersion::VERSION_3_0,
  16110. PhpUnitTargetVersion::VERSION_3_5,
  16111. PhpUnitTargetVersion::VERSION_5_0,
  16112. PhpUnitTargetVersion::VERSION_5_6,
  16113. PhpUnitTargetVersion::VERSION_NEWEST,
  16114. ])
  16115. ->setDefault(PhpUnitTargetVersion::VERSION_5_0)
  16116. ->getOption(),
  16117. ], $this->getName());
  16118. }
  16119. private function fixAssertTrueFalse(Tokens $tokens, array $assertCall)
  16120. {
  16121. $testDefaultNamespaceTokenIndex = false;
  16122. $testIndex = $tokens->getNextMeaningfulToken($assertCall['openBraceIndex']);
  16123. if (!$tokens[$testIndex]->isGivenKind([T_EMPTY, T_STRING])) {
  16124. if (!$tokens[$testIndex]->isGivenKind(T_NS_SEPARATOR)) {
  16125. return;
  16126. }
  16127. $testDefaultNamespaceTokenIndex = $testIndex;
  16128. $testIndex = $tokens->getNextMeaningfulToken($testIndex);
  16129. }
  16130. $testOpenIndex = $tokens->getNextMeaningfulToken($testIndex);
  16131. if (!$tokens[$testOpenIndex]->equals('(')) {
  16132. return;
  16133. }
  16134. $testCloseIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $testOpenIndex);
  16135. $assertCallCloseIndex = $tokens->getNextMeaningfulToken($testCloseIndex);
  16136. if (!$tokens[$assertCallCloseIndex]->equalsAny([')', ','])) {
  16137. return;
  16138. }
  16139. $isPositive = 'asserttrue' === $assertCall['loweredName'];
  16140. $content = strtolower($tokens[$testIndex]->getContent());
  16141. if (!\in_array($content, $this->functions, true)) {
  16142. return;
  16143. }
  16144. if (\is_array(self::$fixMap[$content])) {
  16145. if (false !== self::$fixMap[$content][$isPositive]) {
  16146. $tokens[$assertCall['index']] = new Token([T_STRING, self::$fixMap[$content][$isPositive]]);
  16147. $this->removeFunctionCall($tokens, $testDefaultNamespaceTokenIndex, $testIndex, $testOpenIndex, $testCloseIndex);
  16148. }
  16149. return;
  16150. }
  16151. $type = substr($content, 3);
  16152. $tokens[$assertCall['index']] = new Token([T_STRING, $isPositive ? 'assertInternalType' : 'assertNotInternalType']);
  16153. $tokens[$testIndex] = new Token([T_CONSTANT_ENCAPSED_STRING, "'".$type."'"]);
  16154. $tokens[$testOpenIndex] = new Token(',');
  16155. $tokens->clearTokenAndMergeSurroundingWhitespace($testCloseIndex);
  16156. $commaIndex = $tokens->getPrevMeaningfulToken($testCloseIndex);
  16157. if ($tokens[$commaIndex]->equals(',')) {
  16158. $tokens->removeTrailingWhitespace($commaIndex);
  16159. $tokens->clearAt($commaIndex);
  16160. }
  16161. if (!$tokens[$testOpenIndex + 1]->isWhitespace()) {
  16162. $tokens->insertAt($testOpenIndex + 1, new Token([T_WHITESPACE, ' ']));
  16163. }
  16164. if (false !== $testDefaultNamespaceTokenIndex) {
  16165. $tokens->clearTokenAndMergeSurroundingWhitespace($testDefaultNamespaceTokenIndex);
  16166. }
  16167. }
  16168. private function fixAssertSameEquals(Tokens $tokens, array $assertCall)
  16169. {
  16170. $expectedIndex = $tokens->getNextMeaningfulToken($assertCall['openBraceIndex']);
  16171. if (!$tokens[$expectedIndex]->isGivenKind(T_LNUMBER)) {
  16172. return;
  16173. }
  16174. $commaIndex = $tokens->getNextMeaningfulToken($expectedIndex);
  16175. if (!$tokens[$commaIndex]->equals(',')) {
  16176. return;
  16177. }
  16178. $countCallIndex = $tokens->getNextMeaningfulToken($commaIndex);
  16179. if ($tokens[$countCallIndex]->isGivenKind(T_NS_SEPARATOR)) {
  16180. $defaultNamespaceTokenIndex = $countCallIndex;
  16181. $countCallIndex = $tokens->getNextMeaningfulToken($countCallIndex);
  16182. } else {
  16183. $defaultNamespaceTokenIndex = false;
  16184. }
  16185. if (!$tokens[$countCallIndex]->isGivenKind(T_STRING)) {
  16186. return;
  16187. }
  16188. $lowerContent = strtolower($tokens[$countCallIndex]->getContent());
  16189. if ('count' !== $lowerContent && 'sizeof' !== $lowerContent) {
  16190. return;
  16191. }
  16192. $countCallOpenBraceIndex = $tokens->getNextMeaningfulToken($countCallIndex);
  16193. if (!$tokens[$countCallOpenBraceIndex]->equals('(')) {
  16194. return;
  16195. }
  16196. $countCallCloseBraceIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $countCallOpenBraceIndex);
  16197. $afterCountCallCloseBraceIndex = $tokens->getNextMeaningfulToken($countCallCloseBraceIndex);
  16198. if (!$tokens[$afterCountCallCloseBraceIndex]->equalsAny([')', ','])) {
  16199. return;
  16200. }
  16201. $this->removeFunctionCall(
  16202. $tokens,
  16203. $defaultNamespaceTokenIndex,
  16204. $countCallIndex,
  16205. $countCallOpenBraceIndex,
  16206. $countCallCloseBraceIndex
  16207. );
  16208. $tokens[$assertCall['index']] = new Token([
  16209. T_STRING,
  16210. false === strpos($assertCall['loweredName'], 'not', 6) ? 'assertCount' : 'assertNotCount',
  16211. ]);
  16212. }
  16213. private function getPreviousAssertCall(Tokens $tokens)
  16214. {
  16215. $functionsAnalyzer = new FunctionsAnalyzer();
  16216. for ($index = $tokens->count(); $index > 0; --$index) {
  16217. $index = $tokens->getPrevTokenOfKind($index, [[T_STRING]]);
  16218. if (null === $index) {
  16219. return;
  16220. }
  16221. $loweredContent = strtolower($tokens[$index]->getContent());
  16222. if ('assert' !== substr($loweredContent, 0, 6)) {
  16223. continue;
  16224. }
  16225. $openBraceIndex = $tokens->getNextMeaningfulToken($index);
  16226. if (!$tokens[$openBraceIndex]->equals('(')) {
  16227. continue;
  16228. }
  16229. if (!$functionsAnalyzer->isTheSameClassCall($tokens, $index)) {
  16230. continue;
  16231. }
  16232. yield [
  16233. 'index' => $index,
  16234. 'loweredName' => $loweredContent,
  16235. 'openBraceIndex' => $openBraceIndex,
  16236. 'closeBraceIndex' => $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $openBraceIndex),
  16237. ];
  16238. }
  16239. }
  16240. private function removeFunctionCall(Tokens $tokens, $callNSIndex, $callIndex, $openIndex, $closeIndex)
  16241. {
  16242. $tokens->clearTokenAndMergeSurroundingWhitespace($callIndex);
  16243. if (false !== $callNSIndex) {
  16244. $tokens->clearTokenAndMergeSurroundingWhitespace($callNSIndex);
  16245. }
  16246. $tokens->clearTokenAndMergeSurroundingWhitespace($openIndex);
  16247. $commaIndex = $tokens->getPrevMeaningfulToken($closeIndex);
  16248. if ($tokens[$commaIndex]->equals(',')) {
  16249. $tokens->removeTrailingWhitespace($commaIndex);
  16250. $tokens->clearAt($commaIndex);
  16251. }
  16252. $tokens->clearTokenAndMergeSurroundingWhitespace($closeIndex);
  16253. }
  16254. }
  16255. <?php
  16256. namespace PhpCsFixer\Fixer\PhpUnit;
  16257. use PhpCsFixer\AbstractFixer;
  16258. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  16259. use PhpCsFixer\FixerConfiguration\AllowedValueSubset;
  16260. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverRootless;
  16261. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  16262. use PhpCsFixer\FixerDefinition\CodeSample;
  16263. use PhpCsFixer\FixerDefinition\FixerDefinition;
  16264. use PhpCsFixer\Tokenizer\Analyzer\ArgumentsAnalyzer;
  16265. use PhpCsFixer\Tokenizer\Analyzer\FunctionsAnalyzer;
  16266. use PhpCsFixer\Tokenizer\Token;
  16267. use PhpCsFixer\Tokenizer\Tokens;
  16268. final class PhpUnitStrictFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface
  16269. {
  16270. private static $assertionMap = [
  16271. 'assertAttributeEquals' => 'assertAttributeSame',
  16272. 'assertAttributeNotEquals' => 'assertAttributeNotSame',
  16273. 'assertEquals' => 'assertSame',
  16274. 'assertNotEquals' => 'assertNotSame',
  16275. ];
  16276. public function getDefinition()
  16277. {
  16278. return new FixerDefinition(
  16279. 'PHPUnit methods like `assertSame` should be used instead of `assertEquals`.',
  16280. [
  16281. new CodeSample(
  16282. '<?php
  16283. final class MyTest extends \PHPUnit_Framework_TestCase
  16284. {
  16285. public function testSomeTest()
  16286. {
  16287. $this->assertAttributeEquals(a(), b());
  16288. $this->assertAttributeNotEquals(a(), b());
  16289. $this->assertEquals(a(), b());
  16290. $this->assertNotEquals(a(), b());
  16291. }
  16292. }
  16293. '
  16294. ),
  16295. new CodeSample(
  16296. '<?php
  16297. final class MyTest extends \PHPUnit_Framework_TestCase
  16298. {
  16299. public function testSomeTest()
  16300. {
  16301. $this->assertAttributeEquals(a(), b());
  16302. $this->assertAttributeNotEquals(a(), b());
  16303. $this->assertEquals(a(), b());
  16304. $this->assertNotEquals(a(), b());
  16305. }
  16306. }
  16307. ',
  16308. ['assertions' => ['assertEquals']]
  16309. ),
  16310. ],
  16311. null,
  16312. 'Risky when any of the functions are overridden or when testing object equality.'
  16313. );
  16314. }
  16315. public function isCandidate(Tokens $tokens)
  16316. {
  16317. return $tokens->isTokenKindFound(T_STRING);
  16318. }
  16319. public function isRisky()
  16320. {
  16321. return true;
  16322. }
  16323. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  16324. {
  16325. $argumentsAnalyzer = new ArgumentsAnalyzer();
  16326. $functionsAnalyzer = new FunctionsAnalyzer();
  16327. foreach ($this->configuration['assertions'] as $methodBefore) {
  16328. $methodAfter = self::$assertionMap[$methodBefore];
  16329. for ($index = 0, $limit = $tokens->count(); $index < $limit; ++$index) {
  16330. $methodIndex = $tokens->getNextTokenOfKind($index, [[T_STRING, $methodBefore]]);
  16331. if (null === $methodIndex) {
  16332. break;
  16333. }
  16334. if (!$functionsAnalyzer->isTheSameClassCall($tokens, $methodIndex)) {
  16335. continue;
  16336. }
  16337. $openingParenthesisIndex = $tokens->getNextMeaningfulToken($methodIndex);
  16338. $argumentsCount = $argumentsAnalyzer->countArguments(
  16339. $tokens,
  16340. $openingParenthesisIndex,
  16341. $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $openingParenthesisIndex)
  16342. );
  16343. if (2 === $argumentsCount || 3 === $argumentsCount) {
  16344. $tokens[$methodIndex] = new Token([T_STRING, $methodAfter]);
  16345. }
  16346. $index = $methodIndex;
  16347. }
  16348. }
  16349. }
  16350. protected function createConfigurationDefinition()
  16351. {
  16352. return new FixerConfigurationResolverRootless('assertions', [
  16353. (new FixerOptionBuilder('assertions', 'List of assertion methods to fix.'))
  16354. ->setAllowedTypes(['array'])
  16355. ->setAllowedValues([new AllowedValueSubset(array_keys(self::$assertionMap))])
  16356. ->setDefault([
  16357. 'assertAttributeEquals',
  16358. 'assertAttributeNotEquals',
  16359. 'assertEquals',
  16360. 'assertNotEquals',
  16361. ])
  16362. ->getOption(),
  16363. ], $this->getName());
  16364. }
  16365. }
  16366. <?php
  16367. namespace PhpCsFixer\Fixer\PhpUnit;
  16368. use PhpCsFixer\AbstractFixer;
  16369. use PhpCsFixer\DocBlock\DocBlock;
  16370. use PhpCsFixer\DocBlock\Line;
  16371. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  16372. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  16373. use PhpCsFixer\FixerConfiguration\AllowedValueSubset;
  16374. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  16375. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  16376. use PhpCsFixer\FixerDefinition\CodeSample;
  16377. use PhpCsFixer\FixerDefinition\FixerDefinition;
  16378. use PhpCsFixer\Indicator\PhpUnitTestCaseIndicator;
  16379. use PhpCsFixer\Tokenizer\Token;
  16380. use PhpCsFixer\Tokenizer\Tokens;
  16381. final class PhpUnitInternalClassFixer extends AbstractFixer implements WhitespacesAwareFixerInterface, ConfigurationDefinitionFixerInterface
  16382. {
  16383. public function getDefinition()
  16384. {
  16385. return new FixerDefinition(
  16386. 'All PHPUnit test classes should be marked as internal.',
  16387. [
  16388. new CodeSample("<?php\nclass MyTest extends TestCase {}\n"),
  16389. new CodeSample(
  16390. "<?php\nclass MyTest extends TestCase {}\nfinal class FinalTest extends TestCase {}\nabstract class AbstractTest extends TestCase {}\n",
  16391. ['types' => ['final']]
  16392. ),
  16393. ]
  16394. );
  16395. }
  16396. public function getPriority()
  16397. {
  16398. return 68;
  16399. }
  16400. public function isCandidate(Tokens $tokens)
  16401. {
  16402. return $tokens->isTokenKindFound(T_CLASS);
  16403. }
  16404. protected function createConfigurationDefinition()
  16405. {
  16406. $types = ['normal', 'final', 'abstract'];
  16407. return new FixerConfigurationResolver([
  16408. (new FixerOptionBuilder('types', 'What types of classes to mark as internal'))
  16409. ->setAllowedValues([(new AllowedValueSubset($types))])
  16410. ->setAllowedTypes(['array'])
  16411. ->setDefault(['normal', 'final'])
  16412. ->getOption(),
  16413. ]);
  16414. }
  16415. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  16416. {
  16417. $phpUnitTestCaseIndicator = new PhpUnitTestCaseIndicator();
  16418. foreach ($phpUnitTestCaseIndicator->findPhpUnitClasses($tokens, true) as $indexes) {
  16419. $this->markClassInternal($tokens, $indexes[0]);
  16420. }
  16421. }
  16422. private function markClassInternal(Tokens $tokens, $startIndex)
  16423. {
  16424. $classIndex = $tokens->getPrevTokenOfKind($startIndex, [[T_CLASS]]);
  16425. if (!$this->isAllowedByConfiguration($tokens, $classIndex)) {
  16426. return;
  16427. }
  16428. $docBlockIndex = $this->getDocBlockIndex($tokens, $classIndex);
  16429. if ($this->hasDocBlock($tokens, $classIndex)) {
  16430. $this->updateDocBlockIfNeeded($tokens, $docBlockIndex);
  16431. return;
  16432. }
  16433. $this->createDocBlock($tokens, $docBlockIndex);
  16434. }
  16435. private function isAllowedByConfiguration(Tokens $tokens, $i)
  16436. {
  16437. $typeIndex = $tokens->getPrevMeaningfulToken($i);
  16438. if ($tokens[$typeIndex]->isGivenKind(T_FINAL)) {
  16439. return \in_array('final', $this->configuration['types'], true);
  16440. }
  16441. if ($tokens[$typeIndex]->isGivenKind(T_ABSTRACT)) {
  16442. return \in_array('abstract', $this->configuration['types'], true);
  16443. }
  16444. return \in_array('normal', $this->configuration['types'], true);
  16445. }
  16446. private function createDocBlock(Tokens $tokens, $docBlockIndex)
  16447. {
  16448. $lineEnd = $this->whitespacesConfig->getLineEnding();
  16449. $originalIndent = $this->detectIndent($tokens, $tokens->getNextNonWhitespace($docBlockIndex));
  16450. $toInsert = [
  16451. new Token([T_DOC_COMMENT, '/**'.$lineEnd."{$originalIndent} * @internal".$lineEnd."{$originalIndent} */"]),
  16452. new Token([T_WHITESPACE, $lineEnd.$originalIndent]),
  16453. ];
  16454. $index = $tokens->getNextMeaningfulToken($docBlockIndex);
  16455. $tokens->insertAt($index, $toInsert);
  16456. }
  16457. private function updateDocBlockIfNeeded(Tokens $tokens, $docBlockIndex)
  16458. {
  16459. $doc = new DocBlock($tokens[$docBlockIndex]->getContent());
  16460. if (!empty($doc->getAnnotationsOfType('internal'))) {
  16461. return;
  16462. }
  16463. $doc = $this->makeDocBlockMultiLineIfNeeded($doc, $tokens, $docBlockIndex);
  16464. $lines = $this->addInternalAnnotation($doc, $tokens, $docBlockIndex);
  16465. $lines = implode('', $lines);
  16466. $tokens[$docBlockIndex] = new Token([T_DOC_COMMENT, $lines]);
  16467. }
  16468. private function hasDocBlock(Tokens $tokens, $index)
  16469. {
  16470. $docBlockIndex = $this->getDocBlockIndex($tokens, $index);
  16471. return $tokens[$docBlockIndex]->isGivenKind(T_DOC_COMMENT);
  16472. }
  16473. private function getDocBlockIndex(Tokens $tokens, $index)
  16474. {
  16475. do {
  16476. $index = $tokens->getPrevNonWhitespace($index);
  16477. } while ($tokens[$index]->isGivenKind([T_PUBLIC, T_PROTECTED, T_PRIVATE, T_FINAL, T_ABSTRACT, T_COMMENT]));
  16478. return $index;
  16479. }
  16480. private function detectIndent(Tokens $tokens, $index)
  16481. {
  16482. if (!$tokens[$index - 1]->isWhitespace()) {
  16483. return '';
  16484. }
  16485. $explodedContent = explode($this->whitespacesConfig->getLineEnding(), $tokens[$index - 1]->getContent());
  16486. return end($explodedContent);
  16487. }
  16488. private function addInternalAnnotation(DocBlock $docBlock, Tokens $tokens, $docBlockIndex)
  16489. {
  16490. $lines = $docBlock->getLines();
  16491. $originalIndent = $this->detectIndent($tokens, $docBlockIndex);
  16492. $lineEnd = $this->whitespacesConfig->getLineEnding();
  16493. array_splice($lines, -1, 0, $originalIndent.' *'.$lineEnd.$originalIndent.' * @internal'.$lineEnd);
  16494. return $lines;
  16495. }
  16496. private function makeDocBlockMultiLineIfNeeded(DocBlock $doc, Tokens $tokens, $docBlockIndex)
  16497. {
  16498. $lines = $doc->getLines();
  16499. if (1 === \count($lines) && empty($doc->getAnnotationsOfType('internal'))) {
  16500. $indent = $this->detectIndent($tokens, $tokens->getNextNonWhitespace($docBlockIndex));
  16501. $doc->makeMultiLine($indent, $this->whitespacesConfig->getLineEnding());
  16502. return $doc;
  16503. }
  16504. return $doc;
  16505. }
  16506. }
  16507. <?php
  16508. namespace PhpCsFixer\Fixer;
  16509. use PhpCsFixer\Tokenizer\Tokens;
  16510. /**
  16511. @symfony
  16512. */
  16513. interface FixerInterface
  16514. {
  16515. public function isCandidate(Tokens $tokens);
  16516. public function isRisky();
  16517. public function fix(\SplFileInfo $file, Tokens $tokens);
  16518. public function getName();
  16519. public function getPriority();
  16520. public function supports(\SplFileInfo $file);
  16521. }
  16522. <?php
  16523. namespace PhpCsFixer\Fixer;
  16524. use PhpCsFixer\ConfigurationException\InvalidFixerConfigurationException;
  16525. interface ConfigurableFixerInterface extends FixerInterface
  16526. {
  16527. public function configure(array $configuration = null);
  16528. }
  16529. <?php
  16530. namespace PhpCsFixer\Fixer\LanguageConstruct;
  16531. use PhpCsFixer\AbstractFixer;
  16532. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  16533. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  16534. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  16535. use PhpCsFixer\FixerDefinition\CodeSample;
  16536. use PhpCsFixer\FixerDefinition\FixerDefinition;
  16537. use PhpCsFixer\Tokenizer\Token;
  16538. use PhpCsFixer\Tokenizer\Tokens;
  16539. final class DeclareEqualNormalizeFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface
  16540. {
  16541. private $callback;
  16542. public function configure(array $configuration = null)
  16543. {
  16544. parent::configure($configuration);
  16545. $this->callback = 'none' === $this->configuration['space'] ? 'removeWhitespaceAroundToken' : 'ensureWhitespaceAroundToken';
  16546. }
  16547. public function getDefinition()
  16548. {
  16549. return new FixerDefinition(
  16550. 'Equal sign in declare statement should be surrounded by spaces or not following configuration.',
  16551. [
  16552. new CodeSample("<?php\ndeclare(ticks = 1);\n"),
  16553. new CodeSample("<?php\ndeclare(ticks=1);\n", ['space' => 'single']),
  16554. ]
  16555. );
  16556. }
  16557. public function getPriority()
  16558. {
  16559. return 0;
  16560. }
  16561. public function isCandidate(Tokens $tokens)
  16562. {
  16563. return $tokens->isTokenKindFound(T_DECLARE);
  16564. }
  16565. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  16566. {
  16567. $callback = $this->callback;
  16568. for ($index = 0, $count = $tokens->count(); $index < $count - 6; ++$index) {
  16569. if (!$tokens[$index]->isGivenKind(T_DECLARE)) {
  16570. continue;
  16571. }
  16572. while (!$tokens[++$index]->equals('='));
  16573. $this->{$callback}($tokens, $index);
  16574. }
  16575. }
  16576. protected function createConfigurationDefinition()
  16577. {
  16578. return new FixerConfigurationResolver([
  16579. (new FixerOptionBuilder('space', 'Spacing to apply around the equal sign.'))
  16580. ->setAllowedValues(['single', 'none'])
  16581. ->setDefault('none')
  16582. ->getOption(),
  16583. ]);
  16584. }
  16585. private function ensureWhitespaceAroundToken(Tokens $tokens, $index)
  16586. {
  16587. if ($tokens[$index + 1]->isWhitespace()) {
  16588. if (' ' !== $tokens[$index + 1]->getContent()) {
  16589. $tokens[$index + 1] = new Token([T_WHITESPACE, ' ']);
  16590. }
  16591. } else {
  16592. $tokens->insertAt($index + 1, new Token([T_WHITESPACE, ' ']));
  16593. }
  16594. if ($tokens[$index - 1]->isWhitespace()) {
  16595. if (' ' !== $tokens[$index - 1]->getContent() && !$tokens[$tokens->getPrevNonWhitespace($index - 1)]->isComment()) {
  16596. $tokens[$index - 1] = new Token([T_WHITESPACE, ' ']);
  16597. }
  16598. } else {
  16599. $tokens->insertAt($index, new Token([T_WHITESPACE, ' ']));
  16600. }
  16601. }
  16602. private function removeWhitespaceAroundToken(Tokens $tokens, $index)
  16603. {
  16604. if (!$tokens[$tokens->getPrevNonWhitespace($index)]->isComment()) {
  16605. $tokens->removeLeadingWhitespace($index);
  16606. }
  16607. $tokens->removeTrailingWhitespace($index);
  16608. }
  16609. }
  16610. <?php
  16611. namespace PhpCsFixer\Fixer\LanguageConstruct;
  16612. use PhpCsFixer\AbstractFixer;
  16613. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  16614. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  16615. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  16616. use PhpCsFixer\FixerDefinition\CodeSample;
  16617. use PhpCsFixer\FixerDefinition\FixerDefinition;
  16618. use PhpCsFixer\Tokenizer\Analyzer\FunctionsAnalyzer;
  16619. use PhpCsFixer\Tokenizer\Token;
  16620. use PhpCsFixer\Tokenizer\Tokens;
  16621. final class IsNullFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface
  16622. {
  16623. public function getDefinition()
  16624. {
  16625. return new FixerDefinition(
  16626. 'Replaces `is_null($var)` expression with `null === $var`.',
  16627. [
  16628. new CodeSample("<?php\n\$a = is_null(\$b);\n"),
  16629. ],
  16630. null,
  16631. 'Risky when the function `is_null` is overridden.'
  16632. );
  16633. }
  16634. public function getPriority()
  16635. {
  16636. return 1;
  16637. }
  16638. public function isCandidate(Tokens $tokens)
  16639. {
  16640. return $tokens->isTokenKindFound(T_STRING);
  16641. }
  16642. public function isRisky()
  16643. {
  16644. return true;
  16645. }
  16646. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  16647. {
  16648. static $sequenceNeeded = [[T_STRING, 'is_null'], '('];
  16649. $functionsAnalyzer = new FunctionsAnalyzer();
  16650. $currIndex = 0;
  16651. while (null !== $currIndex) {
  16652. $matches = $tokens->findSequence($sequenceNeeded, $currIndex, $tokens->count() - 1, false);
  16653. if (null === $matches) {
  16654. break;
  16655. }
  16656. $matches = array_keys($matches);
  16657. list($isNullIndex, $currIndex) = $matches;
  16658. if (!$functionsAnalyzer->isGlobalFunctionCall($tokens, $matches[0])) {
  16659. continue;
  16660. }
  16661. $next = $tokens->getNextMeaningfulToken($currIndex);
  16662. if ($tokens[$next]->equals(')')) {
  16663. continue;
  16664. }
  16665. $prevTokenIndex = $tokens->getPrevMeaningfulToken($matches[0]);
  16666. if ($tokens[$prevTokenIndex]->isGivenKind(T_NS_SEPARATOR)) {
  16667. $tokens->removeTrailingWhitespace($prevTokenIndex);
  16668. $tokens->clearAt($prevTokenIndex);
  16669. $prevTokenIndex = $tokens->getPrevMeaningfulToken($prevTokenIndex);
  16670. }
  16671. $isInvertedNullCheck = false;
  16672. if ($tokens[$prevTokenIndex]->equals('!')) {
  16673. $isInvertedNullCheck = true;
  16674. $tokens->removeTrailingWhitespace($prevTokenIndex);
  16675. $tokens->clearAt($prevTokenIndex);
  16676. }
  16677. $referenceEnd = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $matches[1]);
  16678. $isContainingDangerousConstructs = false;
  16679. for ($paramTokenIndex = $matches[1]; $paramTokenIndex <= $referenceEnd; ++$paramTokenIndex) {
  16680. if (\in_array($tokens[$paramTokenIndex]->getContent(), ['?', '?:', '=', '??'], true)) {
  16681. $isContainingDangerousConstructs = true;
  16682. break;
  16683. }
  16684. }
  16685. $parentLeftToken = $tokens[$tokens->getPrevMeaningfulToken($isNullIndex)];
  16686. $parentRightToken = $tokens[$tokens->getNextMeaningfulToken($referenceEnd)];
  16687. $parentOperations = [T_IS_EQUAL, T_IS_NOT_EQUAL, T_IS_IDENTICAL, T_IS_NOT_IDENTICAL];
  16688. $wrapIntoParentheses = $parentLeftToken->isGivenKind($parentOperations) || $parentRightToken->isGivenKind($parentOperations);
  16689. $prevIndex = $tokens->getPrevMeaningfulToken($referenceEnd);
  16690. if ($tokens[$prevIndex]->equals(',')) {
  16691. $tokens->clearTokenAndMergeSurroundingWhitespace($prevIndex);
  16692. }
  16693. if (!$isContainingDangerousConstructs) {
  16694. $tokens->removeLeadingWhitespace($referenceEnd);
  16695. $tokens->clearAt($referenceEnd);
  16696. $tokens->removeLeadingWhitespace($matches[1]);
  16697. $tokens->removeTrailingWhitespace($matches[1]);
  16698. $tokens->clearAt($matches[1]);
  16699. }
  16700. $replacement = [
  16701. new Token([T_STRING, 'null']),
  16702. new Token([T_WHITESPACE, ' ']),
  16703. new Token($isInvertedNullCheck ? [T_IS_NOT_IDENTICAL, '!=='] : [T_IS_IDENTICAL, '===']),
  16704. new Token([T_WHITESPACE, ' ']),
  16705. ];
  16706. if (true === $this->configuration['use_yoda_style']) {
  16707. if ($wrapIntoParentheses) {
  16708. array_unshift($replacement, new Token('('));
  16709. $tokens->insertAt($referenceEnd + 1, new Token(')'));
  16710. }
  16711. $tokens->overrideRange($isNullIndex, $isNullIndex, $replacement);
  16712. } else {
  16713. $replacement = array_reverse($replacement);
  16714. if ($wrapIntoParentheses) {
  16715. $replacement[] = new Token(')');
  16716. $tokens[$isNullIndex] = new Token('(');
  16717. } else {
  16718. $tokens->clearAt($isNullIndex);
  16719. }
  16720. $tokens->insertAt($referenceEnd + 1, $replacement);
  16721. }
  16722. $currIndex = $isNullIndex;
  16723. }
  16724. }
  16725. protected function createConfigurationDefinition()
  16726. {
  16727. return new FixerConfigurationResolver([
  16728. (new FixerOptionBuilder('use_yoda_style', 'Whether Yoda style conditions should be used.'))
  16729. ->setAllowedTypes(['bool'])
  16730. ->setDefault(true)
  16731. ->setDeprecationMessage('Use `yoda_style` fixer instead.')
  16732. ->getOption(),
  16733. ]);
  16734. }
  16735. }
  16736. <?php
  16737. namespace PhpCsFixer\Fixer\LanguageConstruct;
  16738. use PhpCsFixer\AbstractFixer;
  16739. use PhpCsFixer\FixerDefinition\CodeSample;
  16740. use PhpCsFixer\FixerDefinition\FixerDefinition;
  16741. use PhpCsFixer\Tokenizer\Analyzer\NamespacesAnalyzer;
  16742. use PhpCsFixer\Tokenizer\CT;
  16743. use PhpCsFixer\Tokenizer\Token;
  16744. use PhpCsFixer\Tokenizer\Tokens;
  16745. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  16746. final class ClassKeywordRemoveFixer extends AbstractFixer
  16747. {
  16748. private $imports = [];
  16749. public function getDefinition()
  16750. {
  16751. return new FixerDefinition(
  16752. 'Converts `::class` keywords to FQCN strings.',
  16753. [
  16754. new CodeSample(
  16755. '<?php
  16756. use Foo\Bar\Baz;
  16757. $className = Baz::class;
  16758. '
  16759. ),
  16760. ]
  16761. );
  16762. }
  16763. public function getPriority()
  16764. {
  16765. return 0;
  16766. }
  16767. public function isCandidate(Tokens $tokens)
  16768. {
  16769. return $tokens->isTokenKindFound(CT::T_CLASS_CONSTANT);
  16770. }
  16771. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  16772. {
  16773. $namespacesAnalyzer = new NamespacesAnalyzer();
  16774. $previousNamespaceScopeEndIndex = 0;
  16775. foreach ($namespacesAnalyzer->getDeclarations($tokens) as $declaration) {
  16776. $this->replaceClassKeywordsSection($tokens, '', $previousNamespaceScopeEndIndex, $declaration->getStartIndex());
  16777. $this->replaceClassKeywordsSection($tokens, $declaration->getFullName(), $declaration->getStartIndex(), $declaration->getScopeEndIndex());
  16778. $previousNamespaceScopeEndIndex = $declaration->getScopeEndIndex();
  16779. }
  16780. $this->replaceClassKeywordsSection($tokens, '', $previousNamespaceScopeEndIndex, $tokens->count() - 1);
  16781. }
  16782. private function storeImports(Tokens $tokens, $startIndex, $endIndex)
  16783. {
  16784. $tokensAnalyzer = new TokensAnalyzer($tokens);
  16785. $this->imports = [];
  16786. foreach ($tokensAnalyzer->getImportUseIndexes() as $index) {
  16787. if ($index < $startIndex || $index > $endIndex) {
  16788. continue;
  16789. }
  16790. $import = '';
  16791. while ($index = $tokens->getNextMeaningfulToken($index)) {
  16792. if ($tokens[$index]->equalsAny([';', [CT::T_GROUP_IMPORT_BRACE_OPEN]]) || $tokens[$index]->isGivenKind(T_AS)) {
  16793. break;
  16794. }
  16795. $import .= $tokens[$index]->getContent();
  16796. }
  16797. if ($tokens[$index]->isGivenKind(CT::T_GROUP_IMPORT_BRACE_OPEN)) {
  16798. $groupEndIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_GROUP_IMPORT_BRACE, $index);
  16799. $groupImports = array_map(
  16800. static function ($import) {
  16801. return trim($import);
  16802. },
  16803. explode(',', $tokens->generatePartialCode($index + 1, $groupEndIndex - 1))
  16804. );
  16805. foreach ($groupImports as $groupImport) {
  16806. $groupImportParts = array_map(static function ($import) {
  16807. return trim($import);
  16808. }, explode(' as ', $groupImport));
  16809. if (2 === \count($groupImportParts)) {
  16810. $this->imports[$groupImportParts[1]] = $import.$groupImportParts[0];
  16811. } else {
  16812. $this->imports[] = $import.$groupImport;
  16813. }
  16814. }
  16815. } elseif ($tokens[$index]->isGivenKind(T_AS)) {
  16816. $aliasIndex = $tokens->getNextMeaningfulToken($index);
  16817. $alias = $tokens[$aliasIndex]->getContent();
  16818. $this->imports[$alias] = $import;
  16819. } else {
  16820. $this->imports[] = $import;
  16821. }
  16822. }
  16823. }
  16824. private function replaceClassKeywordsSection(Tokens $tokens, $namespace, $startIndex, $endIndex)
  16825. {
  16826. if ($endIndex - $startIndex < 3) {
  16827. return;
  16828. }
  16829. $this->storeImports($tokens, $startIndex, $endIndex);
  16830. $ctClassTokens = $tokens->findGivenKind(CT::T_CLASS_CONSTANT, $startIndex, $endIndex);
  16831. foreach (array_reverse(array_keys($ctClassTokens)) as $classIndex) {
  16832. $this->replaceClassKeyword($tokens, $namespace, $classIndex);
  16833. }
  16834. }
  16835. private function replaceClassKeyword(Tokens $tokens, $namespace, $classIndex)
  16836. {
  16837. $classEndIndex = $tokens->getPrevMeaningfulToken($classIndex);
  16838. $classEndIndex = $tokens->getPrevMeaningfulToken($classEndIndex);
  16839. if ($tokens[$classEndIndex]->equalsAny([[T_STRING, 'self'], [T_STATIC, 'static'], [T_STRING, 'parent']], false)) {
  16840. return;
  16841. }
  16842. $classBeginIndex = $classEndIndex;
  16843. while (true) {
  16844. $prev = $tokens->getPrevMeaningfulToken($classBeginIndex);
  16845. if (!$tokens[$prev]->isGivenKind([T_NS_SEPARATOR, T_STRING])) {
  16846. break;
  16847. }
  16848. $classBeginIndex = $prev;
  16849. }
  16850. $classString = $tokens->generatePartialCode(
  16851. $tokens[$classBeginIndex]->isGivenKind(T_NS_SEPARATOR)
  16852. ? $tokens->getNextMeaningfulToken($classBeginIndex)
  16853. : $classBeginIndex,
  16854. $classEndIndex
  16855. );
  16856. $classImport = false;
  16857. foreach ($this->imports as $alias => $import) {
  16858. if ($classString === $alias) {
  16859. $classImport = $import;
  16860. break;
  16861. }
  16862. $classStringArray = explode('\\', $classString);
  16863. $namespaceToTest = $classStringArray[0];
  16864. if (0 === strcmp($namespaceToTest, substr($import, -\strlen($namespaceToTest)))) {
  16865. $classImport = $import;
  16866. break;
  16867. }
  16868. }
  16869. for ($i = $classBeginIndex; $i <= $classIndex; ++$i) {
  16870. if (!$tokens[$i]->isComment() && !($tokens[$i]->isWhitespace() && false !== strpos($tokens[$i]->getContent(), "\n"))) {
  16871. $tokens->clearAt($i);
  16872. }
  16873. }
  16874. $tokens->insertAt($classBeginIndex, new Token([
  16875. T_CONSTANT_ENCAPSED_STRING,
  16876. "'".$this->makeClassFQN($namespace, $classImport, $classString)."'",
  16877. ]));
  16878. }
  16879. private function makeClassFQN($namespace, $classImport, $classString)
  16880. {
  16881. if (false === $classImport) {
  16882. return ('' !== $namespace ? ($namespace.'\\') : '').$classString;
  16883. }
  16884. $classStringArray = explode('\\', $classString);
  16885. $classStringLength = \count($classStringArray);
  16886. $classImportArray = explode('\\', $classImport);
  16887. $classImportLength = \count($classImportArray);
  16888. if (1 === $classStringLength) {
  16889. return $classImport;
  16890. }
  16891. return implode('\\', array_merge(
  16892. \array_slice($classImportArray, 0, $classImportLength - $classStringLength + 1),
  16893. $classStringArray
  16894. ));
  16895. }
  16896. }
  16897. <?php
  16898. namespace PhpCsFixer\Fixer\LanguageConstruct;
  16899. use PhpCsFixer\AbstractFixer;
  16900. use PhpCsFixer\FixerDefinition\CodeSample;
  16901. use PhpCsFixer\FixerDefinition\FixerDefinition;
  16902. use PhpCsFixer\Tokenizer\Analyzer\ArgumentsAnalyzer;
  16903. use PhpCsFixer\Tokenizer\Token;
  16904. use PhpCsFixer\Tokenizer\Tokens;
  16905. final class NoUnsetOnPropertyFixer extends AbstractFixer
  16906. {
  16907. public function getDefinition()
  16908. {
  16909. return new FixerDefinition(
  16910. 'Properties should be set to `null` instead of using `unset`.',
  16911. [new CodeSample("<?php\nunset(\$this->a);\n")],
  16912. null,
  16913. 'Changing variables to `null` instead of unsetting them will mean they still show up '.
  16914. 'when looping over class variables. With PHP 7.4, this rule might introduce `null` assignments to '.
  16915. 'property whose type declaration does not allow it.'
  16916. );
  16917. }
  16918. public function isRisky()
  16919. {
  16920. return true;
  16921. }
  16922. public function isCandidate(Tokens $tokens)
  16923. {
  16924. return $tokens->isTokenKindFound(T_UNSET)
  16925. && $tokens->isAnyTokenKindsFound([T_OBJECT_OPERATOR, T_PAAMAYIM_NEKUDOTAYIM]);
  16926. }
  16927. public function getPriority()
  16928. {
  16929. return 25;
  16930. }
  16931. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  16932. {
  16933. for ($index = $tokens->count() - 1; $index >= 0; --$index) {
  16934. if (!$tokens[$index]->isGivenKind(T_UNSET)) {
  16935. continue;
  16936. }
  16937. $unsetsInfo = $this->getUnsetsInfo($tokens, $index);
  16938. if (!$this->isAnyUnsetToTransform($unsetsInfo)) {
  16939. continue;
  16940. }
  16941. $isLastUnset = true;
  16942. foreach (array_reverse($unsetsInfo) as $unsetInfo) {
  16943. $this->updateTokens($tokens, $unsetInfo, $isLastUnset);
  16944. $isLastUnset = false;
  16945. }
  16946. }
  16947. }
  16948. private function getUnsetsInfo(Tokens $tokens, $index)
  16949. {
  16950. $argumentsAnalyzer = new ArgumentsAnalyzer();
  16951. $unsetStart = $tokens->getNextTokenOfKind($index, ['(']);
  16952. $unsetEnd = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $unsetStart);
  16953. $isFirst = true;
  16954. $unsets = [];
  16955. foreach ($argumentsAnalyzer->getArguments($tokens, $unsetStart, $unsetEnd) as $startIndex => $endIndex) {
  16956. $startIndex = $tokens->getNextMeaningfulToken($startIndex - 1);
  16957. $endIndex = $tokens->getPrevMeaningfulToken($endIndex + 1);
  16958. $unsets[] = [
  16959. 'startIndex' => $startIndex,
  16960. 'endIndex' => $endIndex,
  16961. 'isToTransform' => $this->isProperty($tokens, $startIndex, $endIndex),
  16962. 'isFirst' => $isFirst,
  16963. ];
  16964. $isFirst = false;
  16965. }
  16966. return $unsets;
  16967. }
  16968. private function isProperty(Tokens $tokens, $index, $endIndex)
  16969. {
  16970. if ($tokens[$index]->isGivenKind(T_VARIABLE)) {
  16971. $nextIndex = $tokens->getNextMeaningfulToken($index);
  16972. if (null === $nextIndex || !$tokens[$nextIndex]->isGivenKind(T_OBJECT_OPERATOR)) {
  16973. return false;
  16974. }
  16975. $nextIndex = $tokens->getNextMeaningfulToken($nextIndex);
  16976. $nextNextIndex = $tokens->getNextMeaningfulToken($nextIndex);
  16977. if (null !== $nextNextIndex && $nextNextIndex < $endIndex) {
  16978. return false;
  16979. }
  16980. return null !== $nextIndex && $tokens[$nextIndex]->isGivenKind(T_STRING);
  16981. }
  16982. if ($tokens[$index]->isGivenKind([T_NS_SEPARATOR, T_STRING])) {
  16983. $nextIndex = $tokens->getTokenNotOfKindSibling($index, 1, [[T_DOUBLE_COLON], [T_NS_SEPARATOR], [T_STRING]]);
  16984. $nextNextIndex = $tokens->getNextMeaningfulToken($nextIndex);
  16985. if (null !== $nextNextIndex && $nextNextIndex < $endIndex) {
  16986. return false;
  16987. }
  16988. return null !== $nextIndex && $tokens[$nextIndex]->isGivenKind(T_VARIABLE);
  16989. }
  16990. return false;
  16991. }
  16992. private function isAnyUnsetToTransform(array $unsetsInfo)
  16993. {
  16994. foreach ($unsetsInfo as $unsetInfo) {
  16995. if ($unsetInfo['isToTransform']) {
  16996. return true;
  16997. }
  16998. }
  16999. return false;
  17000. }
  17001. private function updateTokens(Tokens $tokens, array $unsetInfo, $isLastUnset)
  17002. {
  17003. if ($unsetInfo['isFirst'] && $unsetInfo['isToTransform']) {
  17004. $braceIndex = $tokens->getPrevTokenOfKind($unsetInfo['startIndex'], ['(']);
  17005. $unsetIndex = $tokens->getPrevTokenOfKind($braceIndex, [[T_UNSET]]);
  17006. $tokens->clearTokenAndMergeSurroundingWhitespace($braceIndex);
  17007. $tokens->clearTokenAndMergeSurroundingWhitespace($unsetIndex);
  17008. }
  17009. if ($isLastUnset && $unsetInfo['isToTransform']) {
  17010. $braceIndex = $tokens->getNextTokenOfKind($unsetInfo['endIndex'], [')']);
  17011. $previousIndex = $tokens->getPrevMeaningfulToken($braceIndex);
  17012. if ($tokens[$previousIndex]->equals(',')) {
  17013. $tokens->clearTokenAndMergeSurroundingWhitespace($previousIndex);
  17014. }
  17015. $tokens->clearTokenAndMergeSurroundingWhitespace($braceIndex);
  17016. }
  17017. if (!$isLastUnset) {
  17018. $commaIndex = $tokens->getNextTokenOfKind($unsetInfo['endIndex'], [',']);
  17019. $tokens[$commaIndex] = new Token(';');
  17020. }
  17021. if (!$unsetInfo['isToTransform'] && !$isLastUnset) {
  17022. $tokens->insertAt($unsetInfo['endIndex'] + 1, new Token(')'));
  17023. }
  17024. if (!$unsetInfo['isToTransform'] && !$unsetInfo['isFirst']) {
  17025. $tokens->insertAt(
  17026. $unsetInfo['startIndex'],
  17027. [
  17028. new Token([T_UNSET, 'unset']),
  17029. new Token('('),
  17030. ]
  17031. );
  17032. }
  17033. if ($unsetInfo['isToTransform']) {
  17034. $tokens->insertAt(
  17035. $unsetInfo['endIndex'] + 1,
  17036. [
  17037. new Token([T_WHITESPACE, ' ']),
  17038. new Token('='),
  17039. new Token([T_WHITESPACE, ' ']),
  17040. new Token([T_STRING, 'null']),
  17041. ]
  17042. );
  17043. }
  17044. }
  17045. }
  17046. <?php
  17047. namespace PhpCsFixer\Fixer\LanguageConstruct;
  17048. use PhpCsFixer\AbstractFixer;
  17049. use PhpCsFixer\FixerDefinition\FixerDefinition;
  17050. use PhpCsFixer\FixerDefinition\VersionSpecification;
  17051. use PhpCsFixer\FixerDefinition\VersionSpecificCodeSample;
  17052. use PhpCsFixer\Tokenizer\CT;
  17053. use PhpCsFixer\Tokenizer\Token;
  17054. use PhpCsFixer\Tokenizer\Tokens;
  17055. final class ExplicitIndirectVariableFixer extends AbstractFixer
  17056. {
  17057. public function getDefinition()
  17058. {
  17059. return new FixerDefinition(
  17060. 'Add curly braces to indirect variables to make them clear to understand. Requires PHP >= 7.0.',
  17061. [
  17062. new VersionSpecificCodeSample(
  17063. <<<'EOT'
  17064. <?php
  17065. echo $$foo;
  17066. echo $$foo['bar'];
  17067. echo $foo->$bar['baz'];
  17068. echo $foo->$callback($baz);
  17069. EOT
  17070. ,
  17071. new VersionSpecification(70000)
  17072. ),
  17073. ]
  17074. );
  17075. }
  17076. public function isCandidate(Tokens $tokens)
  17077. {
  17078. return \PHP_VERSION_ID >= 70000 && $tokens->isTokenKindFound(T_VARIABLE);
  17079. }
  17080. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  17081. {
  17082. for ($index = $tokens->count() - 1; $index > 1; --$index) {
  17083. $token = $tokens[$index];
  17084. if (!$token->isGivenKind(T_VARIABLE)) {
  17085. continue;
  17086. }
  17087. $prevIndex = $tokens->getPrevMeaningfulToken($index);
  17088. $prevToken = $tokens[$prevIndex];
  17089. if (!$prevToken->equals('$') && !$prevToken->isGivenKind(T_OBJECT_OPERATOR)) {
  17090. continue;
  17091. }
  17092. $openingBrace = CT::T_DYNAMIC_VAR_BRACE_OPEN;
  17093. $closingBrace = CT::T_DYNAMIC_VAR_BRACE_CLOSE;
  17094. if ($prevToken->isGivenKind(T_OBJECT_OPERATOR)) {
  17095. $openingBrace = CT::T_DYNAMIC_PROP_BRACE_OPEN;
  17096. $closingBrace = CT::T_DYNAMIC_PROP_BRACE_CLOSE;
  17097. }
  17098. $tokens->overrideRange($index, $index, [
  17099. new Token([$openingBrace, '{']),
  17100. new Token([T_VARIABLE, $token->getContent()]),
  17101. new Token([$closingBrace, '}']),
  17102. ]);
  17103. }
  17104. }
  17105. }
  17106. <?php
  17107. namespace PhpCsFixer\Fixer\LanguageConstruct;
  17108. use PhpCsFixer\AbstractFixer;
  17109. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  17110. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  17111. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  17112. use PhpCsFixer\FixerDefinition\CodeSample;
  17113. use PhpCsFixer\FixerDefinition\FixerDefinition;
  17114. use PhpCsFixer\Tokenizer\Analyzer\FunctionsAnalyzer;
  17115. use PhpCsFixer\Tokenizer\Token;
  17116. use PhpCsFixer\Tokenizer\Tokens;
  17117. /**
  17118. @gmail
  17119. */
  17120. final class ErrorSuppressionFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface
  17121. {
  17122. const OPTION_MUTE_DEPRECATION_ERROR = 'mute_deprecation_error';
  17123. const OPTION_NOISE_REMAINING_USAGES = 'noise_remaining_usages';
  17124. const OPTION_NOISE_REMAINING_USAGES_EXCLUDE = 'noise_remaining_usages_exclude';
  17125. public function getDefinition()
  17126. {
  17127. return new FixerDefinition(
  17128. 'Error control operator should be added to deprecation notices and/or removed from other cases.',
  17129. [
  17130. new CodeSample("<?php\ntrigger_error('Warning.', E_USER_DEPRECATED);\n"),
  17131. new CodeSample(
  17132. "<?php\n@mkdir(\$dir);\n@unlink(\$path);\n",
  17133. [self::OPTION_NOISE_REMAINING_USAGES => true]
  17134. ),
  17135. new CodeSample(
  17136. "<?php\n@mkdir(\$dir);\n@unlink(\$path);\n",
  17137. [
  17138. self::OPTION_NOISE_REMAINING_USAGES => true,
  17139. self::OPTION_NOISE_REMAINING_USAGES_EXCLUDE => ['unlink'],
  17140. ]
  17141. ),
  17142. ],
  17143. null,
  17144. 'Risky because adding/removing `@` might cause changes to code behaviour or if `trigger_error` function is overridden.'
  17145. );
  17146. }
  17147. public function isCandidate(Tokens $tokens)
  17148. {
  17149. return $tokens->isAnyTokenKindsFound(['@', T_STRING]);
  17150. }
  17151. public function isRisky()
  17152. {
  17153. return true;
  17154. }
  17155. protected function createConfigurationDefinition()
  17156. {
  17157. return new FixerConfigurationResolver([
  17158. (new FixerOptionBuilder(self::OPTION_MUTE_DEPRECATION_ERROR, 'Whether to add `@` in deprecation notices.'))
  17159. ->setAllowedTypes(['bool'])
  17160. ->setDefault(true)
  17161. ->getOption(),
  17162. (new FixerOptionBuilder(self::OPTION_NOISE_REMAINING_USAGES, 'Whether to remove `@` in remaining usages.'))
  17163. ->setAllowedTypes(['bool'])
  17164. ->setDefault(false)
  17165. ->getOption(),
  17166. (new FixerOptionBuilder(self::OPTION_NOISE_REMAINING_USAGES_EXCLUDE, 'List of global functions to exclude from removing `@`'))
  17167. ->setAllowedTypes(['array'])
  17168. ->setDefault([])
  17169. ->getOption(),
  17170. ]);
  17171. }
  17172. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  17173. {
  17174. $functionsAnalyzer = new FunctionsAnalyzer();
  17175. $excludedFunctions = array_map(static function ($function) {
  17176. return strtolower($function);
  17177. }, $this->configuration[self::OPTION_NOISE_REMAINING_USAGES_EXCLUDE]);
  17178. for ($index = $tokens->count() - 1; $index >= 0; --$index) {
  17179. $token = $tokens[$index];
  17180. if ($this->configuration[self::OPTION_NOISE_REMAINING_USAGES] && $token->equals('@')) {
  17181. $tokens->clearAt($index);
  17182. continue;
  17183. }
  17184. if (!$functionsAnalyzer->isGlobalFunctionCall($tokens, $index)) {
  17185. continue;
  17186. }
  17187. $functionIndex = $index;
  17188. $startIndex = $index;
  17189. $prevIndex = $tokens->getPrevMeaningfulToken($index);
  17190. if ($tokens[$prevIndex]->isGivenKind(T_NS_SEPARATOR)) {
  17191. $startIndex = $prevIndex;
  17192. $prevIndex = $tokens->getPrevMeaningfulToken($startIndex);
  17193. }
  17194. $index = $prevIndex;
  17195. if ($this->isDeprecationErrorCall($tokens, $functionIndex)) {
  17196. if (!$this->configuration[self::OPTION_MUTE_DEPRECATION_ERROR]) {
  17197. continue;
  17198. }
  17199. if ($tokens[$prevIndex]->equals('@')) {
  17200. continue;
  17201. }
  17202. $tokens->insertAt($startIndex, new Token('@'));
  17203. continue;
  17204. }
  17205. if (!$tokens[$prevIndex]->equals('@')) {
  17206. continue;
  17207. }
  17208. if ($this->configuration[self::OPTION_NOISE_REMAINING_USAGES] && !\in_array($tokens[$functionIndex]->getContent(), $excludedFunctions, true)) {
  17209. $tokens->clearAt($index);
  17210. }
  17211. }
  17212. }
  17213. private function isDeprecationErrorCall(Tokens $tokens, $index)
  17214. {
  17215. if ('trigger_error' !== strtolower($tokens[$index]->getContent())) {
  17216. return false;
  17217. }
  17218. $endBraceIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $tokens->getNextTokenOfKind($index, [T_STRING, '(']));
  17219. $prevIndex = $tokens->getPrevMeaningfulToken($endBraceIndex);
  17220. if ($tokens[$prevIndex]->equals(',')) {
  17221. $prevIndex = $tokens->getPrevMeaningfulToken($prevIndex);
  17222. }
  17223. return $tokens[$prevIndex]->equals([T_STRING, 'E_USER_DEPRECATED']);
  17224. }
  17225. }
  17226. <?php
  17227. namespace PhpCsFixer\Fixer\LanguageConstruct;
  17228. use PhpCsFixer\AbstractFixer;
  17229. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  17230. use PhpCsFixer\FixerConfiguration\AllowedValueSubset;
  17231. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  17232. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  17233. use PhpCsFixer\FixerDefinition\CodeSample;
  17234. use PhpCsFixer\FixerDefinition\FixerDefinition;
  17235. use PhpCsFixer\Tokenizer\Analyzer\FunctionsAnalyzer;
  17236. use PhpCsFixer\Tokenizer\CT;
  17237. use PhpCsFixer\Tokenizer\Token;
  17238. use PhpCsFixer\Tokenizer\Tokens;
  17239. final class FunctionToConstantFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface
  17240. {
  17241. private static $availableFunctions;
  17242. private $functionsFixMap;
  17243. public function __construct()
  17244. {
  17245. if (null === self::$availableFunctions) {
  17246. self::$availableFunctions = [
  17247. 'get_called_class' => [
  17248. new Token([T_STATIC, 'static']),
  17249. new Token([T_DOUBLE_COLON, '::']),
  17250. new Token([CT::T_CLASS_CONSTANT, 'class']),
  17251. ],
  17252. 'get_class' => [new Token([T_CLASS_C, '__CLASS__'])],
  17253. 'get_class_this' => [
  17254. new Token([T_STATIC, 'static']),
  17255. new Token([T_DOUBLE_COLON, '::']),
  17256. new Token([CT::T_CLASS_CONSTANT, 'class']),
  17257. ],
  17258. 'php_sapi_name' => [new Token([T_STRING, 'PHP_SAPI'])],
  17259. 'phpversion' => [new Token([T_STRING, 'PHP_VERSION'])],
  17260. 'pi' => [new Token([T_STRING, 'M_PI'])],
  17261. ];
  17262. }
  17263. parent::__construct();
  17264. }
  17265. public function configure(array $configuration = null)
  17266. {
  17267. parent::configure($configuration);
  17268. $this->functionsFixMap = [];
  17269. foreach ($this->configuration['functions'] as $key) {
  17270. $this->functionsFixMap[$key] = self::$availableFunctions[$key];
  17271. }
  17272. }
  17273. public function getDefinition()
  17274. {
  17275. return new FixerDefinition(
  17276. 'Replace core functions calls returning constants with the constants.',
  17277. [
  17278. new CodeSample(
  17279. "<?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"
  17280. ),
  17281. new CodeSample(
  17282. "<?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",
  17283. ['functions' => ['get_called_class', 'get_class_this', 'phpversion']]
  17284. ),
  17285. ],
  17286. null,
  17287. 'Risky when any of the configured functions to replace are overridden.'
  17288. );
  17289. }
  17290. public function getPriority()
  17291. {
  17292. return 1;
  17293. }
  17294. public function isCandidate(Tokens $tokens)
  17295. {
  17296. return $tokens->isTokenKindFound(T_STRING);
  17297. }
  17298. public function isRisky()
  17299. {
  17300. return true;
  17301. }
  17302. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  17303. {
  17304. $functionAnalyzer = new FunctionsAnalyzer();
  17305. for ($index = $tokens->count() - 4; $index > 0; --$index) {
  17306. $candidate = $this->getReplaceCandidate($tokens, $functionAnalyzer, $index);
  17307. if (null === $candidate) {
  17308. continue;
  17309. }
  17310. $this->fixFunctionCallToConstant(
  17311. $tokens,
  17312. $index,
  17313. $candidate[0],
  17314. $candidate[1],
  17315. $candidate[2]
  17316. );
  17317. }
  17318. }
  17319. protected function createConfigurationDefinition()
  17320. {
  17321. $functionNames = array_keys(self::$availableFunctions);
  17322. return new FixerConfigurationResolver([
  17323. (new FixerOptionBuilder('functions', 'List of function names to fix.'))
  17324. ->setAllowedTypes(['array'])
  17325. ->setAllowedValues([new AllowedValueSubset($functionNames)])
  17326. ->setDefault([
  17327. 'get_class',
  17328. 'php_sapi_name',
  17329. 'phpversion',
  17330. 'pi',
  17331. ])
  17332. ->getOption(),
  17333. ]);
  17334. }
  17335. private function fixFunctionCallToConstant(Tokens $tokens, $index, $braceOpenIndex, $braceCloseIndex, array $replacements)
  17336. {
  17337. for ($i = $braceCloseIndex; $i >= $braceOpenIndex; --$i) {
  17338. if ($tokens[$i]->equalsAny([[T_WHITESPACE], [T_COMMENT], [T_DOC_COMMENT]])) {
  17339. continue;
  17340. }
  17341. $tokens->clearTokenAndMergeSurroundingWhitespace($i);
  17342. }
  17343. if ($replacements[0]->isGivenKind([T_CLASS_C, T_STATIC])) {
  17344. $prevIndex = $tokens->getPrevMeaningfulToken($index);
  17345. $prevToken = $tokens[$prevIndex];
  17346. if ($prevToken->isGivenKind(T_NS_SEPARATOR)) {
  17347. $tokens->clearAt($prevIndex);
  17348. }
  17349. }
  17350. $tokens->clearAt($index);
  17351. $tokens->insertAt($index, $replacements);
  17352. }
  17353. private function getReplaceCandidate(
  17354. Tokens $tokens,
  17355. FunctionsAnalyzer $functionAnalyzer,
  17356. $index
  17357. ) {
  17358. if (!$tokens[$index]->isGivenKind(T_STRING)) {
  17359. return null;
  17360. }
  17361. $lowerContent = strtolower($tokens[$index]->getContent());
  17362. if ('get_class' === $lowerContent) {
  17363. return $this->fixGetClassCall($tokens, $functionAnalyzer, $index);
  17364. }
  17365. if (!isset($this->functionsFixMap[$lowerContent])) {
  17366. return null;
  17367. }
  17368. if (!$functionAnalyzer->isGlobalFunctionCall($tokens, $index)) {
  17369. return null;
  17370. }
  17371. $braceOpenIndex = $tokens->getNextMeaningfulToken($index);
  17372. if (!$tokens[$braceOpenIndex]->equals('(')) {
  17373. return null;
  17374. }
  17375. $braceCloseIndex = $tokens->getNextMeaningfulToken($braceOpenIndex);
  17376. if (!$tokens[$braceCloseIndex]->equals(')')) {
  17377. return null;
  17378. }
  17379. return $this->getReplacementTokenClones($lowerContent, $braceOpenIndex, $braceCloseIndex);
  17380. }
  17381. private function fixGetClassCall(
  17382. Tokens $tokens,
  17383. FunctionsAnalyzer $functionAnalyzer,
  17384. $index
  17385. ) {
  17386. if (!isset($this->functionsFixMap['get_class']) && !isset($this->functionsFixMap['get_class_this'])) {
  17387. return null;
  17388. }
  17389. if (!$functionAnalyzer->isGlobalFunctionCall($tokens, $index)) {
  17390. return null;
  17391. }
  17392. $braceOpenIndex = $tokens->getNextMeaningfulToken($index);
  17393. $braceCloseIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $braceOpenIndex);
  17394. if ($braceCloseIndex === $tokens->getNextMeaningfulToken($braceOpenIndex)) {
  17395. if (isset($this->functionsFixMap['get_class'])) {
  17396. return $this->getReplacementTokenClones('get_class', $braceOpenIndex, $braceCloseIndex);
  17397. }
  17398. } else {
  17399. if (isset($this->functionsFixMap['get_class_this'])) {
  17400. $isThis = false;
  17401. for ($i = $braceOpenIndex + 1; $i < $braceCloseIndex; ++$i) {
  17402. if ($tokens[$i]->equalsAny([[T_WHITESPACE], [T_COMMENT], [T_DOC_COMMENT], ')'])) {
  17403. continue;
  17404. }
  17405. if ($tokens[$i]->isGivenKind(T_VARIABLE) && '$this' === strtolower($tokens[$i]->getContent())) {
  17406. $isThis = true;
  17407. continue;
  17408. }
  17409. if (false === $isThis && $tokens[$i]->equals('(')) {
  17410. continue;
  17411. }
  17412. $isThis = false;
  17413. break;
  17414. }
  17415. if ($isThis) {
  17416. return $this->getReplacementTokenClones('get_class_this', $braceOpenIndex, $braceCloseIndex);
  17417. }
  17418. }
  17419. }
  17420. return null;
  17421. }
  17422. private function getReplacementTokenClones($lowerContent, $braceOpenIndex, $braceCloseIndex)
  17423. {
  17424. $clones = [];
  17425. foreach ($this->functionsFixMap[$lowerContent] as $token) {
  17426. $clones[] = clone $token;
  17427. }
  17428. return [
  17429. $braceOpenIndex,
  17430. $braceCloseIndex,
  17431. $clones,
  17432. ];
  17433. }
  17434. }
  17435. <?php
  17436. namespace PhpCsFixer\Fixer\LanguageConstruct;
  17437. use PhpCsFixer\AbstractProxyFixer;
  17438. use PhpCsFixer\Fixer\DeprecatedFixerInterface;
  17439. use PhpCsFixer\FixerDefinition\CodeSample;
  17440. use PhpCsFixer\FixerDefinition\FixerDefinition;
  17441. final class SilencedDeprecationErrorFixer extends AbstractProxyFixer implements DeprecatedFixerInterface
  17442. {
  17443. public function getDefinition()
  17444. {
  17445. return new FixerDefinition(
  17446. 'Ensures deprecation notices are silenced.',
  17447. [new CodeSample("<?php\ntrigger_error('Warning.', E_USER_DEPRECATED);\n")],
  17448. null,
  17449. 'Silencing of deprecation errors might cause changes to code behaviour.'
  17450. );
  17451. }
  17452. public function getSuccessorsNames()
  17453. {
  17454. return array_keys($this->proxyFixers);
  17455. }
  17456. protected function createProxyFixers()
  17457. {
  17458. return [new ErrorSuppressionFixer()];
  17459. }
  17460. }
  17461. <?php
  17462. namespace PhpCsFixer\Fixer\LanguageConstruct;
  17463. use PhpCsFixer\AbstractFixer;
  17464. use PhpCsFixer\FixerDefinition\CodeSample;
  17465. use PhpCsFixer\FixerDefinition\FixerDefinition;
  17466. use PhpCsFixer\Tokenizer\Token;
  17467. use PhpCsFixer\Tokenizer\Tokens;
  17468. final class CombineConsecutiveIssetsFixer extends AbstractFixer
  17469. {
  17470. public function getDefinition()
  17471. {
  17472. return new FixerDefinition(
  17473. 'Using `isset($var) &&` multiple times should be done in one call.',
  17474. [new CodeSample("<?php\n\$a = isset(\$a) && isset(\$b);\n")]
  17475. );
  17476. }
  17477. public function getPriority()
  17478. {
  17479. return 3;
  17480. }
  17481. public function isCandidate(Tokens $tokens)
  17482. {
  17483. return $tokens->isAllTokenKindsFound([T_ISSET, T_BOOLEAN_AND]);
  17484. }
  17485. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  17486. {
  17487. $tokenCount = $tokens->count();
  17488. for ($index = 1; $index < $tokenCount; ++$index) {
  17489. if (!$tokens[$index]->isGivenKind(T_ISSET)
  17490. || !$tokens[$tokens->getPrevMeaningfulToken($index)]->equalsAny(['(', '{', ';', '=', [T_OPEN_TAG], [T_BOOLEAN_AND], [T_BOOLEAN_OR]])) {
  17491. continue;
  17492. }
  17493. $issetInfo = $this->getIssetInfo($tokens, $index);
  17494. $issetCloseBraceIndex = end($issetInfo);
  17495. $insertLocation = prev($issetInfo) + 1;
  17496. $booleanAndTokenIndex = $tokens->getNextMeaningfulToken($issetCloseBraceIndex);
  17497. while ($tokens[$booleanAndTokenIndex]->isGivenKind(T_BOOLEAN_AND)) {
  17498. $issetIndex = $tokens->getNextMeaningfulToken($booleanAndTokenIndex);
  17499. if (!$tokens[$issetIndex]->isGivenKind(T_ISSET)) {
  17500. $index = $issetIndex;
  17501. break;
  17502. }
  17503. $nextIssetInfo = $this->getIssetInfo($tokens, $issetIndex);
  17504. $nextMeaningfulTokenIndex = $tokens->getNextMeaningfulToken(end($nextIssetInfo));
  17505. $nextMeaningfulToken = $tokens[$nextMeaningfulTokenIndex];
  17506. if (!$nextMeaningfulToken->equalsAny([')', '}', ';', [T_CLOSE_TAG], [T_BOOLEAN_AND], [T_BOOLEAN_OR]])) {
  17507. $index = $nextMeaningfulTokenIndex;
  17508. break;
  17509. }
  17510. $clones = $this->getTokenClones($tokens, \array_slice($nextIssetInfo, 1, -1));
  17511. $this->clearTokens($tokens, array_merge($nextIssetInfo, [$issetIndex, $booleanAndTokenIndex]));
  17512. array_unshift($clones, new Token(','), new Token([T_WHITESPACE, ' ']));
  17513. $tokens->insertAt($insertLocation, $clones);
  17514. $numberOfTokensInserted = \count($clones);
  17515. $tokenCount += $numberOfTokensInserted;
  17516. $issetCloseBraceIndex += $numberOfTokensInserted;
  17517. $insertLocation += $numberOfTokensInserted;
  17518. $booleanAndTokenIndex = $tokens->getNextMeaningfulToken($issetCloseBraceIndex);
  17519. }
  17520. }
  17521. }
  17522. private function clearTokens(Tokens $tokens, array $indexes)
  17523. {
  17524. foreach ($indexes as $index) {
  17525. $tokens->clearTokenAndMergeSurroundingWhitespace($index);
  17526. }
  17527. }
  17528. private function getIssetInfo(Tokens $tokens, $index)
  17529. {
  17530. $openIndex = $tokens->getNextMeaningfulToken($index);
  17531. $braceOpenCount = 1;
  17532. $meaningfulTokenIndexes = [$openIndex];
  17533. for ($i = $openIndex + 1;; ++$i) {
  17534. if ($tokens[$i]->isWhitespace() || $tokens[$i]->isComment()) {
  17535. continue;
  17536. }
  17537. $meaningfulTokenIndexes[] = $i;
  17538. if ($tokens[$i]->equals(')')) {
  17539. --$braceOpenCount;
  17540. if (0 === $braceOpenCount) {
  17541. break;
  17542. }
  17543. } elseif ($tokens[$i]->equals('(')) {
  17544. ++$braceOpenCount;
  17545. }
  17546. }
  17547. return $meaningfulTokenIndexes;
  17548. }
  17549. private function getTokenClones(Tokens $tokens, array $indexes)
  17550. {
  17551. $clones = [];
  17552. foreach ($indexes as $i) {
  17553. $clones[] = clone $tokens[$i];
  17554. }
  17555. return $clones;
  17556. }
  17557. }
  17558. <?php
  17559. namespace PhpCsFixer\Fixer\LanguageConstruct;
  17560. use PhpCsFixer\AbstractFixer;
  17561. use PhpCsFixer\FixerDefinition\CodeSample;
  17562. use PhpCsFixer\FixerDefinition\FixerDefinition;
  17563. use PhpCsFixer\Tokenizer\Token;
  17564. use PhpCsFixer\Tokenizer\Tokens;
  17565. final class CombineConsecutiveUnsetsFixer extends AbstractFixer
  17566. {
  17567. public function getDefinition()
  17568. {
  17569. return new FixerDefinition(
  17570. 'Calling `unset` on multiple items should be done in one call.',
  17571. [new CodeSample("<?php\nunset(\$a); unset(\$b);\n")]
  17572. );
  17573. }
  17574. public function getPriority()
  17575. {
  17576. return 24;
  17577. }
  17578. public function isCandidate(Tokens $tokens)
  17579. {
  17580. return $tokens->isTokenKindFound(T_UNSET);
  17581. }
  17582. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  17583. {
  17584. for ($index = $tokens->count() - 1; $index >= 0; --$index) {
  17585. if (!$tokens[$index]->isGivenKind(T_UNSET)) {
  17586. continue;
  17587. }
  17588. $previousUnsetCall = $this->getPreviousUnsetCall($tokens, $index);
  17589. if (\is_int($previousUnsetCall)) {
  17590. $index = $previousUnsetCall;
  17591. continue;
  17592. }
  17593. list($previousUnset, , $previousUnsetBraceEnd) = $previousUnsetCall;
  17594. $tokensAddCount = $this->moveTokens(
  17595. $tokens,
  17596. $nextUnsetContentStart = $tokens->getNextTokenOfKind($index, ['(']),
  17597. $nextUnsetContentEnd = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $nextUnsetContentStart),
  17598. $previousUnsetBraceEnd - 1
  17599. );
  17600. if (!$tokens[$previousUnsetBraceEnd]->isWhitespace()) {
  17601. $tokens->insertAt($previousUnsetBraceEnd, new Token([T_WHITESPACE, ' ']));
  17602. ++$tokensAddCount;
  17603. }
  17604. $tokens->insertAt($previousUnsetBraceEnd, new Token(','));
  17605. ++$tokensAddCount;
  17606. $this->clearOffsetTokens($tokens, $tokensAddCount, [$index, $nextUnsetContentStart, $nextUnsetContentEnd]);
  17607. $nextUnsetSemicolon = $tokens->getNextMeaningfulToken($nextUnsetContentEnd);
  17608. if (null !== $nextUnsetSemicolon && $tokens[$nextUnsetSemicolon]->equals(';')) {
  17609. $tokens->clearTokenAndMergeSurroundingWhitespace($nextUnsetSemicolon);
  17610. }
  17611. $index = $previousUnset + 1;
  17612. }
  17613. }
  17614. private function clearOffsetTokens(Tokens $tokens, $offset, array $indices)
  17615. {
  17616. foreach ($indices as $index) {
  17617. $tokens->clearTokenAndMergeSurroundingWhitespace($index + $offset);
  17618. }
  17619. }
  17620. private function getPreviousUnsetCall(Tokens $tokens, $index)
  17621. {
  17622. $previousUnsetSemicolon = $tokens->getPrevMeaningfulToken($index);
  17623. if (null === $previousUnsetSemicolon) {
  17624. return $index;
  17625. }
  17626. if (!$tokens[$previousUnsetSemicolon]->equals(';')) {
  17627. return $previousUnsetSemicolon;
  17628. }
  17629. $previousUnsetBraceEnd = $tokens->getPrevMeaningfulToken($previousUnsetSemicolon);
  17630. if (null === $previousUnsetBraceEnd) {
  17631. return $index;
  17632. }
  17633. if (!$tokens[$previousUnsetBraceEnd]->equals(')')) {
  17634. return $previousUnsetBraceEnd;
  17635. }
  17636. $previousUnsetBraceStart = $tokens->findBlockStart(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $previousUnsetBraceEnd);
  17637. $previousUnset = $tokens->getPrevMeaningfulToken($previousUnsetBraceStart);
  17638. if (null === $previousUnset) {
  17639. return $index;
  17640. }
  17641. if (!$tokens[$previousUnset]->isGivenKind(T_UNSET)) {
  17642. return $previousUnset;
  17643. }
  17644. return [
  17645. $previousUnset,
  17646. $previousUnsetBraceStart,
  17647. $previousUnsetBraceEnd,
  17648. $previousUnsetSemicolon,
  17649. ];
  17650. }
  17651. private function moveTokens(Tokens $tokens, $start, $end, $to)
  17652. {
  17653. $added = 0;
  17654. for ($i = $start + 1; $i < $end; $i += 2) {
  17655. if ($tokens[$i]->isWhitespace() && $tokens[$to + 1]->isWhitespace()) {
  17656. $tokens[$to + 1] = new Token([T_WHITESPACE, $tokens[$to + 1]->getContent().$tokens[$i]->getContent()]);
  17657. } else {
  17658. $tokens->insertAt(++$to, clone $tokens[$i]);
  17659. ++$end;
  17660. ++$added;
  17661. }
  17662. $tokens->clearAt($i + 1);
  17663. }
  17664. return $added;
  17665. }
  17666. }
  17667. <?php
  17668. namespace PhpCsFixer\Fixer\LanguageConstruct;
  17669. use PhpCsFixer\AbstractFunctionReferenceFixer;
  17670. use PhpCsFixer\FixerDefinition\CodeSample;
  17671. use PhpCsFixer\FixerDefinition\FixerDefinition;
  17672. use PhpCsFixer\Tokenizer\Token;
  17673. use PhpCsFixer\Tokenizer\Tokens;
  17674. final class DirConstantFixer extends AbstractFunctionReferenceFixer
  17675. {
  17676. public function getDefinition()
  17677. {
  17678. return new FixerDefinition(
  17679. 'Replaces `dirname(__FILE__)` expression with equivalent `__DIR__` constant.',
  17680. [new CodeSample("<?php\n\$a = dirname(__FILE__);\n")],
  17681. null,
  17682. 'Risky when the function `dirname` is overridden.'
  17683. );
  17684. }
  17685. public function isCandidate(Tokens $tokens)
  17686. {
  17687. return $tokens->isTokenKindFound(T_FILE);
  17688. }
  17689. public function getPriority()
  17690. {
  17691. return 4;
  17692. }
  17693. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  17694. {
  17695. $currIndex = 0;
  17696. while (null !== $currIndex) {
  17697. $boundaries = $this->find('dirname', $tokens, $currIndex, $tokens->count() - 1);
  17698. if (null === $boundaries) {
  17699. return;
  17700. }
  17701. list($functionNameIndex, $openParenthesis, $closeParenthesis) = $boundaries;
  17702. $currIndex = $openParenthesis;
  17703. $fileCandidateRightIndex = $tokens->getPrevMeaningfulToken($closeParenthesis);
  17704. $trailingCommaIndex = null;
  17705. if ($tokens[$fileCandidateRightIndex]->equals(',')) {
  17706. $trailingCommaIndex = $fileCandidateRightIndex;
  17707. $fileCandidateRightIndex = $tokens->getPrevMeaningfulToken($fileCandidateRightIndex);
  17708. }
  17709. $fileCandidateRight = $tokens[$fileCandidateRightIndex];
  17710. if (!$fileCandidateRight->isGivenKind(T_FILE)) {
  17711. continue;
  17712. }
  17713. $fileCandidateLeftIndex = $tokens->getNextMeaningfulToken($openParenthesis);
  17714. $fileCandidateLeft = $tokens[$fileCandidateLeftIndex];
  17715. if (!$fileCandidateLeft->isGivenKind(T_FILE)) {
  17716. continue;
  17717. }
  17718. $namespaceCandidateIndex = $tokens->getPrevMeaningfulToken($functionNameIndex);
  17719. $namespaceCandidate = $tokens[$namespaceCandidateIndex];
  17720. if ($namespaceCandidate->isGivenKind(T_NS_SEPARATOR)) {
  17721. $tokens->removeTrailingWhitespace($namespaceCandidateIndex);
  17722. $tokens->clearAt($namespaceCandidateIndex);
  17723. }
  17724. if (null !== $trailingCommaIndex) {
  17725. if (!$tokens[$tokens->getNextNonWhitespace($trailingCommaIndex)]->isComment()) {
  17726. $tokens->removeTrailingWhitespace($trailingCommaIndex);
  17727. }
  17728. $tokens->clearTokenAndMergeSurroundingWhitespace($trailingCommaIndex);
  17729. }
  17730. if (!$tokens[$tokens->getNextNonWhitespace($closeParenthesis)]->isComment()) {
  17731. $tokens->removeLeadingWhitespace($closeParenthesis);
  17732. }
  17733. $tokens->clearTokenAndMergeSurroundingWhitespace($closeParenthesis);
  17734. if (!$tokens[$tokens->getNextNonWhitespace($openParenthesis)]->isComment()) {
  17735. $tokens->removeLeadingWhitespace($openParenthesis);
  17736. }
  17737. $tokens->removeTrailingWhitespace($openParenthesis);
  17738. $tokens->clearTokenAndMergeSurroundingWhitespace($openParenthesis);
  17739. $tokens[$fileCandidateLeftIndex] = new Token([T_DIR, '__DIR__']);
  17740. $tokens->clearTokenAndMergeSurroundingWhitespace($functionNameIndex);
  17741. }
  17742. }
  17743. }
  17744. <?php
  17745. namespace PhpCsFixer\Fixer\Basic;
  17746. use PhpCsFixer\AbstractPsrAutoloadingFixer;
  17747. use PhpCsFixer\FixerDefinition\FileSpecificCodeSample;
  17748. use PhpCsFixer\FixerDefinition\FixerDefinition;
  17749. use PhpCsFixer\Tokenizer\Token;
  17750. use PhpCsFixer\Tokenizer\Tokens;
  17751. /**
  17752. @gmail
  17753. @gotink
  17754. @alt
  17755. */
  17756. final class Psr4Fixer extends AbstractPsrAutoloadingFixer
  17757. {
  17758. public function getDefinition()
  17759. {
  17760. return new FixerDefinition(
  17761. 'Class names should match the file name.',
  17762. [
  17763. new FileSpecificCodeSample(
  17764. '<?php
  17765. namespace PhpCsFixer\FIXER\Basic;
  17766. class InvalidName {}
  17767. ',
  17768. new \SplFileInfo(__FILE__)
  17769. ),
  17770. ],
  17771. null,
  17772. 'This fixer may change your class name, which will break the code that depends on the old name.'
  17773. );
  17774. }
  17775. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  17776. {
  17777. $isNamespaceFound = false;
  17778. $classyIndex = 0;
  17779. $classyName = null;
  17780. foreach ($tokens as $index => $token) {
  17781. if ($token->isGivenKind(T_NAMESPACE)) {
  17782. if ($isNamespaceFound) {
  17783. return;
  17784. }
  17785. $isNamespaceFound = true;
  17786. } elseif ($token->isClassy()) {
  17787. $prevToken = $tokens[$tokens->getPrevMeaningfulToken($index)];
  17788. if ($prevToken->isGivenKind(T_NEW)) {
  17789. continue;
  17790. }
  17791. if (null !== $classyName) {
  17792. return;
  17793. }
  17794. $classyIndex = $tokens->getNextMeaningfulToken($index);
  17795. $classyName = $tokens[$classyIndex]->getContent();
  17796. }
  17797. }
  17798. if (null === $classyName) {
  17799. return;
  17800. }
  17801. if ($isNamespaceFound) {
  17802. $filename = basename(str_replace('\\', '/', $file->getRealPath()), '.php');
  17803. if ($classyName !== $filename) {
  17804. $tokens[$classyIndex] = new Token([T_STRING, $filename]);
  17805. }
  17806. } else {
  17807. $normClass = str_replace('_', '/', $classyName);
  17808. $filename = substr(str_replace('\\', '/', $file->getRealPath()), -\strlen($normClass) - 4, -4);
  17809. if ($normClass !== $filename && strtolower($normClass) === strtolower($filename)) {
  17810. $tokens[$classyIndex] = new Token([T_STRING, str_replace('/', '_', $filename)]);
  17811. }
  17812. }
  17813. }
  17814. }
  17815. <?php
  17816. namespace PhpCsFixer\Fixer\Basic;
  17817. use PhpCsFixer\AbstractFixer;
  17818. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  17819. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  17820. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  17821. use PhpCsFixer\FixerConfiguration\InvalidOptionsForEnvException;
  17822. use PhpCsFixer\FixerDefinition\CodeSample;
  17823. use PhpCsFixer\FixerDefinition\FixerDefinition;
  17824. use PhpCsFixer\FixerDefinition\VersionSpecification;
  17825. use PhpCsFixer\FixerDefinition\VersionSpecificCodeSample;
  17826. use PhpCsFixer\Preg;
  17827. use PhpCsFixer\Tokenizer\Token;
  17828. use PhpCsFixer\Tokenizer\Tokens;
  17829. use Symfony\Component\OptionsResolver\Options;
  17830. final class NonPrintableCharacterFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface
  17831. {
  17832. private $symbolsReplace;
  17833. private static $tokens = [
  17834. T_STRING_VARNAME,
  17835. T_INLINE_HTML,
  17836. T_VARIABLE,
  17837. T_COMMENT,
  17838. T_ENCAPSED_AND_WHITESPACE,
  17839. T_CONSTANT_ENCAPSED_STRING,
  17840. T_DOC_COMMENT,
  17841. ];
  17842. public function __construct()
  17843. {
  17844. parent::__construct();
  17845. $this->symbolsReplace = [
  17846. pack('H*', 'e2808b') => ['', '200b'],
  17847. pack('H*', 'e28087') => [' ', '2007'],
  17848. pack('H*', 'e280af') => [' ', '202f'],
  17849. pack('H*', 'e281a0') => ['', '2060'],
  17850. pack('H*', 'c2a0') => [' ', 'a0'],
  17851. ];
  17852. }
  17853. public function getDefinition()
  17854. {
  17855. return new FixerDefinition(
  17856. 'Remove Zero-width space (ZWSP), Non-breaking space (NBSP) and other invisible unicode symbols.',
  17857. [
  17858. new CodeSample(
  17859. '<?php echo "'.pack('H*', 'e2808b').'Hello'.pack('H*', 'e28087').'World'.pack('H*', 'c2a0')."!\";\n"
  17860. ),
  17861. new VersionSpecificCodeSample(
  17862. '<?php echo "'.pack('H*', 'e2808b').'Hello'.pack('H*', 'e28087').'World'.pack('H*', 'c2a0')."!\";\n",
  17863. new VersionSpecification(70000),
  17864. ['use_escape_sequences_in_strings' => true]
  17865. ),
  17866. ],
  17867. null,
  17868. 'Risky when strings contain intended invisible characters.'
  17869. );
  17870. }
  17871. public function isRisky()
  17872. {
  17873. return true;
  17874. }
  17875. public function isCandidate(Tokens $tokens)
  17876. {
  17877. return $tokens->isAnyTokenKindsFound(self::$tokens);
  17878. }
  17879. protected function createConfigurationDefinition()
  17880. {
  17881. return new FixerConfigurationResolver([
  17882. (new FixerOptionBuilder('use_escape_sequences_in_strings', 'Whether characters should be replaced with escape sequences in strings.'))
  17883. ->setAllowedTypes(['bool'])
  17884. ->setDefault(false)
  17885. ->setNormalizer(static function (Options $options, $value) {
  17886. if (\PHP_VERSION_ID < 70000 && $value) {
  17887. throw new InvalidOptionsForEnvException('Escape sequences require PHP 7.0+.');
  17888. }
  17889. return $value;
  17890. })
  17891. ->getOption(),
  17892. ]);
  17893. }
  17894. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  17895. {
  17896. $replacements = [];
  17897. $escapeSequences = [];
  17898. foreach ($this->symbolsReplace as $character => list($replacement, $codepoint)) {
  17899. $replacements[$character] = $replacement;
  17900. $escapeSequences[$character] = '\u{'.$codepoint.'}';
  17901. }
  17902. foreach ($tokens as $index => $token) {
  17903. $content = $token->getContent();
  17904. if (
  17905. $this->configuration['use_escape_sequences_in_strings']
  17906. && $token->isGivenKind([T_CONSTANT_ENCAPSED_STRING, T_ENCAPSED_AND_WHITESPACE])
  17907. ) {
  17908. if (!Preg::match('/'.implode('|', array_keys($escapeSequences)).'/', $content)) {
  17909. continue;
  17910. }
  17911. $previousToken = $tokens[$index - 1];
  17912. $stringTypeChanged = false;
  17913. $swapQuotes = false;
  17914. if ($previousToken->isGivenKind(T_START_HEREDOC)) {
  17915. $previousTokenContent = $previousToken->getContent();
  17916. if (false !== strpos($previousTokenContent, '\'')) {
  17917. $tokens[$index - 1] = new Token([T_START_HEREDOC, str_replace('\'', '', $previousTokenContent)]);
  17918. $stringTypeChanged = true;
  17919. }
  17920. } elseif ("'" === $content[0]) {
  17921. $stringTypeChanged = true;
  17922. $swapQuotes = true;
  17923. }
  17924. if ($swapQuotes) {
  17925. $content = str_replace("\\'", "'", $content);
  17926. }
  17927. if ($stringTypeChanged) {
  17928. $content = Preg::replace('/(\\\\{1,2})/', '\\\\\\\\', $content);
  17929. $content = str_replace('$', '\$', $content);
  17930. }
  17931. if ($swapQuotes) {
  17932. $content = str_replace('"', '\"', $content);
  17933. $content = Preg::replace('/^\'(.*)\'$/', '"$1"', $content);
  17934. }
  17935. $tokens[$index] = new Token([$token->getId(), strtr($content, $escapeSequences)]);
  17936. continue;
  17937. }
  17938. if ($token->isGivenKind(self::$tokens)) {
  17939. $tokens[$index] = new Token([$token->getId(), strtr($content, $replacements)]);
  17940. }
  17941. }
  17942. }
  17943. }
  17944. <?php
  17945. namespace PhpCsFixer\Fixer\Basic;
  17946. use PhpCsFixer\AbstractPsrAutoloadingFixer;
  17947. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  17948. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  17949. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  17950. use PhpCsFixer\FixerDefinition\FileSpecificCodeSample;
  17951. use PhpCsFixer\FixerDefinition\FixerDefinition;
  17952. use PhpCsFixer\Tokenizer\Token;
  17953. use PhpCsFixer\Tokenizer\Tokens;
  17954. /**
  17955. @gmail
  17956. @gotink
  17957. @alt
  17958. */
  17959. final class Psr0Fixer extends AbstractPsrAutoloadingFixer implements ConfigurationDefinitionFixerInterface
  17960. {
  17961. public function getDefinition()
  17962. {
  17963. return new FixerDefinition(
  17964. '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.',
  17965. [
  17966. new FileSpecificCodeSample(
  17967. '<?php
  17968. namespace PhpCsFixer\FIXER\Basic;
  17969. class InvalidName {}
  17970. ',
  17971. new \SplFileInfo(__FILE__)
  17972. ),
  17973. new FileSpecificCodeSample(
  17974. '<?php
  17975. namespace PhpCsFixer\FIXER\Basic;
  17976. class InvalidName {}
  17977. ',
  17978. new \SplFileInfo(__FILE__),
  17979. ['dir' => realpath(__DIR__.'/../..')]
  17980. ),
  17981. ],
  17982. null,
  17983. 'This fixer may change your class name, which will break the code that depends on the old name.'
  17984. );
  17985. }
  17986. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  17987. {
  17988. $namespace = false;
  17989. $namespaceIndex = 0;
  17990. $namespaceEndIndex = 0;
  17991. $classyName = null;
  17992. $classyIndex = 0;
  17993. foreach ($tokens as $index => $token) {
  17994. if ($token->isGivenKind(T_NAMESPACE)) {
  17995. if (false !== $namespace) {
  17996. return;
  17997. }
  17998. $namespaceIndex = $tokens->getNextMeaningfulToken($index);
  17999. $namespaceEndIndex = $tokens->getNextTokenOfKind($index, [';']);
  18000. $namespace = trim($tokens->generatePartialCode($namespaceIndex, $namespaceEndIndex - 1));
  18001. } elseif ($token->isClassy()) {
  18002. $prevToken = $tokens[$tokens->getPrevMeaningfulToken($index)];
  18003. if ($prevToken->isGivenKind(T_NEW)) {
  18004. continue;
  18005. }
  18006. if (null !== $classyName) {
  18007. return;
  18008. }
  18009. $classyIndex = $tokens->getNextMeaningfulToken($index);
  18010. $classyName = $tokens[$classyIndex]->getContent();
  18011. }
  18012. }
  18013. if (null === $classyName) {
  18014. return;
  18015. }
  18016. if (false !== $namespace) {
  18017. $normNamespace = str_replace('\\', '/', $namespace);
  18018. $path = str_replace('\\', '/', $file->getRealPath());
  18019. $dir = \dirname($path);
  18020. if ('' !== $this->configuration['dir']) {
  18021. $dir = substr($dir, \strlen(realpath($this->configuration['dir'])) + 1);
  18022. if (false === $dir) {
  18023. $dir = '';
  18024. }
  18025. if (\strlen($normNamespace) > \strlen($dir)) {
  18026. if ('' !== $dir) {
  18027. $normNamespace = substr($normNamespace, -\strlen($dir));
  18028. } else {
  18029. $normNamespace = '';
  18030. }
  18031. }
  18032. }
  18033. $dir = substr($dir, -\strlen($normNamespace));
  18034. if (false === $dir) {
  18035. $dir = '';
  18036. }
  18037. $filename = basename($path, '.php');
  18038. if ($classyName !== $filename) {
  18039. $tokens[$classyIndex] = new Token([T_STRING, $filename]);
  18040. }
  18041. if ($normNamespace !== $dir && strtolower($normNamespace) === strtolower($dir)) {
  18042. for ($i = $namespaceIndex; $i <= $namespaceEndIndex; ++$i) {
  18043. $tokens->clearAt($i);
  18044. }
  18045. $namespace = substr($namespace, 0, -\strlen($dir)).str_replace('/', '\\', $dir);
  18046. $newNamespace = Tokens::fromCode('<?php namespace '.$namespace.';');
  18047. $newNamespace->clearRange(0, 2);
  18048. $newNamespace->clearEmptyTokens();
  18049. $tokens->insertAt($namespaceIndex, $newNamespace);
  18050. }
  18051. } else {
  18052. $normClass = str_replace('_', '/', $classyName);
  18053. $path = str_replace('\\', '/', $file->getRealPath());
  18054. $filename = substr($path, -\strlen($normClass) - 4, -4);
  18055. if ($normClass !== $filename && strtolower($normClass) === strtolower($filename)) {
  18056. $tokens[$classyIndex] = new Token([T_STRING, str_replace('/', '_', $filename)]);
  18057. }
  18058. }
  18059. }
  18060. protected function createConfigurationDefinition()
  18061. {
  18062. return new FixerConfigurationResolver([
  18063. (new FixerOptionBuilder('dir', 'The directory where the project code is placed.'))
  18064. ->setAllowedTypes(['string'])
  18065. ->setDefault('')
  18066. ->getOption(),
  18067. ]);
  18068. }
  18069. }
  18070. <?php
  18071. namespace PhpCsFixer\Fixer\Basic;
  18072. use PhpCsFixer\AbstractFixer;
  18073. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  18074. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  18075. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  18076. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  18077. use PhpCsFixer\FixerDefinition\CodeSample;
  18078. use PhpCsFixer\FixerDefinition\FixerDefinition;
  18079. use PhpCsFixer\Preg;
  18080. use PhpCsFixer\Tokenizer\CT;
  18081. use PhpCsFixer\Tokenizer\Token;
  18082. use PhpCsFixer\Tokenizer\Tokens;
  18083. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  18084. final class BracesFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface, WhitespacesAwareFixerInterface
  18085. {
  18086. const LINE_NEXT = 'next';
  18087. const LINE_SAME = 'same';
  18088. public function getDefinition()
  18089. {
  18090. return new FixerDefinition(
  18091. 'The body of each structure MUST be enclosed by braces. Braces should be properly placed. Body of braces should be properly indented.',
  18092. [
  18093. new CodeSample(
  18094. '<?php
  18095. class Foo {
  18096. public function bar($baz) {
  18097. if ($baz = 900) echo "Hello!";
  18098. if ($baz = 9000)
  18099. echo "Wait!";
  18100. if ($baz == true)
  18101. {
  18102. echo "Why?";
  18103. }
  18104. else
  18105. {
  18106. echo "Ha?";
  18107. }
  18108. if (is_array($baz))
  18109. foreach ($baz as $b)
  18110. {
  18111. echo $b;
  18112. }
  18113. }
  18114. }
  18115. '
  18116. ),
  18117. new CodeSample(
  18118. '<?php
  18119. $positive = function ($item) { return $item >= 0; };
  18120. $negative = function ($item) {
  18121. return $item < 0; };
  18122. ',
  18123. ['allow_single_line_closure' => true]
  18124. ),
  18125. new CodeSample(
  18126. '<?php
  18127. class Foo
  18128. {
  18129. public function bar($baz)
  18130. {
  18131. if ($baz = 900) echo "Hello!";
  18132. if ($baz = 9000)
  18133. echo "Wait!";
  18134. if ($baz == true)
  18135. {
  18136. echo "Why?";
  18137. }
  18138. else
  18139. {
  18140. echo "Ha?";
  18141. }
  18142. if (is_array($baz))
  18143. foreach ($baz as $b)
  18144. {
  18145. echo $b;
  18146. }
  18147. }
  18148. }
  18149. ',
  18150. ['position_after_functions_and_oop_constructs' => self::LINE_SAME]
  18151. ),
  18152. ]
  18153. );
  18154. }
  18155. public function getPriority()
  18156. {
  18157. return -25;
  18158. }
  18159. public function isCandidate(Tokens $tokens)
  18160. {
  18161. return true;
  18162. }
  18163. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  18164. {
  18165. $this->fixCommentBeforeBrace($tokens);
  18166. $this->fixMissingControlBraces($tokens);
  18167. $this->fixIndents($tokens);
  18168. $this->fixControlContinuationBraces($tokens);
  18169. $this->fixSpaceAroundToken($tokens);
  18170. $this->fixDoWhile($tokens);
  18171. }
  18172. protected function createConfigurationDefinition()
  18173. {
  18174. return new FixerConfigurationResolver([
  18175. (new FixerOptionBuilder('allow_single_line_closure', 'Whether single line lambda notation should be allowed.'))
  18176. ->setAllowedTypes(['bool'])
  18177. ->setDefault(false)
  18178. ->getOption(),
  18179. (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).'))
  18180. ->setAllowedValues([self::LINE_NEXT, self::LINE_SAME])
  18181. ->setDefault(self::LINE_NEXT)
  18182. ->getOption(),
  18183. (new FixerOptionBuilder('position_after_control_structures', 'whether the opening brace should be placed on "next" or "same" line after control structures.'))
  18184. ->setAllowedValues([self::LINE_NEXT, self::LINE_SAME])
  18185. ->setDefault(self::LINE_SAME)
  18186. ->getOption(),
  18187. (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).'))
  18188. ->setAllowedValues([self::LINE_NEXT, self::LINE_SAME])
  18189. ->setDefault(self::LINE_SAME)
  18190. ->getOption(),
  18191. ]);
  18192. }
  18193. private function fixCommentBeforeBrace(Tokens $tokens)
  18194. {
  18195. $tokensAnalyzer = new TokensAnalyzer($tokens);
  18196. $controlTokens = $this->getControlTokens();
  18197. for ($index = $tokens->count() - 1; 0 <= $index; --$index) {
  18198. $token = $tokens[$index];
  18199. if ($token->isGivenKind($controlTokens)) {
  18200. $prevIndex = $this->findParenthesisEnd($tokens, $index);
  18201. } elseif (
  18202. ($token->isGivenKind(T_FUNCTION) && $tokensAnalyzer->isLambda($index)) ||
  18203. ($token->isGivenKind(T_CLASS) && $tokensAnalyzer->isAnonymousClass($index))
  18204. ) {
  18205. $prevIndex = $tokens->getNextTokenOfKind($index, ['{']);
  18206. $prevIndex = $tokens->getPrevMeaningfulToken($prevIndex);
  18207. } else {
  18208. continue;
  18209. }
  18210. $commentIndex = $tokens->getNextNonWhitespace($prevIndex);
  18211. $commentToken = $tokens[$commentIndex];
  18212. if (!$commentToken->isGivenKind(T_COMMENT) || 0 === strpos($commentToken->getContent(), '/*')) {
  18213. continue;
  18214. }
  18215. $braceIndex = $tokens->getNextMeaningfulToken($commentIndex);
  18216. $braceToken = $tokens[$braceIndex];
  18217. if (!$braceToken->equals('{')) {
  18218. continue;
  18219. }
  18220. $tokenTmp = $tokens[$braceIndex];
  18221. $newBraceIndex = $prevIndex + 1;
  18222. for ($i = $braceIndex; $i > $newBraceIndex; --$i) {
  18223. $previousToken = $tokens[$i - 1];
  18224. $tokens[$i] = $previousToken;
  18225. if ($tokens[$i]->isWhitespace() && $tokens[$i + 1]->isWhitespace()) {
  18226. $tokens[$i] = new Token([T_WHITESPACE, $tokens[$i]->getContent().$tokens[$i + 1]->getContent()]);
  18227. $tokens->clearAt($i + 1);
  18228. }
  18229. }
  18230. $tokens[$newBraceIndex] = $tokenTmp;
  18231. $c = $tokens[$braceIndex]->getContent();
  18232. if (substr_count($c, "\n") > 1) {
  18233. $tokens[$braceIndex] = new Token([T_WHITESPACE, substr($c, strrpos($c, "\n"))]);
  18234. }
  18235. }
  18236. }
  18237. private function fixControlContinuationBraces(Tokens $tokens)
  18238. {
  18239. $controlContinuationTokens = $this->getControlContinuationTokens();
  18240. for ($index = \count($tokens) - 1; 0 <= $index; --$index) {
  18241. $token = $tokens[$index];
  18242. if (!$token->isGivenKind($controlContinuationTokens)) {
  18243. continue;
  18244. }
  18245. $prevIndex = $tokens->getPrevNonWhitespace($index);
  18246. $prevToken = $tokens[$prevIndex];
  18247. if (!$prevToken->equals('}')) {
  18248. continue;
  18249. }
  18250. $tokens->ensureWhitespaceAtIndex(
  18251. $index - 1,
  18252. 1,
  18253. self::LINE_NEXT === $this->configuration['position_after_control_structures'] ?
  18254. $this->whitespacesConfig->getLineEnding().$this->detectIndent($tokens, $index)
  18255. : ' '
  18256. );
  18257. }
  18258. }
  18259. private function fixDoWhile(Tokens $tokens)
  18260. {
  18261. for ($index = \count($tokens) - 1; 0 <= $index; --$index) {
  18262. $token = $tokens[$index];
  18263. if (!$token->isGivenKind(T_DO)) {
  18264. continue;
  18265. }
  18266. $parenthesisEndIndex = $this->findParenthesisEnd($tokens, $index);
  18267. $startBraceIndex = $tokens->getNextNonWhitespace($parenthesisEndIndex);
  18268. $endBraceIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $startBraceIndex);
  18269. $nextNonWhitespaceIndex = $tokens->getNextNonWhitespace($endBraceIndex);
  18270. $nextNonWhitespaceToken = $tokens[$nextNonWhitespaceIndex];
  18271. if (!$nextNonWhitespaceToken->isGivenKind(T_WHILE)) {
  18272. continue;
  18273. }
  18274. $tokens->ensureWhitespaceAtIndex($nextNonWhitespaceIndex - 1, 1, ' ');
  18275. }
  18276. }
  18277. private function fixIndents(Tokens $tokens)
  18278. {
  18279. $classyTokens = Token::getClassyTokenKinds();
  18280. $classyAndFunctionTokens = array_merge([T_FUNCTION], $classyTokens);
  18281. $controlTokens = $this->getControlTokens();
  18282. $indentTokens = array_filter(
  18283. array_merge($classyAndFunctionTokens, $controlTokens),
  18284. static function ($item) {
  18285. return T_SWITCH !== $item;
  18286. }
  18287. );
  18288. $tokensAnalyzer = new TokensAnalyzer($tokens);
  18289. for ($index = 0, $limit = \count($tokens); $index < $limit; ++$index) {
  18290. $token = $tokens[$index];
  18291. if (!$token->isGivenKind($indentTokens)) {
  18292. continue;
  18293. }
  18294. if (
  18295. $token->isGivenKind(T_WHILE)
  18296. && $tokensAnalyzer->isWhilePartOfDoWhile($index)
  18297. ) {
  18298. continue;
  18299. }
  18300. if (
  18301. $this->configuration['allow_single_line_closure']
  18302. && $token->isGivenKind(T_FUNCTION)
  18303. && $tokensAnalyzer->isLambda($index)
  18304. ) {
  18305. $braceEndIndex = $tokens->findBlockEnd(
  18306. Tokens::BLOCK_TYPE_CURLY_BRACE,
  18307. $tokens->getNextTokenOfKind($index, ['{'])
  18308. );
  18309. if (!$this->isMultilined($tokens, $index, $braceEndIndex)) {
  18310. $index = $braceEndIndex;
  18311. continue;
  18312. }
  18313. }
  18314. if ($token->isGivenKind($classyAndFunctionTokens)) {
  18315. $startBraceIndex = $tokens->getNextTokenOfKind($index, [';', '{']);
  18316. $startBraceToken = $tokens[$startBraceIndex];
  18317. } else {
  18318. $parenthesisEndIndex = $this->findParenthesisEnd($tokens, $index);
  18319. $startBraceIndex = $tokens->getNextNonWhitespace($parenthesisEndIndex);
  18320. $startBraceToken = $tokens[$startBraceIndex];
  18321. }
  18322. if (!$startBraceToken->equals('{')) {
  18323. continue;
  18324. }
  18325. $nextNonWhitespaceIndex = $tokens->getNextNonWhitespace($startBraceIndex, " \t");
  18326. $nextNonWhitespace = $tokens[$nextNonWhitespaceIndex];
  18327. if ($nextNonWhitespace->isGivenKind(T_CLOSE_TAG)) {
  18328. continue;
  18329. }
  18330. if ($nextNonWhitespace->isComment() && $tokens[$tokens->getNextMeaningfulToken($nextNonWhitespaceIndex)]->isGivenKind(T_CLOSE_TAG)) {
  18331. continue;
  18332. }
  18333. $endBraceIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $startBraceIndex);
  18334. $indent = $this->detectIndent($tokens, $index);
  18335. $tokens->ensureWhitespaceAtIndex($endBraceIndex - 1, 1, $this->whitespacesConfig->getLineEnding().$indent);
  18336. $lastCommaIndex = $tokens->getPrevTokenOfKind($endBraceIndex - 1, [';', '}']);
  18337. $nestLevel = 1;
  18338. for ($nestIndex = $lastCommaIndex; $nestIndex >= $startBraceIndex; --$nestIndex) {
  18339. $nestToken = $tokens[$nestIndex];
  18340. if ($nestToken->equalsAny([')', [CT::T_BRACE_CLASS_INSTANTIATION_CLOSE]])) {
  18341. $nestIndex = $tokens->findBlockStart(
  18342. $nestToken->equals(')') ? Tokens::BLOCK_TYPE_PARENTHESIS_BRACE : Tokens::BLOCK_TYPE_BRACE_CLASS_INSTANTIATION,
  18343. $nestIndex
  18344. );
  18345. continue;
  18346. }
  18347. if (1 === $nestLevel) {
  18348. $nextLineCanBeIndented = false;
  18349. if ($nestToken->equalsAny([';', '}'])) {
  18350. $nextLineCanBeIndented = true;
  18351. } elseif ($this->isCommentWithFixableIndentation($tokens, $nestIndex)) {
  18352. for ($i = $nestIndex; $i > $startBraceIndex; --$i) {
  18353. if ($tokens[$i]->equalsAny([';', '}'])) {
  18354. $nextLineCanBeIndented = true;
  18355. break;
  18356. }
  18357. if (!$tokens[$i]->isWhitespace() && !$tokens[$i]->isComment()) {
  18358. break;
  18359. }
  18360. }
  18361. if ($nextLineCanBeIndented || $i === $startBraceIndex) {
  18362. $nextToken = $tokens[$nestIndex + 1];
  18363. $nextLineCanBeIndented = $nextToken->isWhitespace() && 1 === Preg::match('/\R/', $nextToken->getContent());
  18364. }
  18365. }
  18366. if (!$nextLineCanBeIndented) {
  18367. continue;
  18368. }
  18369. $nextNonWhitespaceNestIndex = $tokens->getNextNonWhitespace($nestIndex);
  18370. $nextNonWhitespaceNestToken = $tokens[$nextNonWhitespaceNestIndex];
  18371. if (
  18372. !($nextNonWhitespaceNestToken->isComment() && (
  18373. !$tokens[$nextNonWhitespaceNestIndex - 1]->isWhitespace()
  18374. || !Preg::match('/\R/', $tokens[$nextNonWhitespaceNestIndex - 1]->getContent())
  18375. )) &&
  18376. !($nestToken->equals('}') && $nextNonWhitespaceNestToken->equalsAny([';', ',', ']', [CT::T_ARRAY_SQUARE_BRACE_CLOSE]])) &&
  18377. !($nestToken->equals('}') && $nextNonWhitespaceNestToken->equals('(')) &&
  18378. !($nestToken->equals('}') && $tokens[$nestIndex - 1]->equalsAny(['"', "'", [T_CONSTANT_ENCAPSED_STRING], [T_VARIABLE]])) &&
  18379. !($tokens[$nestIndex - 1]->isGivenKind(T_END_HEREDOC) && $nextNonWhitespaceNestToken->isGivenKind(T_CLOSE_TAG))
  18380. ) {
  18381. if (
  18382. (
  18383. self::LINE_NEXT !== $this->configuration['position_after_control_structures']
  18384. && $nextNonWhitespaceNestToken->isGivenKind($this->getControlContinuationTokens())
  18385. && !$tokens[$tokens->getPrevNonWhitespace($nextNonWhitespaceNestIndex)]->isComment()
  18386. )
  18387. || $nextNonWhitespaceNestToken->isGivenKind(T_CLOSE_TAG)
  18388. || (
  18389. self::LINE_NEXT !== $this->configuration['position_after_control_structures']
  18390. && $nextNonWhitespaceNestToken->isGivenKind(T_WHILE)
  18391. && $tokensAnalyzer->isWhilePartOfDoWhile($nextNonWhitespaceNestIndex)
  18392. )
  18393. ) {
  18394. $whitespace = ' ';
  18395. } else {
  18396. $nextToken = $tokens[$nestIndex + 1];
  18397. $nextWhitespace = '';
  18398. if ($nextToken->isWhitespace()) {
  18399. $nextWhitespace = rtrim($nextToken->getContent(), " \t");
  18400. if ('' !== $nextWhitespace) {
  18401. $nextWhitespace = Preg::replace(
  18402. sprintf('/%s$/', $this->whitespacesConfig->getLineEnding()),
  18403. '',
  18404. $nextWhitespace,
  18405. 1
  18406. );
  18407. }
  18408. }
  18409. $whitespace = $nextWhitespace.$this->whitespacesConfig->getLineEnding().$indent;
  18410. if (!$nextNonWhitespaceNestToken->equals('}')) {
  18411. $determineIsIndentableBlockContent = static function ($contentIndex) use ($tokens) {
  18412. if (!$tokens[$contentIndex]->isComment()) {
  18413. return true;
  18414. }
  18415. if (!$tokens[$tokens->getPrevMeaningfulToken($contentIndex)]->equals(';')) {
  18416. return true;
  18417. }
  18418. $nextIndex = $tokens->getNextMeaningfulToken($contentIndex);
  18419. if (!$tokens[$nextIndex]->equals('}')) {
  18420. return true;
  18421. }
  18422. $nextNextIndex = $tokens->getNextMeaningfulToken($nextIndex);
  18423. if (null === $nextNextIndex) {
  18424. return true;
  18425. }
  18426. if ($tokens[$nextNextIndex]->equalsAny([
  18427. [T_ELSE],
  18428. [T_ELSEIF],
  18429. ',',
  18430. ])) {
  18431. return false;
  18432. }
  18433. return true;
  18434. };
  18435. if ($determineIsIndentableBlockContent($nestIndex + 2)) {
  18436. $whitespace .= $this->whitespacesConfig->getIndent();
  18437. }
  18438. }
  18439. }
  18440. $this->ensureWhitespaceAtIndexAndIndentMultilineComment($tokens, $nestIndex + 1, $whitespace);
  18441. }
  18442. }
  18443. if ($nestToken->equals('}')) {
  18444. ++$nestLevel;
  18445. continue;
  18446. }
  18447. if ($nestToken->equals('{')) {
  18448. --$nestLevel;
  18449. continue;
  18450. }
  18451. }
  18452. if (isset($tokens[$startBraceIndex + 2]) && $tokens[$startBraceIndex + 2]->equals('}')) {
  18453. $tokens->ensureWhitespaceAtIndex($startBraceIndex + 1, 0, $this->whitespacesConfig->getLineEnding().$indent);
  18454. } else {
  18455. $nextToken = $tokens[$startBraceIndex + 1];
  18456. $nextNonWhitespaceToken = $tokens[$tokens->getNextNonWhitespace($startBraceIndex)];
  18457. if (
  18458. !$nextNonWhitespaceToken->isComment()
  18459. || ($nextToken->isWhitespace() && 1 === substr_count($nextToken->getContent(), "\n"))
  18460. ) {
  18461. $this->ensureWhitespaceAtIndexAndIndentMultilineComment(
  18462. $tokens,
  18463. $startBraceIndex + 1,
  18464. $this->whitespacesConfig->getLineEnding().$indent.$this->whitespacesConfig->getIndent()
  18465. );
  18466. }
  18467. }
  18468. if ($token->isGivenKind($classyTokens) && !$tokensAnalyzer->isAnonymousClass($index)) {
  18469. if (self::LINE_SAME === $this->configuration['position_after_functions_and_oop_constructs'] && !$tokens[$tokens->getPrevNonWhitespace($startBraceIndex)]->isComment()) {
  18470. $ensuredWhitespace = ' ';
  18471. } else {
  18472. $ensuredWhitespace = $this->whitespacesConfig->getLineEnding().$indent;
  18473. }
  18474. $tokens->ensureWhitespaceAtIndex($startBraceIndex - 1, 1, $ensuredWhitespace);
  18475. } elseif (
  18476. $token->isGivenKind(T_FUNCTION) && !$tokensAnalyzer->isLambda($index)
  18477. || (
  18478. self::LINE_NEXT === $this->configuration['position_after_control_structures'] && $token->isGivenKind($controlTokens)
  18479. || (
  18480. self::LINE_NEXT === $this->configuration['position_after_anonymous_constructs']
  18481. && (
  18482. $token->isGivenKind(T_FUNCTION) && $tokensAnalyzer->isLambda($index)
  18483. || $token->isGivenKind(T_CLASS) && $tokensAnalyzer->isAnonymousClass($index)
  18484. )
  18485. )
  18486. )
  18487. ) {
  18488. $isAnonymousClass = $token->isGivenKind($classyTokens) && $tokensAnalyzer->isAnonymousClass($index);
  18489. $closingParenthesisIndex = $tokens->getPrevTokenOfKind($startBraceIndex, [')']);
  18490. if (null === $closingParenthesisIndex && !$isAnonymousClass) {
  18491. continue;
  18492. }
  18493. if (
  18494. !$isAnonymousClass
  18495. && $tokens[$closingParenthesisIndex - 1]->isWhitespace()
  18496. && false !== strpos($tokens[$closingParenthesisIndex - 1]->getContent(), "\n")
  18497. ) {
  18498. if (!$tokens[$startBraceIndex - 2]->isComment()) {
  18499. $tokens->ensureWhitespaceAtIndex($startBraceIndex - 1, 1, ' ');
  18500. }
  18501. } else {
  18502. if (
  18503. self::LINE_SAME === $this->configuration['position_after_functions_and_oop_constructs']
  18504. && (
  18505. $token->isGivenKind(T_FUNCTION) && !$tokensAnalyzer->isLambda($index)
  18506. || $token->isGivenKind($classyTokens) && !$tokensAnalyzer->isAnonymousClass($index)
  18507. )
  18508. && !$tokens[$tokens->getPrevNonWhitespace($startBraceIndex)]->isComment()
  18509. ) {
  18510. $ensuredWhitespace = ' ';
  18511. } else {
  18512. $ensuredWhitespace = $this->whitespacesConfig->getLineEnding().$indent;
  18513. }
  18514. $tokens->ensureWhitespaceAtIndex($startBraceIndex - 1, 1, $ensuredWhitespace);
  18515. }
  18516. } else {
  18517. $tokens->ensureWhitespaceAtIndex($startBraceIndex - 1, 1, ' ');
  18518. }
  18519. $limit = \count($tokens);
  18520. }
  18521. }
  18522. private function fixMissingControlBraces(Tokens $tokens)
  18523. {
  18524. $controlTokens = $this->getControlTokens();
  18525. for ($index = $tokens->count() - 1; 0 <= $index; --$index) {
  18526. $token = $tokens[$index];
  18527. if (!$token->isGivenKind($controlTokens)) {
  18528. continue;
  18529. }
  18530. $parenthesisEndIndex = $this->findParenthesisEnd($tokens, $index);
  18531. $nextAfterParenthesisEndIndex = $tokens->getNextMeaningfulToken($parenthesisEndIndex);
  18532. $tokenAfterParenthesis = $tokens[$nextAfterParenthesisEndIndex];
  18533. if ($tokenAfterParenthesis->equals('{') && self::LINE_SAME === $this->configuration['position_after_control_structures']) {
  18534. $tokens->ensureWhitespaceAtIndex($parenthesisEndIndex + 1, 0, ' ');
  18535. continue;
  18536. }
  18537. if ($tokenAfterParenthesis->equalsAny([';', '{', ':'])) {
  18538. continue;
  18539. }
  18540. if ($tokenAfterParenthesis->isGivenKind([T_FOR, T_FOREACH, T_SWITCH, T_WHILE])) {
  18541. $tokenAfterParenthesisBlockEnd = $tokens->findBlockEnd(
  18542. Tokens::BLOCK_TYPE_PARENTHESIS_BRACE,
  18543. $tokens->getNextMeaningfulToken($nextAfterParenthesisEndIndex)
  18544. );
  18545. if ($tokens[$tokens->getNextMeaningfulToken($tokenAfterParenthesisBlockEnd)]->equals(':')) {
  18546. continue;
  18547. }
  18548. }
  18549. $statementEndIndex = $this->findStatementEnd($tokens, $parenthesisEndIndex);
  18550. $tokens->insertAt($statementEndIndex + 1, [new Token([T_WHITESPACE, ' ']), new Token('}')]);
  18551. if (!$tokens[$statementEndIndex]->equalsAny([';', '}'])) {
  18552. $tokens->insertAt($statementEndIndex + 1, new Token(';'));
  18553. }
  18554. $tokens->insertAt($parenthesisEndIndex + 1, new Token('{'));
  18555. $tokens->ensureWhitespaceAtIndex($parenthesisEndIndex + 1, 0, ' ');
  18556. }
  18557. }
  18558. private function fixSpaceAroundToken(Tokens $tokens)
  18559. {
  18560. $controlTokens = $this->getControlTokens();
  18561. for ($index = $tokens->count() - 1; 0 <= $index; --$index) {
  18562. $token = $tokens[$index];
  18563. if ($token->isGivenKind(T_DECLARE)) {
  18564. $this->fixDeclareStatement($tokens, $index);
  18565. } elseif ($token->isGivenKind($controlTokens) || $token->isGivenKind(CT::T_USE_LAMBDA)) {
  18566. $nextNonWhitespaceIndex = $tokens->getNextNonWhitespace($index);
  18567. if (!$tokens[$nextNonWhitespaceIndex]->equals(':')) {
  18568. $tokens->ensureWhitespaceAtIndex(
  18569. $index + 1,
  18570. 0,
  18571. self::LINE_NEXT === $this->configuration['position_after_control_structures'] && !$tokens[$nextNonWhitespaceIndex]->equals('(') ?
  18572. $this->whitespacesConfig->getLineEnding().$this->detectIndent($tokens, $index)
  18573. : ' '
  18574. );
  18575. }
  18576. $prevToken = $tokens[$index - 1];
  18577. if (!$prevToken->isWhitespace() && !$prevToken->isComment() && !$prevToken->isGivenKind(T_OPEN_TAG)) {
  18578. $tokens->ensureWhitespaceAtIndex($index - 1, 1, ' ');
  18579. }
  18580. }
  18581. }
  18582. }
  18583. private function detectIndent(Tokens $tokens, $index)
  18584. {
  18585. while (true) {
  18586. $whitespaceIndex = $tokens->getPrevTokenOfKind($index, [[T_WHITESPACE]]);
  18587. if (null === $whitespaceIndex) {
  18588. return '';
  18589. }
  18590. $whitespaceToken = $tokens[$whitespaceIndex];
  18591. if (false !== strpos($whitespaceToken->getContent(), "\n")) {
  18592. break;
  18593. }
  18594. $prevToken = $tokens[$whitespaceIndex - 1];
  18595. if ($prevToken->isGivenKind([T_OPEN_TAG, T_COMMENT]) && "\n" === substr($prevToken->getContent(), -1)) {
  18596. break;
  18597. }
  18598. $index = $whitespaceIndex;
  18599. }
  18600. $explodedContent = explode("\n", $whitespaceToken->getContent());
  18601. return end($explodedContent);
  18602. }
  18603. private function findParenthesisEnd(Tokens $tokens, $structureTokenIndex)
  18604. {
  18605. $nextIndex = $tokens->getNextMeaningfulToken($structureTokenIndex);
  18606. $nextToken = $tokens[$nextIndex];
  18607. if (!$nextToken->equals('(')) {
  18608. return $structureTokenIndex;
  18609. }
  18610. return $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $nextIndex);
  18611. }
  18612. private function findStatementEnd(Tokens $tokens, $parenthesisEndIndex)
  18613. {
  18614. $nextIndex = $tokens->getNextMeaningfulToken($parenthesisEndIndex);
  18615. $nextToken = $tokens[$nextIndex];
  18616. if (!$nextToken) {
  18617. return $parenthesisEndIndex;
  18618. }
  18619. if ($nextToken->equals('{')) {
  18620. return $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $nextIndex);
  18621. }
  18622. if ($nextToken->isGivenKind($this->getControlTokens())) {
  18623. $parenthesisEndIndex = $this->findParenthesisEnd($tokens, $nextIndex);
  18624. $endIndex = $this->findStatementEnd($tokens, $parenthesisEndIndex);
  18625. if ($nextToken->isGivenKind([T_IF, T_TRY, T_DO])) {
  18626. $openingTokenKind = $nextToken->getId();
  18627. while (true) {
  18628. $nextIndex = $tokens->getNextMeaningfulToken($endIndex);
  18629. $nextToken = isset($nextIndex) ? $tokens[$nextIndex] : null;
  18630. if ($nextToken && $nextToken->isGivenKind($this->getControlContinuationTokensForOpeningToken($openingTokenKind))) {
  18631. $parenthesisEndIndex = $this->findParenthesisEnd($tokens, $nextIndex);
  18632. $endIndex = $this->findStatementEnd($tokens, $parenthesisEndIndex);
  18633. if ($nextToken->isGivenKind($this->getFinalControlContinuationTokensForOpeningToken($openingTokenKind))) {
  18634. return $endIndex;
  18635. }
  18636. } else {
  18637. break;
  18638. }
  18639. }
  18640. }
  18641. return $endIndex;
  18642. }
  18643. $index = $parenthesisEndIndex;
  18644. while (true) {
  18645. $token = $tokens[++$index];
  18646. if ($token->equals('{')) {
  18647. $index = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $index);
  18648. continue;
  18649. }
  18650. if ($token->equals(';')) {
  18651. return $index;
  18652. }
  18653. if ($token->isGivenKind(T_CLOSE_TAG)) {
  18654. return $tokens->getPrevNonWhitespace($index);
  18655. }
  18656. }
  18657. }
  18658. private function getControlTokens()
  18659. {
  18660. static $tokens = [
  18661. T_DECLARE,
  18662. T_DO,
  18663. T_ELSE,
  18664. T_ELSEIF,
  18665. T_FINALLY,
  18666. T_FOR,
  18667. T_FOREACH,
  18668. T_IF,
  18669. T_WHILE,
  18670. T_TRY,
  18671. T_CATCH,
  18672. T_SWITCH,
  18673. ];
  18674. return $tokens;
  18675. }
  18676. private function getControlContinuationTokens()
  18677. {
  18678. static $tokens = [
  18679. T_CATCH,
  18680. T_ELSE,
  18681. T_ELSEIF,
  18682. T_FINALLY,
  18683. ];
  18684. return $tokens;
  18685. }
  18686. private function getControlContinuationTokensForOpeningToken($openingTokenKind)
  18687. {
  18688. if (T_IF === $openingTokenKind) {
  18689. return [
  18690. T_ELSE,
  18691. T_ELSEIF,
  18692. ];
  18693. }
  18694. if (T_DO === $openingTokenKind) {
  18695. return [T_WHILE];
  18696. }
  18697. if (T_TRY === $openingTokenKind) {
  18698. return [
  18699. T_CATCH,
  18700. T_FINALLY,
  18701. ];
  18702. }
  18703. return [];
  18704. }
  18705. private function getFinalControlContinuationTokensForOpeningToken($openingTokenKind)
  18706. {
  18707. if (T_IF === $openingTokenKind) {
  18708. return [T_ELSE];
  18709. }
  18710. if (T_TRY === $openingTokenKind) {
  18711. return [T_FINALLY];
  18712. }
  18713. return [];
  18714. }
  18715. private function fixDeclareStatement(Tokens $tokens, $index)
  18716. {
  18717. $tokens->removeTrailingWhitespace($index);
  18718. $startParenthesisIndex = $tokens->getNextTokenOfKind($index, ['(']);
  18719. $tokens->removeTrailingWhitespace($startParenthesisIndex);
  18720. $endParenthesisIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $startParenthesisIndex);
  18721. $tokens->removeLeadingWhitespace($endParenthesisIndex);
  18722. $startBraceIndex = $tokens->getNextTokenOfKind($endParenthesisIndex, [';', '{']);
  18723. $startBraceToken = $tokens[$startBraceIndex];
  18724. if ($startBraceToken->equals('{')) {
  18725. $this->fixSingleLineWhitespaceForDeclare($tokens, $startBraceIndex);
  18726. }
  18727. }
  18728. private function fixSingleLineWhitespaceForDeclare(Tokens $tokens, $startBraceIndex)
  18729. {
  18730. if (
  18731. !$tokens[$startBraceIndex - 1]->isWhitespace() ||
  18732. $tokens[$startBraceIndex - 1]->isWhitespace(" \t")
  18733. ) {
  18734. $tokens->ensureWhitespaceAtIndex($startBraceIndex - 1, 1, ' ');
  18735. }
  18736. }
  18737. private function ensureWhitespaceAtIndexAndIndentMultilineComment(Tokens $tokens, $index, $whitespace)
  18738. {
  18739. if ($tokens[$index]->isWhitespace()) {
  18740. $nextTokenIndex = $tokens->getNextNonWhitespace($index);
  18741. } else {
  18742. $nextTokenIndex = $index;
  18743. }
  18744. $nextToken = $tokens[$nextTokenIndex];
  18745. if ($nextToken->isComment()) {
  18746. $previousToken = $tokens[$nextTokenIndex - 1];
  18747. $nextTokenContent = $nextToken->getContent();
  18748. if (
  18749. $previousToken->isWhitespace()
  18750. && 1 === Preg::match('/\R$/', $previousToken->getContent())
  18751. && (
  18752. (0 === strpos($nextTokenContent, '//'.$this->whitespacesConfig->getIndent()) || '//' === $nextTokenContent)
  18753. || (0 === strpos($nextTokenContent, '#'.$this->whitespacesConfig->getIndent()) || '#' === $nextTokenContent)
  18754. )
  18755. ) {
  18756. return;
  18757. }
  18758. $tokens[$nextTokenIndex] = new Token([
  18759. $nextToken->getId(),
  18760. Preg::replace(
  18761. '/(\R)'.$this->detectIndent($tokens, $nextTokenIndex).'(\h*\S+.*)/',
  18762. '$1'.Preg::replace('/^.*\R(\h*)$/s', '$1', $whitespace).'$2',
  18763. $nextToken->getContent()
  18764. ),
  18765. ]);
  18766. }
  18767. $tokens->ensureWhitespaceAtIndex($index, 0, $whitespace);
  18768. }
  18769. private function isMultilined(Tokens $tokens, $startParenthesisIndex, $endParenthesisIndex)
  18770. {
  18771. for ($i = $startParenthesisIndex; $i < $endParenthesisIndex; ++$i) {
  18772. if (false !== strpos($tokens[$i]->getContent(), "\n")) {
  18773. return true;
  18774. }
  18775. }
  18776. return false;
  18777. }
  18778. private function isCommentWithFixableIndentation(Tokens $tokens, $index)
  18779. {
  18780. if (!$tokens[$index]->isComment()) {
  18781. return false;
  18782. }
  18783. if (0 === strpos($tokens[$index]->getContent(), '/*')) {
  18784. return true;
  18785. }
  18786. $firstCommentIndex = $index;
  18787. while (true) {
  18788. $i = $this->getSiblingContinuousSingleLineComment($tokens, $firstCommentIndex, false);
  18789. if (null === $i) {
  18790. break;
  18791. }
  18792. $firstCommentIndex = $i;
  18793. }
  18794. $lastCommentIndex = $index;
  18795. while (true) {
  18796. $i = $this->getSiblingContinuousSingleLineComment($tokens, $lastCommentIndex, true);
  18797. if (null === $i) {
  18798. break;
  18799. }
  18800. $lastCommentIndex = $i;
  18801. }
  18802. if ($firstCommentIndex === $lastCommentIndex) {
  18803. return true;
  18804. }
  18805. for ($i = $firstCommentIndex + 1; $i < $lastCommentIndex; ++$i) {
  18806. if (!$tokens[$i]->isWhitespace() && !$tokens[$i]->isComment()) {
  18807. return false;
  18808. }
  18809. }
  18810. return true;
  18811. }
  18812. private function getSiblingContinuousSingleLineComment(Tokens $tokens, $index, $after)
  18813. {
  18814. $siblingIndex = $index;
  18815. do {
  18816. if ($after) {
  18817. $siblingIndex = $tokens->getNextTokenOfKind($siblingIndex, [[T_COMMENT]]);
  18818. } else {
  18819. $siblingIndex = $tokens->getPrevTokenOfKind($siblingIndex, [[T_COMMENT]]);
  18820. }
  18821. if (null === $siblingIndex) {
  18822. return null;
  18823. }
  18824. } while (0 === strpos($tokens[$siblingIndex]->getContent(), '/*'));
  18825. $newLines = 0;
  18826. for ($i = min($siblingIndex, $index) + 1, $max = max($siblingIndex, $index); $i < $max; ++$i) {
  18827. if ($tokens[$i]->isWhitespace() && Preg::match('/\R/', $tokens[$i]->getContent())) {
  18828. if (1 === $newLines || Preg::match('/\R.*\R/', $tokens[$i]->getContent())) {
  18829. return null;
  18830. }
  18831. ++$newLines;
  18832. }
  18833. }
  18834. return $siblingIndex;
  18835. }
  18836. }
  18837. <?php
  18838. namespace PhpCsFixer\Fixer\Basic;
  18839. use PhpCsFixer\AbstractFixer;
  18840. use PhpCsFixer\FixerDefinition\CodeSample;
  18841. use PhpCsFixer\FixerDefinition\FixerDefinition;
  18842. use PhpCsFixer\Tokenizer\Token;
  18843. use PhpCsFixer\Tokenizer\Tokens;
  18844. final class EncodingFixer extends AbstractFixer
  18845. {
  18846. private $BOM;
  18847. public function __construct()
  18848. {
  18849. parent::__construct();
  18850. $this->BOM = pack('CCC', 0xef, 0xbb, 0xbf);
  18851. }
  18852. public function getDefinition()
  18853. {
  18854. return new FixerDefinition(
  18855. 'PHP code MUST use only UTF-8 without BOM (remove BOM).',
  18856. [
  18857. new CodeSample(
  18858. $this->BOM.'<?php
  18859. echo "Hello!";
  18860. '
  18861. ),
  18862. ]
  18863. );
  18864. }
  18865. public function getPriority()
  18866. {
  18867. return 100;
  18868. }
  18869. public function isCandidate(Tokens $tokens)
  18870. {
  18871. return true;
  18872. }
  18873. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  18874. {
  18875. $content = $tokens[0]->getContent();
  18876. if (0 === strncmp($content, $this->BOM, 3)) {
  18877. $newContent = substr($content, 3);
  18878. if (false === $newContent) {
  18879. $newContent = '';
  18880. }
  18881. if ('' === $newContent) {
  18882. $tokens->clearAt(0);
  18883. } else {
  18884. $tokens[0] = new Token([$tokens[0]->getId(), $newContent]);
  18885. }
  18886. }
  18887. }
  18888. }
  18889. <?php
  18890. namespace PhpCsFixer\Fixer\Semicolon;
  18891. use PhpCsFixer\AbstractFixer;
  18892. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  18893. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  18894. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  18895. use PhpCsFixer\FixerDefinition\CodeSample;
  18896. use PhpCsFixer\FixerDefinition\FixerDefinition;
  18897. use PhpCsFixer\Preg;
  18898. use PhpCsFixer\Tokenizer\Token;
  18899. use PhpCsFixer\Tokenizer\Tokens;
  18900. final class SpaceAfterSemicolonFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface
  18901. {
  18902. public function getDefinition()
  18903. {
  18904. return new FixerDefinition(
  18905. 'Fix whitespace after a semicolon.',
  18906. [
  18907. new CodeSample(
  18908. "<?php
  18909. sample(); \$test = 1;
  18910. sample();\$test = 2;
  18911. for ( ;;++\$sample) {
  18912. }\n"
  18913. ),
  18914. new CodeSample("<?php\nfor (\$i = 0; ; ++\$i) {\n}\n", [
  18915. 'remove_in_empty_for_expressions' => true,
  18916. ]),
  18917. ]
  18918. );
  18919. }
  18920. public function getPriority()
  18921. {
  18922. return -1;
  18923. }
  18924. public function isCandidate(Tokens $tokens)
  18925. {
  18926. return $tokens->isTokenKindFound(';');
  18927. }
  18928. protected function createConfigurationDefinition()
  18929. {
  18930. return new FixerConfigurationResolver([
  18931. (new FixerOptionBuilder('remove_in_empty_for_expressions', 'Whether spaces should be removed for empty `for` expressions.'))
  18932. ->setAllowedTypes(['bool'])
  18933. ->setDefault(false)
  18934. ->getOption(),
  18935. ]);
  18936. }
  18937. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  18938. {
  18939. $insideForParenthesesUntil = null;
  18940. for ($index = 0, $max = \count($tokens) - 1; $index < $max; ++$index) {
  18941. if ($this->configuration['remove_in_empty_for_expressions']) {
  18942. if ($tokens[$index]->isGivenKind(T_FOR)) {
  18943. $index = $tokens->getNextMeaningfulToken($index);
  18944. $insideForParenthesesUntil = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $index);
  18945. continue;
  18946. }
  18947. if ($index === $insideForParenthesesUntil) {
  18948. $insideForParenthesesUntil = null;
  18949. continue;
  18950. }
  18951. }
  18952. if (!$tokens[$index]->equals(';')) {
  18953. continue;
  18954. }
  18955. if (!$tokens[$index + 1]->isWhitespace()) {
  18956. if (
  18957. !$tokens[$index + 1]->equalsAny([')', [T_INLINE_HTML]]) && (
  18958. !$this->configuration['remove_in_empty_for_expressions']
  18959. || !$tokens[$index + 1]->equals(';')
  18960. )
  18961. ) {
  18962. $tokens->insertAt($index + 1, new Token([T_WHITESPACE, ' ']));
  18963. ++$max;
  18964. }
  18965. continue;
  18966. }
  18967. if (
  18968. null !== $insideForParenthesesUntil
  18969. && ($tokens[$index + 2]->equals(';') || $index + 2 === $insideForParenthesesUntil)
  18970. && !Preg::match('/\R/', $tokens[$index + 1]->getContent())
  18971. ) {
  18972. $tokens->clearAt($index + 1);
  18973. continue;
  18974. }
  18975. if (
  18976. isset($tokens[$index + 2])
  18977. && !$tokens[$index + 1]->equals([T_WHITESPACE, ' '])
  18978. && $tokens[$index + 1]->isWhitespace(" \t")
  18979. && !$tokens[$index + 2]->isComment()
  18980. && !$tokens[$index + 2]->equals(')')
  18981. ) {
  18982. $tokens[$index + 1] = new Token([T_WHITESPACE, ' ']);
  18983. }
  18984. }
  18985. }
  18986. }
  18987. <?php
  18988. namespace PhpCsFixer\Fixer\Semicolon;
  18989. use PhpCsFixer\AbstractFixer;
  18990. use PhpCsFixer\FixerDefinition\CodeSample;
  18991. use PhpCsFixer\FixerDefinition\FixerDefinition;
  18992. use PhpCsFixer\Tokenizer\Tokens;
  18993. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  18994. final class NoEmptyStatementFixer extends AbstractFixer
  18995. {
  18996. public function getDefinition()
  18997. {
  18998. return new FixerDefinition(
  18999. 'Remove useless semicolon statements.',
  19000. [new CodeSample("<?php \$a = 1;;\n")]
  19001. );
  19002. }
  19003. public function getPriority()
  19004. {
  19005. return 26;
  19006. }
  19007. public function isCandidate(Tokens $tokens)
  19008. {
  19009. return $tokens->isTokenKindFound(';');
  19010. }
  19011. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  19012. {
  19013. for ($index = 0, $count = $tokens->count(); $index < $count; ++$index) {
  19014. if ($tokens[$index]->isGivenKind(T_FOR)) {
  19015. $index = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $tokens->getNextMeaningfulToken($index)) + 1;
  19016. continue;
  19017. }
  19018. if (!$tokens[$index]->equals(';')) {
  19019. continue;
  19020. }
  19021. $previousMeaningfulIndex = $tokens->getPrevMeaningfulToken($index);
  19022. if ($tokens[$previousMeaningfulIndex]->equalsAny(['{', ';', [T_OPEN_TAG]])) {
  19023. $tokens->clearTokenAndMergeSurroundingWhitespace($index);
  19024. continue;
  19025. }
  19026. if ($tokens[$previousMeaningfulIndex]->equals('}')) {
  19027. $this->fixSemicolonAfterCurlyBraceClose($tokens, $index, $previousMeaningfulIndex);
  19028. }
  19029. }
  19030. }
  19031. private function fixSemicolonAfterCurlyBraceClose(Tokens $tokens, $index, $curlyCloseIndex)
  19032. {
  19033. static $beforeCurlyOpeningKinds = null;
  19034. if (null === $beforeCurlyOpeningKinds) {
  19035. $beforeCurlyOpeningKinds = [T_ELSE, T_FINALLY, T_NAMESPACE, T_OPEN_TAG];
  19036. }
  19037. $curlyOpeningIndex = $tokens->findBlockStart(Tokens::BLOCK_TYPE_CURLY_BRACE, $curlyCloseIndex);
  19038. $beforeCurlyOpening = $tokens->getPrevMeaningfulToken($curlyOpeningIndex);
  19039. if ($tokens[$beforeCurlyOpening]->isGivenKind($beforeCurlyOpeningKinds) || $tokens[$beforeCurlyOpening]->equalsAny([';', '{', '}'])) {
  19040. $tokens->clearTokenAndMergeSurroundingWhitespace($index);
  19041. return;
  19042. }
  19043. if ($tokens[$beforeCurlyOpening]->isGivenKind(T_STRING)) {
  19044. $classyTest = $tokens->getPrevMeaningfulToken($beforeCurlyOpening);
  19045. while ($tokens[$classyTest]->equals(',') || $tokens[$classyTest]->isGivenKind([T_STRING, T_NS_SEPARATOR, T_EXTENDS, T_IMPLEMENTS])) {
  19046. $classyTest = $tokens->getPrevMeaningfulToken($classyTest);
  19047. }
  19048. $tokensAnalyzer = new TokensAnalyzer($tokens);
  19049. if (
  19050. $tokens[$classyTest]->isGivenKind(T_NAMESPACE) ||
  19051. ($tokens[$classyTest]->isClassy() && !$tokensAnalyzer->isAnonymousClass($classyTest))
  19052. ) {
  19053. $tokens->clearTokenAndMergeSurroundingWhitespace($index);
  19054. }
  19055. return;
  19056. }
  19057. if (!$tokens[$beforeCurlyOpening]->equals(')')) {
  19058. return;
  19059. }
  19060. $openingBrace = $tokens->findBlockStart(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $beforeCurlyOpening);
  19061. $beforeOpeningBrace = $tokens->getPrevMeaningfulToken($openingBrace);
  19062. if ($tokens[$beforeOpeningBrace]->isGivenKind([T_IF, T_ELSEIF, T_FOR, T_FOREACH, T_WHILE, T_SWITCH, T_CATCH, T_DECLARE])) {
  19063. $tokens->clearTokenAndMergeSurroundingWhitespace($index);
  19064. return;
  19065. }
  19066. if ($tokens[$beforeOpeningBrace]->isGivenKind(T_STRING)) {
  19067. $beforeString = $tokens->getPrevMeaningfulToken($beforeOpeningBrace);
  19068. if ($tokens[$beforeString]->isGivenKind(T_FUNCTION)) {
  19069. $tokens->clearTokenAndMergeSurroundingWhitespace($index);
  19070. }
  19071. }
  19072. }
  19073. }
  19074. <?php
  19075. namespace PhpCsFixer\Fixer\Semicolon;
  19076. use PhpCsFixer\AbstractFixer;
  19077. use PhpCsFixer\FixerDefinition\CodeSample;
  19078. use PhpCsFixer\FixerDefinition\FixerDefinition;
  19079. use PhpCsFixer\Tokenizer\Token;
  19080. use PhpCsFixer\Tokenizer\Tokens;
  19081. final class NoSinglelineWhitespaceBeforeSemicolonsFixer extends AbstractFixer
  19082. {
  19083. public function getDefinition()
  19084. {
  19085. return new FixerDefinition(
  19086. 'Single-line whitespace before closing semicolon are prohibited.',
  19087. [new CodeSample("<?php \$this->foo() ;\n")]
  19088. );
  19089. }
  19090. public function getPriority()
  19091. {
  19092. return 0;
  19093. }
  19094. public function isCandidate(Tokens $tokens)
  19095. {
  19096. return $tokens->isTokenKindFound(';');
  19097. }
  19098. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  19099. {
  19100. foreach ($tokens as $index => $token) {
  19101. if (!$token->equals(';') || !$tokens[$index - 1]->isWhitespace(" \t")) {
  19102. continue;
  19103. }
  19104. if ($tokens[$index - 2]->equals(';')) {
  19105. if (!$tokens[$index - 1]->equals(' ')) {
  19106. $tokens[$index - 1] = new Token([T_WHITESPACE, ' ']);
  19107. }
  19108. } elseif (!$tokens[$index - 2]->isComment()) {
  19109. $tokens->clearAt($index - 1);
  19110. }
  19111. }
  19112. }
  19113. }
  19114. <?php
  19115. namespace PhpCsFixer\Fixer\Semicolon;
  19116. use PhpCsFixer\AbstractFixer;
  19117. use PhpCsFixer\FixerDefinition\CodeSample;
  19118. use PhpCsFixer\FixerDefinition\FixerDefinition;
  19119. use PhpCsFixer\Tokenizer\Token;
  19120. use PhpCsFixer\Tokenizer\Tokens;
  19121. final class SemicolonAfterInstructionFixer extends AbstractFixer
  19122. {
  19123. public function getDefinition()
  19124. {
  19125. return new FixerDefinition(
  19126. 'Instructions must be terminated with a semicolon.',
  19127. [new CodeSample("<?php echo 1 ?>\n")]
  19128. );
  19129. }
  19130. public function isCandidate(Tokens $tokens)
  19131. {
  19132. return $tokens->isTokenKindFound(T_CLOSE_TAG);
  19133. }
  19134. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  19135. {
  19136. for ($index = \count($tokens) - 1; $index > 1; --$index) {
  19137. if (!$tokens[$index]->isGivenKind(T_CLOSE_TAG)) {
  19138. continue;
  19139. }
  19140. $prev = $tokens->getPrevMeaningfulToken($index);
  19141. if ($tokens[$prev]->equalsAny([';', '{', '}', ':', [T_OPEN_TAG]])) {
  19142. continue;
  19143. }
  19144. $tokens->insertAt($prev + 1, new Token(';'));
  19145. }
  19146. }
  19147. }
  19148. <?php
  19149. namespace PhpCsFixer\Fixer\Semicolon;
  19150. use PhpCsFixer\AbstractProxyFixer;
  19151. use PhpCsFixer\Fixer\DeprecatedFixerInterface;
  19152. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  19153. use PhpCsFixer\FixerDefinition\CodeSample;
  19154. use PhpCsFixer\FixerDefinition\FixerDefinition;
  19155. final class NoMultilineWhitespaceBeforeSemicolonsFixer extends AbstractProxyFixer implements DeprecatedFixerInterface, WhitespacesAwareFixerInterface
  19156. {
  19157. public function getDefinition()
  19158. {
  19159. return new FixerDefinition(
  19160. 'Multi-line whitespace before closing semicolon are prohibited.',
  19161. [
  19162. new CodeSample(
  19163. '<?php
  19164. function foo () {
  19165. return 1 + 2
  19166. ;
  19167. }
  19168. '
  19169. ),
  19170. ]
  19171. );
  19172. }
  19173. public function getSuccessorsNames()
  19174. {
  19175. return array_keys($this->proxyFixers);
  19176. }
  19177. protected function createProxyFixers()
  19178. {
  19179. $fixer = new MultilineWhitespaceBeforeSemicolonsFixer();
  19180. $fixer->configure(['strategy' => MultilineWhitespaceBeforeSemicolonsFixer::STRATEGY_NO_MULTI_LINE]);
  19181. return [$fixer];
  19182. }
  19183. }
  19184. <?php
  19185. namespace PhpCsFixer\Fixer\Semicolon;
  19186. use PhpCsFixer\AbstractFixer;
  19187. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  19188. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  19189. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  19190. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  19191. use PhpCsFixer\FixerDefinition\CodeSample;
  19192. use PhpCsFixer\FixerDefinition\FixerDefinition;
  19193. use PhpCsFixer\Preg;
  19194. use PhpCsFixer\Tokenizer\Token;
  19195. use PhpCsFixer\Tokenizer\Tokens;
  19196. /**
  19197. @gmail
  19198. */
  19199. final class MultilineWhitespaceBeforeSemicolonsFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface, WhitespacesAwareFixerInterface
  19200. {
  19201. const STRATEGY_NO_MULTI_LINE = 'no_multi_line';
  19202. const STRATEGY_NEW_LINE_FOR_CHAINED_CALLS = 'new_line_for_chained_calls';
  19203. public function getDefinition()
  19204. {
  19205. return new FixerDefinition(
  19206. 'Forbid multi-line whitespace before the closing semicolon or move the semicolon to the new line for chained calls.',
  19207. [
  19208. new CodeSample(
  19209. '<?php
  19210. function foo () {
  19211. return 1 + 2
  19212. ;
  19213. }
  19214. '
  19215. ),
  19216. new CodeSample(
  19217. '<?php
  19218. $this->method1()
  19219. ->method2()
  19220. ->method(3);
  19221. ?>
  19222. ',
  19223. ['strategy' => self::STRATEGY_NEW_LINE_FOR_CHAINED_CALLS]
  19224. ),
  19225. ]
  19226. );
  19227. }
  19228. public function getPriority()
  19229. {
  19230. return 0;
  19231. }
  19232. public function isCandidate(Tokens $tokens)
  19233. {
  19234. return $tokens->isTokenKindFound(';');
  19235. }
  19236. protected function createConfigurationDefinition()
  19237. {
  19238. return new FixerConfigurationResolver([
  19239. (new FixerOptionBuilder(
  19240. 'strategy',
  19241. 'Forbid multi-line whitespace or move the semicolon to the new line for chained calls.'
  19242. ))
  19243. ->setAllowedValues([self::STRATEGY_NO_MULTI_LINE, self::STRATEGY_NEW_LINE_FOR_CHAINED_CALLS])
  19244. ->setDefault(self::STRATEGY_NO_MULTI_LINE)
  19245. ->getOption(),
  19246. ]);
  19247. }
  19248. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  19249. {
  19250. if (self::STRATEGY_NEW_LINE_FOR_CHAINED_CALLS === $this->configuration['strategy']) {
  19251. $this->applyChainedCallsFix($tokens);
  19252. return;
  19253. }
  19254. if (self::STRATEGY_NO_MULTI_LINE === $this->configuration['strategy']) {
  19255. $this->applyNoMultiLineFix($tokens);
  19256. }
  19257. }
  19258. private function applyNoMultiLineFix(Tokens $tokens)
  19259. {
  19260. $lineEnding = $this->whitespacesConfig->getLineEnding();
  19261. foreach ($tokens as $index => $token) {
  19262. if (!$token->equals(';')) {
  19263. continue;
  19264. }
  19265. $previousIndex = $index - 1;
  19266. $previous = $tokens[$previousIndex];
  19267. if (!$previous->isWhitespace() || false === strpos($previous->getContent(), "\n")) {
  19268. continue;
  19269. }
  19270. $content = $previous->getContent();
  19271. if (0 === strpos($content, $lineEnding) && $tokens[$index - 2]->isComment()) {
  19272. $tokens->ensureWhitespaceAtIndex($previousIndex, 0, $lineEnding);
  19273. } else {
  19274. $tokens->clearAt($previousIndex);
  19275. }
  19276. }
  19277. }
  19278. private function applyChainedCallsFix(Tokens $tokens)
  19279. {
  19280. for ($index = \count($tokens) - 1; $index >= 0; --$index) {
  19281. if (!$tokens[$index]->equals(';')) {
  19282. continue;
  19283. }
  19284. $indent = $this->findWhitespaceBeforeFirstCall($index - 1, $tokens);
  19285. if (null === $indent) {
  19286. continue;
  19287. }
  19288. $tokens->clearAt($index);
  19289. $index = $this->getNewLineIndex($index, $tokens);
  19290. $lineEnding = $this->whitespacesConfig->getLineEnding();
  19291. $newline = new Token([T_WHITESPACE, $lineEnding.$indent]);
  19292. $tokens->insertAt($index, [$newline, new Token(';')]);
  19293. }
  19294. }
  19295. private function getNewLineIndex($index, Tokens $tokens)
  19296. {
  19297. $lineEnding = $this->whitespacesConfig->getLineEnding();
  19298. for ($index, $count = \count($tokens); $index < $count; ++$index) {
  19299. if (false !== strstr($tokens[$index]->getContent(), $lineEnding)) {
  19300. return $index;
  19301. }
  19302. }
  19303. return $index;
  19304. }
  19305. private function findWhitespaceBeforeFirstCall($index, Tokens $tokens)
  19306. {
  19307. if (!$tokens[$index]->equals(')')) {
  19308. return null;
  19309. }
  19310. $openingBrackets = 1;
  19311. for (--$index; $index > 0; --$index) {
  19312. if ($tokens[$index]->equals(')')) {
  19313. ++$openingBrackets;
  19314. continue;
  19315. }
  19316. if ($tokens[$index]->equals('(')) {
  19317. if (1 === $openingBrackets) {
  19318. break;
  19319. }
  19320. --$openingBrackets;
  19321. }
  19322. }
  19323. if (!$tokens[--$index]->isGivenKind(T_STRING)) {
  19324. return null;
  19325. }
  19326. if (!$tokens[--$index]->isGivenKind([T_OBJECT_OPERATOR, T_DOUBLE_COLON])) {
  19327. return null;
  19328. }
  19329. if (!$tokens[--$index]->isGivenKind(T_WHITESPACE)) {
  19330. return null;
  19331. }
  19332. $closingBrackets = 0;
  19333. for ($index; $index >= 0; --$index) {
  19334. if ($tokens[$index]->equals(')')) {
  19335. ++$closingBrackets;
  19336. }
  19337. if ($tokens[$index]->equals('(')) {
  19338. --$closingBrackets;
  19339. }
  19340. if ($tokens[$index]->isGivenKind([T_VARIABLE, T_RETURN, T_STRING]) && 0 === $closingBrackets) {
  19341. if ($tokens[--$index]->isGivenKind(T_WHITESPACE)
  19342. || $tokens[$index]->isGivenKind(T_OPEN_TAG)) {
  19343. return $this->getIndentAt($tokens, $index);
  19344. }
  19345. }
  19346. }
  19347. return null;
  19348. }
  19349. private function getIndentAt(Tokens $tokens, $index)
  19350. {
  19351. $content = '';
  19352. $lineEnding = $this->whitespacesConfig->getLineEnding();
  19353. for ($index; $index > 0; --$index) {
  19354. if (false !== strstr($tokens[$index]->getContent(), $lineEnding)) {
  19355. break;
  19356. }
  19357. }
  19358. if ($tokens[$index]->isWhitespace()) {
  19359. $content = $tokens[$index]->getContent();
  19360. --$index;
  19361. }
  19362. if ($tokens[$index]->isGivenKind(T_OPEN_TAG)) {
  19363. $content = $tokens[$index]->getContent().$content;
  19364. }
  19365. if (1 === Preg::match('/\R{1}(\h*)$/', $content, $matches)) {
  19366. return $matches[1];
  19367. }
  19368. return null;
  19369. }
  19370. }
  19371. <?php
  19372. namespace PhpCsFixer\Fixer;
  19373. use PhpCsFixer\WhitespacesFixerConfig;
  19374. interface WhitespacesAwareFixerInterface extends FixerInterface
  19375. {
  19376. public function setWhitespacesConfig(WhitespacesFixerConfig $config);
  19377. }
  19378. <?php
  19379. namespace PhpCsFixer\Fixer;
  19380. interface DeprecatedFixerInterface extends FixerInterface
  19381. {
  19382. public function getSuccessorsNames();
  19383. }
  19384. <?php
  19385. namespace PhpCsFixer\Fixer\ArrayNotation;
  19386. use PhpCsFixer\AbstractFixer;
  19387. use PhpCsFixer\FixerDefinition\CodeSample;
  19388. use PhpCsFixer\FixerDefinition\FixerDefinition;
  19389. use PhpCsFixer\Tokenizer\CT;
  19390. use PhpCsFixer\Tokenizer\Token;
  19391. use PhpCsFixer\Tokenizer\Tokens;
  19392. final class WhitespaceAfterCommaInArrayFixer extends AbstractFixer
  19393. {
  19394. public function getDefinition()
  19395. {
  19396. return new FixerDefinition(
  19397. 'In array declaration, there MUST be a whitespace after each comma.',
  19398. [new CodeSample("<?php\n\$sample = array(1,'a',\$b,);\n")]
  19399. );
  19400. }
  19401. public function isCandidate(Tokens $tokens)
  19402. {
  19403. return $tokens->isAnyTokenKindsFound([T_ARRAY, CT::T_ARRAY_SQUARE_BRACE_OPEN]);
  19404. }
  19405. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  19406. {
  19407. for ($index = $tokens->count() - 1; $index >= 0; --$index) {
  19408. if ($tokens[$index]->isGivenKind([T_ARRAY, CT::T_ARRAY_SQUARE_BRACE_OPEN])) {
  19409. $this->fixSpacing($index, $tokens);
  19410. }
  19411. }
  19412. }
  19413. private function fixSpacing($index, Tokens $tokens)
  19414. {
  19415. if ($tokens[$index]->isGivenKind(CT::T_ARRAY_SQUARE_BRACE_OPEN)) {
  19416. $startIndex = $index;
  19417. $endIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_ARRAY_SQUARE_BRACE, $startIndex);
  19418. } else {
  19419. $startIndex = $tokens->getNextTokenOfKind($index, ['(']);
  19420. $endIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $startIndex);
  19421. }
  19422. for ($i = $endIndex - 1; $i > $startIndex; --$i) {
  19423. $i = $this->skipNonArrayElements($i, $tokens);
  19424. if ($tokens[$i]->equals(',') && !$tokens[$i + 1]->isWhitespace()) {
  19425. $tokens->insertAt($i + 1, new Token([T_WHITESPACE, ' ']));
  19426. }
  19427. }
  19428. }
  19429. private function skipNonArrayElements($index, Tokens $tokens)
  19430. {
  19431. if ($tokens[$index]->equals('}')) {
  19432. return $tokens->findBlockStart(Tokens::BLOCK_TYPE_CURLY_BRACE, $index);
  19433. }
  19434. if ($tokens[$index]->equals(')')) {
  19435. $startIndex = $tokens->findBlockStart(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $index);
  19436. $startIndex = $tokens->getPrevMeaningfulToken($startIndex);
  19437. if (!$tokens[$startIndex]->isGivenKind([T_ARRAY, CT::T_ARRAY_SQUARE_BRACE_OPEN])) {
  19438. return $startIndex;
  19439. }
  19440. }
  19441. return $index;
  19442. }
  19443. }
  19444. <?php
  19445. namespace PhpCsFixer\Fixer\ArrayNotation;
  19446. use PhpCsFixer\AbstractFixer;
  19447. use PhpCsFixer\FixerDefinition\CodeSample;
  19448. use PhpCsFixer\FixerDefinition\FixerDefinition;
  19449. use PhpCsFixer\Tokenizer\CT;
  19450. use PhpCsFixer\Tokenizer\Tokens;
  19451. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  19452. /**
  19453. @rollerscapes
  19454. */
  19455. final class NoTrailingCommaInSinglelineArrayFixer extends AbstractFixer
  19456. {
  19457. public function getDefinition()
  19458. {
  19459. return new FixerDefinition(
  19460. 'PHP single-line arrays should not have trailing comma.',
  19461. [new CodeSample("<?php\n\$a = array('sample', );\n")]
  19462. );
  19463. }
  19464. public function isCandidate(Tokens $tokens)
  19465. {
  19466. return $tokens->isAnyTokenKindsFound([T_ARRAY, CT::T_ARRAY_SQUARE_BRACE_OPEN]);
  19467. }
  19468. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  19469. {
  19470. $tokensAnalyzer = new TokensAnalyzer($tokens);
  19471. for ($index = 0, $c = $tokens->count(); $index < $c; ++$index) {
  19472. if ($tokensAnalyzer->isArray($index)) {
  19473. $this->fixArray($tokens, $index);
  19474. }
  19475. }
  19476. }
  19477. private function fixArray(Tokens $tokens, $index)
  19478. {
  19479. $tokensAnalyzer = new TokensAnalyzer($tokens);
  19480. if ($tokensAnalyzer->isArrayMultiLine($index)) {
  19481. return;
  19482. }
  19483. $startIndex = $index;
  19484. if ($tokens[$startIndex]->isGivenKind(T_ARRAY)) {
  19485. $startIndex = $tokens->getNextTokenOfKind($startIndex, ['(']);
  19486. $endIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $startIndex);
  19487. } else {
  19488. $endIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_ARRAY_SQUARE_BRACE, $startIndex);
  19489. }
  19490. $beforeEndIndex = $tokens->getPrevMeaningfulToken($endIndex);
  19491. $beforeEndToken = $tokens[$beforeEndIndex];
  19492. if ($beforeEndToken->equals(',')) {
  19493. $tokens->removeTrailingWhitespace($beforeEndIndex);
  19494. $tokens->clearAt($beforeEndIndex);
  19495. }
  19496. }
  19497. }
  19498. <?php
  19499. namespace PhpCsFixer\Fixer\ArrayNotation;
  19500. use PhpCsFixer\AbstractFixer;
  19501. use PhpCsFixer\FixerDefinition\CodeSample;
  19502. use PhpCsFixer\FixerDefinition\FixerDefinition;
  19503. use PhpCsFixer\Tokenizer\CT;
  19504. use PhpCsFixer\Tokenizer\Token;
  19505. use PhpCsFixer\Tokenizer\Tokens;
  19506. final class NormalizeIndexBraceFixer extends AbstractFixer
  19507. {
  19508. public function getDefinition()
  19509. {
  19510. return new FixerDefinition(
  19511. 'Array index should always be written by using square braces.',
  19512. [new CodeSample("<?php\necho \$sample{\$index};\n")]
  19513. );
  19514. }
  19515. public function isCandidate(Tokens $tokens)
  19516. {
  19517. return $tokens->isTokenKindFound(CT::T_ARRAY_INDEX_CURLY_BRACE_OPEN);
  19518. }
  19519. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  19520. {
  19521. foreach ($tokens as $index => $token) {
  19522. if ($token->isGivenKind(CT::T_ARRAY_INDEX_CURLY_BRACE_OPEN)) {
  19523. $tokens[$index] = new Token('[');
  19524. } elseif ($token->isGivenKind(CT::T_ARRAY_INDEX_CURLY_BRACE_CLOSE)) {
  19525. $tokens[$index] = new Token(']');
  19526. }
  19527. }
  19528. }
  19529. }
  19530. <?php
  19531. namespace PhpCsFixer\Fixer\ArrayNotation;
  19532. use PhpCsFixer\AbstractFixer;
  19533. use PhpCsFixer\FixerDefinition\CodeSample;
  19534. use PhpCsFixer\FixerDefinition\FixerDefinition;
  19535. use PhpCsFixer\Tokenizer\CT;
  19536. use PhpCsFixer\Tokenizer\Tokens;
  19537. final class TrimArraySpacesFixer extends AbstractFixer
  19538. {
  19539. public function getDefinition()
  19540. {
  19541. return new FixerDefinition(
  19542. 'Arrays should be formatted like function/method arguments, without leading or trailing single line space.',
  19543. [new CodeSample("<?php\n\$sample = array( );\n\$sample = array( 'a', 'b' );\n")]
  19544. );
  19545. }
  19546. public function isCandidate(Tokens $tokens)
  19547. {
  19548. return $tokens->isAnyTokenKindsFound([T_ARRAY, CT::T_ARRAY_SQUARE_BRACE_OPEN]);
  19549. }
  19550. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  19551. {
  19552. for ($index = 0, $c = $tokens->count(); $index < $c; ++$index) {
  19553. if ($tokens[$index]->isGivenKind([T_ARRAY, CT::T_ARRAY_SQUARE_BRACE_OPEN])) {
  19554. self::fixArray($tokens, $index);
  19555. }
  19556. }
  19557. }
  19558. private static function fixArray(Tokens $tokens, $index)
  19559. {
  19560. $startIndex = $index;
  19561. if ($tokens[$startIndex]->isGivenKind(T_ARRAY)) {
  19562. $startIndex = $tokens->getNextMeaningfulToken($startIndex);
  19563. $endIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $startIndex);
  19564. } else {
  19565. $endIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_ARRAY_SQUARE_BRACE, $startIndex);
  19566. }
  19567. $nextIndex = $startIndex + 1;
  19568. $nextToken = $tokens[$nextIndex];
  19569. $nextNonWhitespaceIndex = $tokens->getNextNonWhitespace($startIndex);
  19570. $nextNonWhitespaceToken = $tokens[$nextNonWhitespaceIndex];
  19571. $tokenAfterNextNonWhitespaceToken = $tokens[$nextNonWhitespaceIndex + 1];
  19572. $prevIndex = $endIndex - 1;
  19573. $prevToken = $tokens[$prevIndex];
  19574. $prevNonWhitespaceIndex = $tokens->getPrevNonWhitespace($endIndex);
  19575. $prevNonWhitespaceToken = $tokens[$prevNonWhitespaceIndex];
  19576. if (
  19577. $nextToken->isWhitespace(" \t")
  19578. && (
  19579. !$nextNonWhitespaceToken->isComment()
  19580. || $nextNonWhitespaceIndex === $prevNonWhitespaceIndex
  19581. || $tokenAfterNextNonWhitespaceToken->isWhitespace(" \t")
  19582. || '/*' === substr($nextNonWhitespaceToken->getContent(), 0, 2)
  19583. )
  19584. ) {
  19585. $tokens->clearAt($nextIndex);
  19586. }
  19587. if (
  19588. $prevToken->isWhitespace(" \t")
  19589. && !$prevNonWhitespaceToken->equals(',')
  19590. ) {
  19591. $tokens->clearAt($prevIndex);
  19592. }
  19593. }
  19594. }
  19595. <?php
  19596. namespace PhpCsFixer\Fixer\ArrayNotation;
  19597. use PhpCsFixer\AbstractFixer;
  19598. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  19599. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  19600. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  19601. use PhpCsFixer\FixerConfiguration\InvalidOptionsForEnvException;
  19602. use PhpCsFixer\FixerDefinition\CodeSample;
  19603. use PhpCsFixer\FixerDefinition\FixerDefinition;
  19604. use PhpCsFixer\FixerDefinition\VersionSpecification;
  19605. use PhpCsFixer\FixerDefinition\VersionSpecificCodeSample;
  19606. use PhpCsFixer\Tokenizer\CT;
  19607. use PhpCsFixer\Tokenizer\Token;
  19608. use PhpCsFixer\Tokenizer\Tokens;
  19609. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  19610. use Symfony\Component\OptionsResolver\Options;
  19611. /**
  19612. @gmail
  19613. */
  19614. final class TrailingCommaInMultilineArrayFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface
  19615. {
  19616. public function getDefinition()
  19617. {
  19618. return new FixerDefinition(
  19619. 'PHP multi-line arrays should have a trailing comma.',
  19620. [
  19621. new CodeSample("<?php\narray(\n 1,\n 2\n);\n"),
  19622. new VersionSpecificCodeSample(
  19623. <<<'SAMPLE'
  19624. <?php
  19625. $x = [
  19626. 'foo',
  19627. <<<EOD
  19628. bar
  19629. EOD
  19630. ];
  19631. SAMPLE
  19632. ,
  19633. new VersionSpecification(70300),
  19634. ['after_heredoc' => true]
  19635. ),
  19636. ]
  19637. );
  19638. }
  19639. public function getPriority()
  19640. {
  19641. return 0;
  19642. }
  19643. public function isCandidate(Tokens $tokens)
  19644. {
  19645. return $tokens->isAnyTokenKindsFound([T_ARRAY, CT::T_ARRAY_SQUARE_BRACE_OPEN]);
  19646. }
  19647. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  19648. {
  19649. $tokensAnalyzer = new TokensAnalyzer($tokens);
  19650. for ($index = $tokens->count() - 1; $index >= 0; --$index) {
  19651. if ($tokensAnalyzer->isArray($index) && $tokensAnalyzer->isArrayMultiLine($index)) {
  19652. $this->fixArray($tokens, $index);
  19653. }
  19654. }
  19655. }
  19656. protected function createConfigurationDefinition()
  19657. {
  19658. return new FixerConfigurationResolver([
  19659. (new FixerOptionBuilder('after_heredoc', 'Whether a trailing comma should also be placed after heredoc end.'))
  19660. ->setAllowedTypes(['bool'])
  19661. ->setDefault(false)
  19662. ->setNormalizer(static function (Options $options, $value) {
  19663. if (\PHP_VERSION_ID < 70300 && $value) {
  19664. throw new InvalidOptionsForEnvException('"after_heredoc" option can only be enabled with PHP 7.3+.');
  19665. }
  19666. return $value;
  19667. })
  19668. ->getOption(),
  19669. ]);
  19670. }
  19671. private function fixArray(Tokens $tokens, $index)
  19672. {
  19673. $startIndex = $index;
  19674. if ($tokens[$startIndex]->isGivenKind(T_ARRAY)) {
  19675. $startIndex = $tokens->getNextTokenOfKind($startIndex, ['(']);
  19676. $endIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $startIndex);
  19677. } else {
  19678. $endIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_ARRAY_SQUARE_BRACE, $startIndex);
  19679. }
  19680. $beforeEndIndex = $tokens->getPrevMeaningfulToken($endIndex);
  19681. $beforeEndToken = $tokens[$beforeEndIndex];
  19682. if (
  19683. $startIndex !== $beforeEndIndex && !$beforeEndToken->equals(',') &&
  19684. ($this->configuration['after_heredoc'] || !$beforeEndToken->isGivenKind(T_END_HEREDOC))
  19685. ) {
  19686. $tokens->insertAt($beforeEndIndex + 1, new Token(','));
  19687. $endToken = $tokens[$endIndex];
  19688. if (!$endToken->isComment() && !$endToken->isWhitespace()) {
  19689. $tokens->ensureWhitespaceAtIndex($endIndex, 1, ' ');
  19690. }
  19691. }
  19692. }
  19693. }
  19694. <?php
  19695. namespace PhpCsFixer\Fixer\ArrayNotation;
  19696. use PhpCsFixer\AbstractFixer;
  19697. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  19698. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  19699. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  19700. use PhpCsFixer\FixerConfiguration\InvalidOptionsForEnvException;
  19701. use PhpCsFixer\FixerDefinition\CodeSample;
  19702. use PhpCsFixer\FixerDefinition\FixerDefinition;
  19703. use PhpCsFixer\FixerDefinition\VersionSpecification;
  19704. use PhpCsFixer\FixerDefinition\VersionSpecificCodeSample;
  19705. use PhpCsFixer\Tokenizer\CT;
  19706. use PhpCsFixer\Tokenizer\Tokens;
  19707. use Symfony\Component\OptionsResolver\Options;
  19708. final class NoWhitespaceBeforeCommaInArrayFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface
  19709. {
  19710. public function getDefinition()
  19711. {
  19712. return new FixerDefinition(
  19713. 'In array declaration, there MUST NOT be a whitespace before each comma.',
  19714. [
  19715. new CodeSample("<?php \$x = array(1 , \"2\");\n"),
  19716. new VersionSpecificCodeSample(
  19717. <<<'SAMPLE'
  19718. <?php
  19719. $x = [<<<EOD
  19720. foo
  19721. EOD
  19722. , 'bar'
  19723. ];
  19724. SAMPLE
  19725. ,
  19726. new VersionSpecification(70300),
  19727. ['after_heredoc' => true]
  19728. ),
  19729. ]
  19730. );
  19731. }
  19732. public function isCandidate(Tokens $tokens)
  19733. {
  19734. return $tokens->isAnyTokenKindsFound([T_ARRAY, CT::T_ARRAY_SQUARE_BRACE_OPEN]);
  19735. }
  19736. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  19737. {
  19738. for ($index = $tokens->count() - 1; $index >= 0; --$index) {
  19739. if ($tokens[$index]->isGivenKind([T_ARRAY, CT::T_ARRAY_SQUARE_BRACE_OPEN])) {
  19740. $this->fixSpacing($index, $tokens);
  19741. }
  19742. }
  19743. }
  19744. protected function createConfigurationDefinition()
  19745. {
  19746. return new FixerConfigurationResolver([
  19747. (new FixerOptionBuilder('after_heredoc', 'Whether the whitespace between heredoc end and comma should be removed.'))
  19748. ->setAllowedTypes(['bool'])
  19749. ->setDefault(false)
  19750. ->setNormalizer(static function (Options $options, $value) {
  19751. if (\PHP_VERSION_ID < 70300 && $value) {
  19752. throw new InvalidOptionsForEnvException('"after_heredoc" option can only be enabled with PHP 7.3+.');
  19753. }
  19754. return $value;
  19755. })
  19756. ->getOption(),
  19757. ]);
  19758. }
  19759. private function fixSpacing($index, Tokens $tokens)
  19760. {
  19761. if ($tokens[$index]->isGivenKind(CT::T_ARRAY_SQUARE_BRACE_OPEN)) {
  19762. $startIndex = $index;
  19763. $endIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_ARRAY_SQUARE_BRACE, $startIndex);
  19764. } else {
  19765. $startIndex = $tokens->getNextTokenOfKind($index, ['(']);
  19766. $endIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $startIndex);
  19767. }
  19768. for ($i = $endIndex - 1; $i > $startIndex; --$i) {
  19769. $i = $this->skipNonArrayElements($i, $tokens);
  19770. $currentToken = $tokens[$i];
  19771. $prevIndex = $tokens->getPrevNonWhitespace($i - 1);
  19772. if (
  19773. $currentToken->equals(',') && !$tokens[$prevIndex]->isComment() &&
  19774. ($this->configuration['after_heredoc'] || !$tokens[$prevIndex]->equals([T_END_HEREDOC]))
  19775. ) {
  19776. $tokens->removeLeadingWhitespace($i);
  19777. }
  19778. }
  19779. }
  19780. private function skipNonArrayElements($index, Tokens $tokens)
  19781. {
  19782. if ($tokens[$index]->equals('}')) {
  19783. return $tokens->findBlockStart(Tokens::BLOCK_TYPE_CURLY_BRACE, $index);
  19784. }
  19785. if ($tokens[$index]->equals(')')) {
  19786. $startIndex = $tokens->findBlockStart(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $index);
  19787. $startIndex = $tokens->getPrevMeaningfulToken($startIndex);
  19788. if (!$tokens[$startIndex]->isGivenKind([T_ARRAY, CT::T_ARRAY_SQUARE_BRACE_OPEN])) {
  19789. return $startIndex;
  19790. }
  19791. }
  19792. return $index;
  19793. }
  19794. }
  19795. <?php
  19796. namespace PhpCsFixer\Fixer\ArrayNotation;
  19797. use PhpCsFixer\AbstractFixer;
  19798. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  19799. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  19800. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  19801. use PhpCsFixer\FixerDefinition\CodeSample;
  19802. use PhpCsFixer\FixerDefinition\FixerDefinition;
  19803. use PhpCsFixer\FixerDefinition\VersionSpecification;
  19804. use PhpCsFixer\FixerDefinition\VersionSpecificCodeSample;
  19805. use PhpCsFixer\Tokenizer\CT;
  19806. use PhpCsFixer\Tokenizer\Token;
  19807. use PhpCsFixer\Tokenizer\Tokens;
  19808. /**
  19809. @rollerscapes
  19810. @gmail
  19811. */
  19812. final class ArraySyntaxFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface
  19813. {
  19814. private $candidateTokenKind;
  19815. private $fixCallback;
  19816. public function configure(array $configuration = null)
  19817. {
  19818. parent::configure($configuration);
  19819. $this->resolveCandidateTokenKind();
  19820. $this->resolveFixCallback();
  19821. }
  19822. public function getDefinition()
  19823. {
  19824. return new FixerDefinition(
  19825. 'PHP arrays should be declared using the configured syntax.',
  19826. [
  19827. new CodeSample(
  19828. "<?php\n[1,2];\n"
  19829. ),
  19830. new VersionSpecificCodeSample(
  19831. "<?php\narray(1,2);\n",
  19832. new VersionSpecification(50400),
  19833. ['syntax' => 'short']
  19834. ),
  19835. ]
  19836. );
  19837. }
  19838. public function getPriority()
  19839. {
  19840. return 1;
  19841. }
  19842. public function isCandidate(Tokens $tokens)
  19843. {
  19844. return $tokens->isTokenKindFound($this->candidateTokenKind);
  19845. }
  19846. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  19847. {
  19848. $callback = $this->fixCallback;
  19849. for ($index = $tokens->count() - 1; 0 <= $index; --$index) {
  19850. if ($tokens[$index]->isGivenKind($this->candidateTokenKind)) {
  19851. $this->{$callback}($tokens, $index);
  19852. }
  19853. }
  19854. }
  19855. protected function createConfigurationDefinition()
  19856. {
  19857. return new FixerConfigurationResolver([
  19858. (new FixerOptionBuilder('syntax', 'Whether to use the `long` or `short` array syntax.'))
  19859. ->setAllowedValues(['long', 'short'])
  19860. ->setDefault('long')
  19861. ->getOption(),
  19862. ]);
  19863. }
  19864. private function fixToLongArraySyntax(Tokens $tokens, $index)
  19865. {
  19866. $closeIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_ARRAY_SQUARE_BRACE, $index);
  19867. $tokens[$index] = new Token('(');
  19868. $tokens[$closeIndex] = new Token(')');
  19869. $tokens->insertAt($index, new Token([T_ARRAY, 'array']));
  19870. }
  19871. private function fixToShortArraySyntax(Tokens $tokens, $index)
  19872. {
  19873. $openIndex = $tokens->getNextTokenOfKind($index, ['(']);
  19874. $closeIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $openIndex);
  19875. $tokens[$openIndex] = new Token([CT::T_ARRAY_SQUARE_BRACE_OPEN, '[']);
  19876. $tokens[$closeIndex] = new Token([CT::T_ARRAY_SQUARE_BRACE_CLOSE, ']']);
  19877. $tokens->clearTokenAndMergeSurroundingWhitespace($index);
  19878. }
  19879. private function resolveFixCallback()
  19880. {
  19881. $this->fixCallback = sprintf('fixTo%sArraySyntax', ucfirst($this->configuration['syntax']));
  19882. }
  19883. private function resolveCandidateTokenKind()
  19884. {
  19885. $this->candidateTokenKind = 'long' === $this->configuration['syntax'] ? CT::T_ARRAY_SQUARE_BRACE_OPEN : T_ARRAY;
  19886. }
  19887. }
  19888. <?php
  19889. namespace PhpCsFixer\Fixer\ArrayNotation;
  19890. use PhpCsFixer\AbstractFixer;
  19891. use PhpCsFixer\FixerDefinition\CodeSample;
  19892. use PhpCsFixer\FixerDefinition\FixerDefinition;
  19893. use PhpCsFixer\Tokenizer\Token;
  19894. use PhpCsFixer\Tokenizer\Tokens;
  19895. /**
  19896. @gmail
  19897. @alt
  19898. */
  19899. final class NoMultilineWhitespaceAroundDoubleArrowFixer extends AbstractFixer
  19900. {
  19901. public function getDefinition()
  19902. {
  19903. return new FixerDefinition(
  19904. 'Operator `=>` should not be surrounded by multi-line whitespaces.',
  19905. [new CodeSample("<?php\n\$a = array(1\n\n=> 2);\n")]
  19906. );
  19907. }
  19908. public function getPriority()
  19909. {
  19910. return 1;
  19911. }
  19912. public function isCandidate(Tokens $tokens)
  19913. {
  19914. return $tokens->isTokenKindFound(T_DOUBLE_ARROW);
  19915. }
  19916. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  19917. {
  19918. foreach ($tokens as $index => $token) {
  19919. if (!$token->isGivenKind(T_DOUBLE_ARROW)) {
  19920. continue;
  19921. }
  19922. $this->fixWhitespace($tokens, $index - 1);
  19923. if (!$tokens[$index + 2]->isComment()) {
  19924. $this->fixWhitespace($tokens, $index + 1);
  19925. }
  19926. }
  19927. }
  19928. private function fixWhitespace(Tokens $tokens, $index)
  19929. {
  19930. $token = $tokens[$index];
  19931. if ($token->isWhitespace() && !$token->isWhitespace(" \t")) {
  19932. $tokens[$index] = new Token([T_WHITESPACE, rtrim($token->getContent()).' ']);
  19933. }
  19934. }
  19935. }
  19936. <?php
  19937. namespace PhpCsFixer\Fixer\ConstantNotation;
  19938. use PhpCsFixer\AbstractFixer;
  19939. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  19940. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  19941. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  19942. use PhpCsFixer\FixerDefinition\CodeSample;
  19943. use PhpCsFixer\FixerDefinition\FixerDefinition;
  19944. use PhpCsFixer\Tokenizer\Analyzer\Analysis\NamespaceAnalysis;
  19945. use PhpCsFixer\Tokenizer\Analyzer\NamespacesAnalyzer;
  19946. use PhpCsFixer\Tokenizer\Analyzer\NamespaceUsesAnalyzer;
  19947. use PhpCsFixer\Tokenizer\Token;
  19948. use PhpCsFixer\Tokenizer\Tokens;
  19949. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  19950. use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException;
  19951. final class NativeConstantInvocationFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface
  19952. {
  19953. private $constantsToEscape = [];
  19954. private $caseInsensitiveConstantsToEscape = [];
  19955. public function getDefinition()
  19956. {
  19957. return new FixerDefinition(
  19958. 'Add leading `\` before constant invocation of internal constant to speed up resolving. Constant name match is case-sensitive, except for `null`, `false` and `true`.',
  19959. [
  19960. new CodeSample("<?php var_dump(PHP_VERSION, M_PI, MY_CUSTOM_PI);\n"),
  19961. new CodeSample(
  19962. '<?php
  19963. namespace space1 {
  19964. echo PHP_VERSION;
  19965. }
  19966. namespace {
  19967. echo M_PI;
  19968. }
  19969. ',
  19970. ['scope' => 'namespaced']
  19971. ),
  19972. new CodeSample(
  19973. "<?php var_dump(PHP_VERSION, M_PI, MY_CUSTOM_PI);\n",
  19974. [
  19975. 'include' => [
  19976. 'MY_CUSTOM_PI',
  19977. ],
  19978. ]
  19979. ),
  19980. new CodeSample(
  19981. "<?php var_dump(PHP_VERSION, M_PI, MY_CUSTOM_PI);\n",
  19982. [
  19983. 'fix_built_in' => false,
  19984. 'include' => [
  19985. 'MY_CUSTOM_PI',
  19986. ],
  19987. ]
  19988. ),
  19989. new CodeSample(
  19990. "<?php var_dump(PHP_VERSION, M_PI, MY_CUSTOM_PI);\n",
  19991. [
  19992. 'exclude' => [
  19993. 'M_PI',
  19994. ],
  19995. ]
  19996. ),
  19997. ],
  19998. null,
  19999. 'Risky when any of the constants are namespaced or overridden.'
  20000. );
  20001. }
  20002. public function getPriority()
  20003. {
  20004. return 10;
  20005. }
  20006. public function isCandidate(Tokens $tokens)
  20007. {
  20008. return $tokens->isTokenKindFound(T_STRING);
  20009. }
  20010. public function isRisky()
  20011. {
  20012. return true;
  20013. }
  20014. public function configure(array $configuration = null)
  20015. {
  20016. parent::configure($configuration);
  20017. $uniqueConfiguredExclude = array_unique($this->configuration['exclude']);
  20018. $constantsToEscape = array_values($this->configuration['include']);
  20019. if (true === $this->configuration['fix_built_in']) {
  20020. $getDefinedConstants = get_defined_constants(true);
  20021. unset($getDefinedConstants['user']);
  20022. foreach ($getDefinedConstants as $constants) {
  20023. $constantsToEscape = array_merge($constantsToEscape, array_keys($constants));
  20024. }
  20025. }
  20026. $constantsToEscape = array_diff(
  20027. array_unique($constantsToEscape),
  20028. $uniqueConfiguredExclude
  20029. );
  20030. static $caseInsensitiveConstants = ['null', 'false', 'true'];
  20031. $caseInsensitiveConstantsToEscape = [];
  20032. foreach ($constantsToEscape as $constantIndex => $constant) {
  20033. $loweredConstant = strtolower($constant);
  20034. if (\in_array($loweredConstant, $caseInsensitiveConstants, true)) {
  20035. $caseInsensitiveConstantsToEscape[] = $loweredConstant;
  20036. unset($constantsToEscape[$constantIndex]);
  20037. }
  20038. }
  20039. $caseInsensitiveConstantsToEscape = array_diff(
  20040. array_unique($caseInsensitiveConstantsToEscape),
  20041. array_map(static function ($function) { return strtolower($function); }, $uniqueConfiguredExclude)
  20042. );
  20043. $this->constantsToEscape = array_fill_keys($constantsToEscape, true);
  20044. ksort($this->constantsToEscape);
  20045. $this->caseInsensitiveConstantsToEscape = array_fill_keys($caseInsensitiveConstantsToEscape, true);
  20046. ksort($this->caseInsensitiveConstantsToEscape);
  20047. }
  20048. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  20049. {
  20050. if ('all' === $this->configuration['scope']) {
  20051. $this->fixConstantInvocations($tokens, 0, \count($tokens) - 1);
  20052. return;
  20053. }
  20054. $namespaces = (new NamespacesAnalyzer())->getDeclarations($tokens);
  20055. foreach (array_reverse($namespaces) as $namespace) {
  20056. if ('' === $namespace->getFullName()) {
  20057. continue;
  20058. }
  20059. $this->fixConstantInvocations($tokens, $namespace->getScopeStartIndex(), $namespace->getScopeEndIndex());
  20060. }
  20061. }
  20062. protected function createConfigurationDefinition()
  20063. {
  20064. $constantChecker = static function ($value) {
  20065. foreach ($value as $constantName) {
  20066. if (!\is_string($constantName) || '' === trim($constantName) || trim($constantName) !== $constantName) {
  20067. throw new InvalidOptionsException(sprintf(
  20068. 'Each element must be a non-empty, trimmed string, got "%s" instead.',
  20069. \is_object($constantName) ? \get_class($constantName) : \gettype($constantName)
  20070. ));
  20071. }
  20072. }
  20073. return true;
  20074. };
  20075. return new FixerConfigurationResolver([
  20076. (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.'))
  20077. ->setAllowedTypes(['bool'])
  20078. ->setDefault(true)
  20079. ->getOption(),
  20080. (new FixerOptionBuilder('include', 'List of additional constants to fix.'))
  20081. ->setAllowedTypes(['array'])
  20082. ->setAllowedValues([$constantChecker])
  20083. ->setDefault([])
  20084. ->getOption(),
  20085. (new FixerOptionBuilder('exclude', 'List of constants to ignore.'))
  20086. ->setAllowedTypes(['array'])
  20087. ->setAllowedValues([$constantChecker])
  20088. ->setDefault(['null', 'false', 'true'])
  20089. ->getOption(),
  20090. (new FixerOptionBuilder('scope', 'Only fix constant invocations that are made within a namespace or fix all.'))
  20091. ->setAllowedValues(['all', 'namespaced'])
  20092. ->setDefault('all')
  20093. ->getOption(),
  20094. ]);
  20095. }
  20096. private function fixConstantInvocations(Tokens $tokens, $start, $end)
  20097. {
  20098. $useDeclarations = (new NamespaceUsesAnalyzer())->getDeclarationsFromTokens($tokens);
  20099. $useConstantDeclarations = [];
  20100. foreach ($useDeclarations as $use) {
  20101. if ($use->isConstant()) {
  20102. $useConstantDeclarations[$use->getShortName()] = true;
  20103. }
  20104. }
  20105. $tokenAnalyzer = new TokensAnalyzer($tokens);
  20106. $indexes = [];
  20107. for ($index = $start; $index < $end; ++$index) {
  20108. $token = $tokens[$index];
  20109. if (!$token->isGivenKind(T_STRING)) {
  20110. continue;
  20111. }
  20112. $tokenContent = $token->getContent();
  20113. if (!isset($this->constantsToEscape[$tokenContent]) && !isset($this->caseInsensitiveConstantsToEscape[strtolower($tokenContent)])) {
  20114. continue;
  20115. }
  20116. if (isset($useConstantDeclarations[$tokenContent])) {
  20117. continue;
  20118. }
  20119. $prevIndex = $tokens->getPrevMeaningfulToken($index);
  20120. if ($tokens[$prevIndex]->isGivenKind(T_NS_SEPARATOR)) {
  20121. continue;
  20122. }
  20123. if (!$tokenAnalyzer->isConstantInvocation($index)) {
  20124. continue;
  20125. }
  20126. $indexes[] = $index;
  20127. }
  20128. $indexes = array_reverse($indexes);
  20129. foreach ($indexes as $index) {
  20130. $tokens->insertAt($index, new Token([T_NS_SEPARATOR, '\\']));
  20131. }
  20132. }
  20133. }
  20134. <?php
  20135. namespace PhpCsFixer\Fixer\Phpdoc;
  20136. use PhpCsFixer\AbstractFixer;
  20137. use PhpCsFixer\DocBlock\DocBlock;
  20138. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  20139. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverRootless;
  20140. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  20141. use PhpCsFixer\FixerDefinition\CodeSample;
  20142. use PhpCsFixer\FixerDefinition\FixerDefinition;
  20143. use PhpCsFixer\Tokenizer\Token;
  20144. use PhpCsFixer\Tokenizer\Tokens;
  20145. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  20146. use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException;
  20147. use Symfony\Component\OptionsResolver\Options;
  20148. final class PhpdocReturnSelfReferenceFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface
  20149. {
  20150. private static $toTypes = [
  20151. '$this',
  20152. 'static',
  20153. 'self',
  20154. ];
  20155. public function getDefinition()
  20156. {
  20157. return new FixerDefinition(
  20158. 'The type of `@return` annotations of methods returning a reference to itself must the configured one.',
  20159. [
  20160. new CodeSample(
  20161. '<?php
  20162. class Sample
  20163. {
  20164. /**
  20165. * @return this
  20166. */
  20167. public function test1()
  20168. {
  20169. return $this;
  20170. }
  20171. /**
  20172. * @return $self
  20173. */
  20174. public function test2()
  20175. {
  20176. return $this;
  20177. }
  20178. }
  20179. '
  20180. ),
  20181. new CodeSample(
  20182. '<?php
  20183. class Sample
  20184. {
  20185. /**
  20186. * @return this
  20187. */
  20188. public function test1()
  20189. {
  20190. return $this;
  20191. }
  20192. /**
  20193. * @return $self
  20194. */
  20195. public function test2()
  20196. {
  20197. return $this;
  20198. }
  20199. }
  20200. ',
  20201. ['replacements' => ['this' => 'self']]
  20202. ),
  20203. ]
  20204. );
  20205. }
  20206. public function isCandidate(Tokens $tokens)
  20207. {
  20208. return \count($tokens) > 10 && $tokens->isTokenKindFound(T_DOC_COMMENT) && $tokens->isAnyTokenKindsFound([T_CLASS, T_INTERFACE]);
  20209. }
  20210. public function getPriority()
  20211. {
  20212. return 10;
  20213. }
  20214. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  20215. {
  20216. $tokensAnalyzer = new TokensAnalyzer($tokens);
  20217. foreach ($tokensAnalyzer->getClassyElements() as $index => $element) {
  20218. if ('method' === $element['type']) {
  20219. $this->fixMethod($tokens, $index);
  20220. }
  20221. }
  20222. }
  20223. protected function createConfigurationDefinition()
  20224. {
  20225. $default = [
  20226. 'this' => '$this',
  20227. '@this' => '$this',
  20228. '$self' => 'self',
  20229. '@self' => 'self',
  20230. '$static' => 'static',
  20231. '@static' => 'static',
  20232. ];
  20233. return new FixerConfigurationResolverRootless('replacements', [
  20234. (new FixerOptionBuilder('replacements', 'Mapping between replaced return types with new ones.'))
  20235. ->setAllowedTypes(['array'])
  20236. ->setNormalizer(static function (Options $options, $value) use ($default) {
  20237. $normalizedValue = [];
  20238. foreach ($value as $from => $to) {
  20239. if (\is_string($from)) {
  20240. $from = strtolower($from);
  20241. }
  20242. if (!isset($default[$from])) {
  20243. throw new InvalidOptionsException(sprintf(
  20244. 'Unknown key "%s", expected any of "%s".',
  20245. \is_object($from) ? \get_class($from) : \gettype($from).(\is_resource($from) ? '' : '#'.$from),
  20246. implode('", "', array_keys($default))
  20247. ));
  20248. }
  20249. if (!\in_array($to, self::$toTypes, true)) {
  20250. throw new InvalidOptionsException(sprintf(
  20251. 'Unknown value "%s", expected any of "%s".',
  20252. \is_object($to) ? \get_class($to) : \gettype($to).(\is_resource($to) ? '' : '#'.$to),
  20253. implode('", "', self::$toTypes)
  20254. ));
  20255. }
  20256. $normalizedValue[$from] = $to;
  20257. }
  20258. return $normalizedValue;
  20259. })
  20260. ->setDefault($default)
  20261. ->getOption(),
  20262. ], $this->getName());
  20263. }
  20264. private function fixMethod(Tokens $tokens, $index)
  20265. {
  20266. static $methodModifiers = [T_STATIC, T_FINAL, T_ABSTRACT, T_PRIVATE, T_PROTECTED, T_PUBLIC];
  20267. do {
  20268. $tokenIndex = $tokens->getPrevMeaningfulToken($index);
  20269. if (!$tokens[$tokenIndex]->isGivenKind($methodModifiers)) {
  20270. break;
  20271. }
  20272. $index = $tokenIndex;
  20273. } while (true);
  20274. $docIndex = $tokens->getPrevNonWhitespace($index);
  20275. if (!$tokens[$docIndex]->isGivenKind(T_DOC_COMMENT)) {
  20276. return;
  20277. }
  20278. $docBlock = new DocBlock($tokens[$docIndex]->getContent());
  20279. $returnsBlock = $docBlock->getAnnotationsOfType('return');
  20280. if (!\count($returnsBlock)) {
  20281. return;
  20282. }
  20283. $returnsBlock = $returnsBlock[0];
  20284. $types = $returnsBlock->getTypes();
  20285. if (!\count($types)) {
  20286. return;
  20287. }
  20288. $newTypes = [];
  20289. foreach ($types as $type) {
  20290. $lower = strtolower($type);
  20291. $newTypes[] = isset($this->configuration['replacements'][$lower]) ? $this->configuration['replacements'][$lower] : $type;
  20292. }
  20293. if ($types === $newTypes) {
  20294. return;
  20295. }
  20296. $returnsBlock->setTypes($newTypes);
  20297. $tokens[$docIndex] = new Token([T_DOC_COMMENT, $docBlock->getContent()]);
  20298. }
  20299. }
  20300. <?php
  20301. namespace PhpCsFixer\Fixer\Phpdoc;
  20302. use PhpCsFixer\AbstractFixer;
  20303. use PhpCsFixer\FixerDefinition\CodeSample;
  20304. use PhpCsFixer\FixerDefinition\FixerDefinition;
  20305. use PhpCsFixer\Preg;
  20306. use PhpCsFixer\Tokenizer\Token;
  20307. use PhpCsFixer\Tokenizer\Tokens;
  20308. final class PhpdocTrimFixer extends AbstractFixer
  20309. {
  20310. public function getDefinition()
  20311. {
  20312. return new FixerDefinition(
  20313. 'PHPDoc should start and end with content, excluding the very first and last line of the docblocks.',
  20314. [new CodeSample('<?php
  20315. /**
  20316. *
  20317. * Foo must be final class.
  20318. *
  20319. *
  20320. */
  20321. final class Foo {}
  20322. ')]
  20323. );
  20324. }
  20325. public function getPriority()
  20326. {
  20327. return -5;
  20328. }
  20329. public function isCandidate(Tokens $tokens)
  20330. {
  20331. return $tokens->isTokenKindFound(T_DOC_COMMENT);
  20332. }
  20333. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  20334. {
  20335. foreach ($tokens as $index => $token) {
  20336. if (!$token->isGivenKind(T_DOC_COMMENT)) {
  20337. continue;
  20338. }
  20339. $content = $token->getContent();
  20340. $content = $this->fixStart($content);
  20341. $content = $this->fixEnd($content);
  20342. $tokens[$index] = new Token([T_DOC_COMMENT, $content]);
  20343. }
  20344. }
  20345. private function fixStart($content)
  20346. {
  20347. return Preg::replace(
  20348. '~
  20349. (^/\*\*) # DocComment begin
  20350. (?:
  20351. \R\h*(?:\*\h*)? # lines without useful content
  20352. (?!\R\h*\*/) # not followed by a DocComment end
  20353. )+
  20354. (\R\h*(?:\*\h*)?\S) # first line with useful content
  20355. ~x',
  20356. '$1$2',
  20357. $content
  20358. );
  20359. }
  20360. private function fixEnd($content)
  20361. {
  20362. return Preg::replace(
  20363. '~
  20364. (\R\h*(?:\*\h*)?\S.*?) # last line with useful content
  20365. (?:
  20366. (?<!/\*\*) # not preceded by a DocComment start
  20367. \R\h*(?:\*\h*)? # lines without useful content
  20368. )+
  20369. (\R\h*\*/$) # DocComment end
  20370. ~xu',
  20371. '$1$2',
  20372. $content
  20373. );
  20374. }
  20375. }
  20376. <?php
  20377. namespace PhpCsFixer\Fixer\Phpdoc;
  20378. use PhpCsFixer\AbstractFixer;
  20379. use PhpCsFixer\DocBlock\Annotation;
  20380. use PhpCsFixer\DocBlock\DocBlock;
  20381. use PhpCsFixer\DocBlock\TagComparator;
  20382. use PhpCsFixer\FixerDefinition\CodeSample;
  20383. use PhpCsFixer\FixerDefinition\FixerDefinition;
  20384. use PhpCsFixer\Tokenizer\Token;
  20385. use PhpCsFixer\Tokenizer\Tokens;
  20386. final class PhpdocSeparationFixer extends AbstractFixer
  20387. {
  20388. public function getDefinition()
  20389. {
  20390. return new FixerDefinition(
  20391. 'Annotations in PHPDoc should be grouped together so that annotations of the same type immediately follow each other, and annotations of a different type are separated by a single blank line.',
  20392. [
  20393. new CodeSample(
  20394. '<?php
  20395. /**
  20396. * Description.
  20397. * @param string $foo
  20398. *
  20399. *
  20400. * @param bool $bar Bar
  20401. * @throws Exception|RuntimeException
  20402. * @return bool
  20403. */
  20404. function fnc($foo, $bar) {}
  20405. '
  20406. ),
  20407. ]
  20408. );
  20409. }
  20410. public function getPriority()
  20411. {
  20412. return -3;
  20413. }
  20414. public function isCandidate(Tokens $tokens)
  20415. {
  20416. return $tokens->isTokenKindFound(T_DOC_COMMENT);
  20417. }
  20418. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  20419. {
  20420. foreach ($tokens as $index => $token) {
  20421. if (!$token->isGivenKind(T_DOC_COMMENT)) {
  20422. continue;
  20423. }
  20424. $doc = new DocBlock($token->getContent());
  20425. $this->fixDescription($doc);
  20426. $this->fixAnnotations($doc);
  20427. $tokens[$index] = new Token([T_DOC_COMMENT, $doc->getContent()]);
  20428. }
  20429. }
  20430. private function fixDescription(DocBlock $doc)
  20431. {
  20432. foreach ($doc->getLines() as $index => $line) {
  20433. if ($line->containsATag()) {
  20434. break;
  20435. }
  20436. if ($line->containsUsefulContent()) {
  20437. $next = $doc->getLine($index + 1);
  20438. if (null !== $next && $next->containsATag()) {
  20439. $line->addBlank();
  20440. break;
  20441. }
  20442. }
  20443. }
  20444. }
  20445. private function fixAnnotations(DocBlock $doc)
  20446. {
  20447. foreach ($doc->getAnnotations() as $index => $annotation) {
  20448. $next = $doc->getAnnotation($index + 1);
  20449. if (null === $next) {
  20450. break;
  20451. }
  20452. if (true === $next->getTag()->valid()) {
  20453. if (TagComparator::shouldBeTogether($annotation->getTag(), $next->getTag())) {
  20454. $this->ensureAreTogether($doc, $annotation, $next);
  20455. } else {
  20456. $this->ensureAreSeparate($doc, $annotation, $next);
  20457. }
  20458. }
  20459. }
  20460. return $doc->getContent();
  20461. }
  20462. private function ensureAreTogether(DocBlock $doc, Annotation $first, Annotation $second)
  20463. {
  20464. $pos = $first->getEnd();
  20465. $final = $second->getStart();
  20466. for ($pos = $pos + 1; $pos < $final; ++$pos) {
  20467. $doc->getLine($pos)->remove();
  20468. }
  20469. }
  20470. private function ensureAreSeparate(DocBlock $doc, Annotation $first, Annotation $second)
  20471. {
  20472. $pos = $first->getEnd();
  20473. $final = $second->getStart() - 1;
  20474. if ($pos === $final) {
  20475. $doc->getLine($pos)->addBlank();
  20476. return;
  20477. }
  20478. for ($pos = $pos + 1; $pos < $final; ++$pos) {
  20479. $doc->getLine($pos)->remove();
  20480. }
  20481. }
  20482. }
  20483. <?php
  20484. namespace PhpCsFixer\Fixer\Phpdoc;
  20485. use PhpCsFixer\AbstractFixer;
  20486. use PhpCsFixer\DocBlock\Annotation;
  20487. use PhpCsFixer\DocBlock\DocBlock;
  20488. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  20489. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  20490. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  20491. use PhpCsFixer\FixerDefinition\CodeSample;
  20492. use PhpCsFixer\FixerDefinition\FixerDefinition;
  20493. use PhpCsFixer\FixerDefinition\VersionSpecification;
  20494. use PhpCsFixer\FixerDefinition\VersionSpecificCodeSample;
  20495. use PhpCsFixer\Preg;
  20496. use PhpCsFixer\Tokenizer\Analyzer\NamespaceUsesAnalyzer;
  20497. use PhpCsFixer\Tokenizer\CT;
  20498. use PhpCsFixer\Tokenizer\Token;
  20499. use PhpCsFixer\Tokenizer\Tokens;
  20500. final class NoSuperfluousPhpdocTagsFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface
  20501. {
  20502. public function getDefinition()
  20503. {
  20504. return new FixerDefinition(
  20505. 'Removes `@param`, `@return` and `@var` tags that don\'t provide any useful information.',
  20506. [
  20507. new CodeSample('<?php
  20508. class Foo {
  20509. /**
  20510. * @param Bar $bar
  20511. * @param mixed $baz
  20512. */
  20513. public function doFoo(Bar $bar, $baz) {}
  20514. }
  20515. '),
  20516. new CodeSample('<?php
  20517. class Foo {
  20518. /**
  20519. * @param Bar $bar
  20520. * @param mixed $baz
  20521. */
  20522. public function doFoo(Bar $bar, $baz) {}
  20523. }
  20524. ', ['allow_mixed' => true]),
  20525. new VersionSpecificCodeSample('<?php
  20526. class Foo {
  20527. /**
  20528. * @param Bar $bar
  20529. * @param mixed $baz
  20530. *
  20531. * @return Baz
  20532. */
  20533. public function doFoo(Bar $bar, $baz): Baz {}
  20534. }
  20535. ', new VersionSpecification(70000)),
  20536. new CodeSample('<?php
  20537. class Foo {
  20538. /**
  20539. * @inheritDoc
  20540. */
  20541. public function doFoo(Bar $bar, $baz) {}
  20542. }
  20543. ', ['remove_inheritdoc' => true]),
  20544. new CodeSample('<?php
  20545. class Foo {
  20546. /**
  20547. * @param Bar $bar
  20548. * @param mixed $baz
  20549. * @param string|int|null $qux
  20550. */
  20551. public function doFoo(Bar $bar, $baz /*, $qux = null */) {}
  20552. }
  20553. ', ['allow_unused_params' => true]),
  20554. ]
  20555. );
  20556. }
  20557. public function getPriority()
  20558. {
  20559. return 6;
  20560. }
  20561. public function isCandidate(Tokens $tokens)
  20562. {
  20563. return $tokens->isTokenKindFound(T_DOC_COMMENT);
  20564. }
  20565. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  20566. {
  20567. $namespaceUseAnalyzer = new NamespaceUsesAnalyzer();
  20568. $shortNames = [];
  20569. foreach ($namespaceUseAnalyzer->getDeclarationsFromTokens($tokens) as $namespaceUseAnalysis) {
  20570. $shortNames[strtolower($namespaceUseAnalysis->getShortName())] = '\\'.strtolower($namespaceUseAnalysis->getFullName());
  20571. }
  20572. foreach ($tokens as $index => $token) {
  20573. if (!$token->isGivenKind(T_DOC_COMMENT)) {
  20574. continue;
  20575. }
  20576. $content = $initialContent = $token->getContent();
  20577. $documentedElementIndex = $this->findDocumentedElement($tokens, $index);
  20578. if (null === $documentedElementIndex) {
  20579. continue;
  20580. }
  20581. $token = $tokens[$documentedElementIndex];
  20582. if ($token->isGivenKind(T_FUNCTION)) {
  20583. $content = $this->fixFunctionDocComment($content, $tokens, $index, $shortNames);
  20584. } elseif ($token->isGivenKind(T_VARIABLE)) {
  20585. $content = $this->fixPropertyDocComment($content, $tokens, $index, $shortNames);
  20586. }
  20587. if ($this->configuration['remove_inheritdoc']) {
  20588. $content = $this->removeSuperfluousInheritDoc($content);
  20589. }
  20590. if ($content !== $initialContent) {
  20591. $tokens[$index] = new Token([T_DOC_COMMENT, $content]);
  20592. }
  20593. }
  20594. }
  20595. protected function createConfigurationDefinition()
  20596. {
  20597. return new FixerConfigurationResolver([
  20598. (new FixerOptionBuilder('allow_mixed', 'Whether type `mixed` without description is allowed (`true`) or considered superfluous (`false`)'))
  20599. ->setAllowedTypes(['bool'])
  20600. ->setDefault(false)
  20601. ->getOption(),
  20602. (new FixerOptionBuilder('remove_inheritdoc', 'Remove `@inheritDoc` tags'))
  20603. ->setAllowedTypes(['bool'])
  20604. ->setDefault(false)
  20605. ->getOption(),
  20606. (new FixerOptionBuilder('allow_unused_params', 'Whether `param` annotation without actual signature is allowed (`true`) or considered superfluous (`false`)'))
  20607. ->setAllowedTypes(['bool'])
  20608. ->setDefault(false)
  20609. ->getOption(),
  20610. ]);
  20611. }
  20612. private function findDocumentedElement(Tokens $tokens, $docCommentIndex)
  20613. {
  20614. $index = $docCommentIndex;
  20615. do {
  20616. $index = $tokens->getNextMeaningfulToken($index);
  20617. if (null === $index || $tokens[$index]->isGivenKind([T_FUNCTION, T_CLASS, T_INTERFACE])) {
  20618. return $index;
  20619. }
  20620. } while ($tokens[$index]->isGivenKind([T_ABSTRACT, T_FINAL, T_STATIC, T_PRIVATE, T_PROTECTED, T_PUBLIC]));
  20621. $index = $tokens->getNextMeaningfulToken($docCommentIndex);
  20622. $kindsBeforeProperty = [T_STATIC, T_PRIVATE, T_PROTECTED, T_PUBLIC, CT::T_NULLABLE_TYPE, CT::T_ARRAY_TYPEHINT, T_STRING, T_NS_SEPARATOR];
  20623. if (!$tokens[$index]->isGivenKind($kindsBeforeProperty)) {
  20624. return null;
  20625. }
  20626. do {
  20627. $index = $tokens->getNextMeaningfulToken($index);
  20628. if ($tokens[$index]->isGivenKind(T_VARIABLE)) {
  20629. return $index;
  20630. }
  20631. } while ($tokens[$index]->isGivenKind($kindsBeforeProperty));
  20632. return null;
  20633. }
  20634. private function fixFunctionDocComment($content, Tokens $tokens, $functionIndex, array $shortNames)
  20635. {
  20636. $docBlock = new DocBlock($content);
  20637. $openingParenthesisIndex = $tokens->getNextTokenOfKind($functionIndex, ['(']);
  20638. $closingParenthesisIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $openingParenthesisIndex);
  20639. $argumentsInfo = $this->getArgumentsInfo(
  20640. $tokens,
  20641. $openingParenthesisIndex + 1,
  20642. $closingParenthesisIndex - 1
  20643. );
  20644. foreach ($docBlock->getAnnotationsOfType('param') as $annotation) {
  20645. if (0 === Preg::match('/@param(?:\s+[^\$]\S+)?\s+(\$\S+)/', $annotation->getContent(), $matches)) {
  20646. continue;
  20647. }
  20648. $argumentName = $matches[1];
  20649. if (!isset($argumentsInfo[$argumentName]) && $this->configuration['allow_unused_params']) {
  20650. continue;
  20651. }
  20652. if (!isset($argumentsInfo[$argumentName]) || $this->annotationIsSuperfluous($annotation, $argumentsInfo[$argumentName], $shortNames)) {
  20653. $annotation->remove();
  20654. }
  20655. }
  20656. $returnTypeInfo = $this->getReturnTypeInfo($tokens, $closingParenthesisIndex);
  20657. foreach ($docBlock->getAnnotationsOfType('return') as $annotation) {
  20658. if ($this->annotationIsSuperfluous($annotation, $returnTypeInfo, $shortNames)) {
  20659. $annotation->remove();
  20660. }
  20661. }
  20662. return $docBlock->getContent();
  20663. }
  20664. private function fixPropertyDocComment($content, Tokens $tokens, $index, array $shortNames)
  20665. {
  20666. $docBlock = new DocBlock($content);
  20667. do {
  20668. $index = $tokens->getNextMeaningfulToken($index);
  20669. } while ($tokens[$index]->isGivenKind([T_STATIC, T_PRIVATE, T_PROTECTED, T_PUBLIC]));
  20670. $propertyTypeInfo = $this->getPropertyTypeInfo($tokens, $index);
  20671. foreach ($docBlock->getAnnotationsOfType('var') as $annotation) {
  20672. if ($this->annotationIsSuperfluous($annotation, $propertyTypeInfo, $shortNames)) {
  20673. $annotation->remove();
  20674. }
  20675. }
  20676. return $docBlock->getContent();
  20677. }
  20678. private function getArgumentsInfo(Tokens $tokens, $start, $end)
  20679. {
  20680. $argumentsInfo = [];
  20681. for ($index = $start; $index <= $end; ++$index) {
  20682. $token = $tokens[$index];
  20683. if (!$token->isGivenKind(T_VARIABLE)) {
  20684. continue;
  20685. }
  20686. $beforeArgumentIndex = $tokens->getPrevTokenOfKind($index, ['(', ',']);
  20687. $typeIndex = $tokens->getNextMeaningfulToken($beforeArgumentIndex);
  20688. if ($typeIndex !== $index) {
  20689. $info = $this->parseTypeHint($tokens, $typeIndex);
  20690. } else {
  20691. $info = [
  20692. 'type' => null,
  20693. 'allows_null' => true,
  20694. ];
  20695. }
  20696. if (!$info['allows_null']) {
  20697. $nextIndex = $tokens->getNextMeaningfulToken($index);
  20698. if (
  20699. $tokens[$nextIndex]->equals('=')
  20700. && $tokens[$tokens->getNextMeaningfulToken($nextIndex)]->equals([T_STRING, 'null'])
  20701. ) {
  20702. $info['allows_null'] = true;
  20703. }
  20704. }
  20705. $argumentsInfo[$token->getContent()] = $info;
  20706. }
  20707. return $argumentsInfo;
  20708. }
  20709. private function getReturnTypeInfo(Tokens $tokens, $closingParenthesisIndex)
  20710. {
  20711. $colonIndex = $tokens->getNextMeaningfulToken($closingParenthesisIndex);
  20712. if ($tokens[$colonIndex]->isGivenKind(CT::T_TYPE_COLON)) {
  20713. return $this->parseTypeHint($tokens, $tokens->getNextMeaningfulToken($colonIndex));
  20714. }
  20715. return [
  20716. 'type' => null,
  20717. 'allows_null' => true,
  20718. ];
  20719. }
  20720. private function getPropertyTypeInfo(Tokens $tokens, $index)
  20721. {
  20722. if ($tokens[$index]->isGivenKind(T_VARIABLE)) {
  20723. return [
  20724. 'type' => null,
  20725. 'allows_null' => true,
  20726. ];
  20727. }
  20728. return $this->parseTypeHint($tokens, $index);
  20729. }
  20730. private function parseTypeHint(Tokens $tokens, $index)
  20731. {
  20732. $allowsNull = false;
  20733. if ($tokens[$index]->isGivenKind(CT::T_NULLABLE_TYPE)) {
  20734. $allowsNull = true;
  20735. $index = $tokens->getNextMeaningfulToken($index);
  20736. }
  20737. $type = '';
  20738. while ($tokens[$index]->isGivenKind([T_NS_SEPARATOR, T_STRING, CT::T_ARRAY_TYPEHINT, T_CALLABLE])) {
  20739. $type .= $tokens[$index]->getContent();
  20740. $index = $tokens->getNextMeaningfulToken($index);
  20741. }
  20742. return [
  20743. 'type' => '' === $type ? null : $type,
  20744. 'allows_null' => $allowsNull,
  20745. ];
  20746. }
  20747. private function annotationIsSuperfluous(Annotation $annotation, array $info, array $symbolShortNames)
  20748. {
  20749. if ('param' === $annotation->getTag()->getName()) {
  20750. $regex = '/@param\s+(?:\S|\s(?!\$))++\s\$\S+\s+\S/';
  20751. } elseif ('var' === $annotation->getTag()->getName()) {
  20752. $regex = '/@var\s+\S+(\s+\$\S+)?(\s+)([^$\s]+)/';
  20753. } else {
  20754. $regex = '/@return\s+\S+\s+\S/';
  20755. }
  20756. if (Preg::match($regex, $annotation->getContent())) {
  20757. return false;
  20758. }
  20759. $annotationTypes = $this->toComparableNames($annotation->getTypes(), $symbolShortNames);
  20760. if (['null'] === $annotationTypes) {
  20761. return false;
  20762. }
  20763. if (['mixed'] === $annotationTypes && null === $info['type']) {
  20764. return !$this->configuration['allow_mixed'];
  20765. }
  20766. $actualTypes = null === $info['type'] ? [] : [$info['type']];
  20767. if ($info['allows_null']) {
  20768. $actualTypes[] = 'null';
  20769. }
  20770. return $annotationTypes === $this->toComparableNames($actualTypes, $symbolShortNames);
  20771. }
  20772. private function toComparableNames(array $types, array $symbolShortNames)
  20773. {
  20774. $normalized = array_map(
  20775. static function ($type) use ($symbolShortNames) {
  20776. $type = strtolower($type);
  20777. if (isset($symbolShortNames[$type])) {
  20778. return $symbolShortNames[$type];
  20779. }
  20780. return $type;
  20781. },
  20782. $types
  20783. );
  20784. sort($normalized);
  20785. return $normalized;
  20786. }
  20787. private function removeSuperfluousInheritDoc($docComment)
  20788. {
  20789. return Preg::replace('~
  20790. # $1: before @inheritDoc tag
  20791. (
  20792. # beginning of comment or a PHPDoc tag
  20793. (?:
  20794. ^/\*\*
  20795. (?:
  20796. \R
  20797. [ \t]*(?:\*[ \t]*)?
  20798. )*?
  20799. |
  20800. @\N+
  20801. )
  20802. # empty comment lines
  20803. (?:
  20804. \R
  20805. [ \t]*(?:\*[ \t]*?)?
  20806. )*
  20807. )
  20808. # spaces before @inheritDoc tag
  20809. [ \t]*
  20810. # @inheritDoc tag
  20811. (?:@inheritDocs?|\{@inheritDocs?\})
  20812. # $2: after @inheritDoc tag
  20813. (
  20814. # empty comment lines
  20815. (?:
  20816. \R
  20817. [ \t]*(?:\*[ \t]*)?
  20818. )*
  20819. # a PHPDoc tag or end of comment
  20820. (?:
  20821. @\N+
  20822. |
  20823. (?:
  20824. \R
  20825. [ \t]*(?:\*[ \t]*)?
  20826. )*
  20827. [ \t]*\*/$
  20828. )
  20829. )
  20830. ~ix', '$1$2', $docComment);
  20831. }
  20832. }
  20833. <?php
  20834. namespace PhpCsFixer\Fixer\Phpdoc;
  20835. use PhpCsFixer\AbstractFixer;
  20836. use PhpCsFixer\FixerDefinition\CodeSample;
  20837. use PhpCsFixer\FixerDefinition\FixerDefinition;
  20838. use PhpCsFixer\Preg;
  20839. use PhpCsFixer\Tokenizer\Token;
  20840. use PhpCsFixer\Tokenizer\Tokens;
  20841. final class PhpdocInlineTagFixer extends AbstractFixer
  20842. {
  20843. public function getDefinition()
  20844. {
  20845. return new FixerDefinition(
  20846. 'Fix PHPDoc inline tags, make `@inheritdoc` always inline.',
  20847. [new CodeSample(
  20848. '<?php
  20849. /**
  20850. * @{TUTORIAL}
  20851. * {{ @link }}
  20852. * {@examples}
  20853. * @inheritdocs
  20854. */
  20855. '
  20856. )]
  20857. );
  20858. }
  20859. public function getPriority()
  20860. {
  20861. return 0;
  20862. }
  20863. public function isCandidate(Tokens $tokens)
  20864. {
  20865. return $tokens->isTokenKindFound(T_DOC_COMMENT);
  20866. }
  20867. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  20868. {
  20869. foreach ($tokens as $index => $token) {
  20870. if (!$token->isGivenKind(T_DOC_COMMENT)) {
  20871. continue;
  20872. }
  20873. $content = $token->getContent();
  20874. $content = Preg::replaceCallback(
  20875. '#(?:@{+|{+\h*@)[ \t]*(example|id|internal|inheritdoc|link|source|toc|tutorial)s?([^}]*)(?:}+)#i',
  20876. static function (array $matches) {
  20877. $doc = trim($matches[2]);
  20878. if ('' === $doc) {
  20879. return '{@'.strtolower($matches[1]).'}';
  20880. }
  20881. return '{@'.strtolower($matches[1]).' '.$doc.'}';
  20882. },
  20883. $content
  20884. );
  20885. $content = Preg::replace(
  20886. '#(?<!{)@inheritdocs?(?!})#i',
  20887. '{@inheritdoc}',
  20888. $content
  20889. );
  20890. $tokens[$index] = new Token([T_DOC_COMMENT, $content]);
  20891. }
  20892. }
  20893. }
  20894. <?php
  20895. namespace PhpCsFixer\Fixer\Phpdoc;
  20896. use PhpCsFixer\AbstractFixer;
  20897. use PhpCsFixer\DocBlock\DocBlock;
  20898. use PhpCsFixer\FixerDefinition\CodeSample;
  20899. use PhpCsFixer\FixerDefinition\FixerDefinition;
  20900. use PhpCsFixer\Tokenizer\Token;
  20901. use PhpCsFixer\Tokenizer\Tokens;
  20902. final class PhpdocOrderFixer extends AbstractFixer
  20903. {
  20904. public function isCandidate(Tokens $tokens)
  20905. {
  20906. return $tokens->isTokenKindFound(T_DOC_COMMENT);
  20907. }
  20908. public function getDefinition()
  20909. {
  20910. return new FixerDefinition(
  20911. 'Annotations in PHPDoc should be ordered so that `@param` annotations come first, then `@throws` annotations, then `@return` annotations.',
  20912. [
  20913. new CodeSample(
  20914. '<?php
  20915. /**
  20916. * Hello there!
  20917. *
  20918. * @throws Exception|RuntimeException foo
  20919. * @custom Test!
  20920. * @return int Return the number of changes.
  20921. * @param string $foo
  20922. * @param bool $bar Bar
  20923. */
  20924. '
  20925. ),
  20926. ]
  20927. );
  20928. }
  20929. public function getPriority()
  20930. {
  20931. return -2;
  20932. }
  20933. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  20934. {
  20935. foreach ($tokens as $index => $token) {
  20936. if (!$token->isGivenKind(T_DOC_COMMENT)) {
  20937. continue;
  20938. }
  20939. $content = $token->getContent();
  20940. $content = $this->moveParamAnnotations($content);
  20941. $content = $this->moveReturnAnnotations($content);
  20942. $tokens[$index] = new Token([T_DOC_COMMENT, $content]);
  20943. }
  20944. }
  20945. private function moveParamAnnotations($content)
  20946. {
  20947. $doc = new DocBlock($content);
  20948. $params = $doc->getAnnotationsOfType('param');
  20949. if (empty($params)) {
  20950. return $content;
  20951. }
  20952. $others = $doc->getAnnotationsOfType(['throws', 'return']);
  20953. if (empty($others)) {
  20954. return $content;
  20955. }
  20956. $end = end($params)->getEnd();
  20957. $line = $doc->getLine($end);
  20958. foreach ($others as $other) {
  20959. if ($other->getStart() < $end) {
  20960. $line->setContent($line->getContent().$other->getContent());
  20961. $other->remove();
  20962. }
  20963. }
  20964. return $doc->getContent();
  20965. }
  20966. private function moveReturnAnnotations($content)
  20967. {
  20968. $doc = new DocBlock($content);
  20969. $returns = $doc->getAnnotationsOfType('return');
  20970. if (empty($returns)) {
  20971. return $content;
  20972. }
  20973. $others = $doc->getAnnotationsOfType(['param', 'throws']);
  20974. if (empty($others)) {
  20975. return $content;
  20976. }
  20977. $start = $returns[0]->getStart();
  20978. $line = $doc->getLine($start);
  20979. foreach (array_reverse($others) as $other) {
  20980. if ($other->getEnd() > $start) {
  20981. $line->setContent($other->getContent().$line->getContent());
  20982. $other->remove();
  20983. }
  20984. }
  20985. return $doc->getContent();
  20986. }
  20987. }
  20988. <?php
  20989. namespace PhpCsFixer\Fixer\Phpdoc;
  20990. use PhpCsFixer\AbstractFixer;
  20991. use PhpCsFixer\FixerDefinition\CodeSample;
  20992. use PhpCsFixer\FixerDefinition\FixerDefinition;
  20993. use PhpCsFixer\Preg;
  20994. use PhpCsFixer\Tokenizer\Tokens;
  20995. final class NoEmptyPhpdocFixer extends AbstractFixer
  20996. {
  20997. public function getDefinition()
  20998. {
  20999. return new FixerDefinition(
  21000. 'There should not be empty PHPDoc blocks.',
  21001. [new CodeSample("<?php /** */\n")]
  21002. );
  21003. }
  21004. public function getPriority()
  21005. {
  21006. return 5;
  21007. }
  21008. public function isCandidate(Tokens $tokens)
  21009. {
  21010. return $tokens->isTokenKindFound(T_DOC_COMMENT);
  21011. }
  21012. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  21013. {
  21014. foreach ($tokens as $index => $token) {
  21015. if (!$token->isGivenKind(T_DOC_COMMENT)) {
  21016. continue;
  21017. }
  21018. if (Preg::match('#^/\*\*[\s\*]*\*/$#', $token->getContent())) {
  21019. $tokens->clearTokenAndMergeSurroundingWhitespace($index);
  21020. }
  21021. }
  21022. }
  21023. }
  21024. <?php
  21025. namespace PhpCsFixer\Fixer\Phpdoc;
  21026. use PhpCsFixer\AbstractProxyFixer;
  21027. use PhpCsFixer\FixerDefinition\CodeSample;
  21028. use PhpCsFixer\FixerDefinition\FixerDefinition;
  21029. /**
  21030. @gmail
  21031. */
  21032. final class PhpdocNoPackageFixer extends AbstractProxyFixer
  21033. {
  21034. public function getDefinition()
  21035. {
  21036. return new FixerDefinition(
  21037. '`@package` and `@subpackage` annotations should be omitted from PHPDoc.',
  21038. [
  21039. new CodeSample(
  21040. '<?php
  21041. /**
  21042. * @internal
  21043. * @package Foo
  21044. * subpackage Bar
  21045. */
  21046. class Baz
  21047. {
  21048. }
  21049. '
  21050. ),
  21051. ]
  21052. );
  21053. }
  21054. public function getPriority()
  21055. {
  21056. return parent::getPriority();
  21057. }
  21058. protected function createProxyFixers()
  21059. {
  21060. $fixer = new GeneralPhpdocAnnotationRemoveFixer();
  21061. $fixer->configure(['annotations' => ['package', 'subpackage']]);
  21062. return [$fixer];
  21063. }
  21064. }
  21065. <?php
  21066. namespace PhpCsFixer\Fixer\Phpdoc;
  21067. use PhpCsFixer\AbstractFixer;
  21068. use PhpCsFixer\DocBlock\Annotation;
  21069. use PhpCsFixer\DocBlock\DocBlock;
  21070. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  21071. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  21072. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  21073. use PhpCsFixer\FixerDefinition\CodeSample;
  21074. use PhpCsFixer\FixerDefinition\FixerDefinition;
  21075. use PhpCsFixer\Preg;
  21076. use PhpCsFixer\Tokenizer\Token;
  21077. use PhpCsFixer\Tokenizer\Tokens;
  21078. use PhpCsFixer\Utils;
  21079. final class PhpdocTypesOrderFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface
  21080. {
  21081. public function getDefinition()
  21082. {
  21083. return new FixerDefinition(
  21084. 'Sorts PHPDoc types.',
  21085. [
  21086. new CodeSample(
  21087. '<?php
  21088. /**
  21089. * @param string|null $bar
  21090. */
  21091. '
  21092. ),
  21093. new CodeSample(
  21094. '<?php
  21095. /**
  21096. * @param null|string $bar
  21097. */
  21098. ',
  21099. ['null_adjustment' => 'always_last']
  21100. ),
  21101. new CodeSample(
  21102. '<?php
  21103. /**
  21104. * @param null|string|int|\Foo $bar
  21105. */
  21106. ',
  21107. ['sort_algorithm' => 'alpha']
  21108. ),
  21109. new CodeSample(
  21110. '<?php
  21111. /**
  21112. * @param null|string|int|\Foo $bar
  21113. */
  21114. ',
  21115. [
  21116. 'sort_algorithm' => 'alpha',
  21117. 'null_adjustment' => 'always_last',
  21118. ]
  21119. ),
  21120. new CodeSample(
  21121. '<?php
  21122. /**
  21123. * @param null|string|int|\Foo $bar
  21124. */
  21125. ',
  21126. [
  21127. 'sort_algorithm' => 'alpha',
  21128. 'null_adjustment' => 'none',
  21129. ]
  21130. ),
  21131. ]
  21132. );
  21133. }
  21134. public function getPriority()
  21135. {
  21136. return 0;
  21137. }
  21138. public function isCandidate(Tokens $tokens)
  21139. {
  21140. return $tokens->isTokenKindFound(T_DOC_COMMENT);
  21141. }
  21142. protected function createConfigurationDefinition()
  21143. {
  21144. return new FixerConfigurationResolver([
  21145. (new FixerOptionBuilder('sort_algorithm', 'The sorting algorithm to apply.'))
  21146. ->setAllowedValues(['alpha', 'none'])
  21147. ->setDefault('alpha')
  21148. ->getOption(),
  21149. (new FixerOptionBuilder('null_adjustment', 'Forces the position of `null` (overrides `sort_algorithm`).'))
  21150. ->setAllowedValues(['always_first', 'always_last', 'none'])
  21151. ->setDefault('always_first')
  21152. ->getOption(),
  21153. ]);
  21154. }
  21155. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  21156. {
  21157. foreach ($tokens as $index => $token) {
  21158. if (!$token->isGivenKind(T_DOC_COMMENT)) {
  21159. continue;
  21160. }
  21161. $doc = new DocBlock($token->getContent());
  21162. $annotations = $doc->getAnnotationsOfType(Annotation::getTagsWithTypes());
  21163. if (!\count($annotations)) {
  21164. continue;
  21165. }
  21166. foreach ($annotations as $annotation) {
  21167. $types = $annotation->getTypes();
  21168. $annotation->setTypes($this->sortTypes($types));
  21169. $line = $doc->getLine($annotation->getStart());
  21170. $line->setContent(Preg::replaceCallback('/(@method\s+.+?\s+\w+\()(.*)\)/', function (array $matches) {
  21171. $sorted = Preg::replaceCallback('/([^\s,]+)([\s]+\$[^\s,]+)/', function (array $matches) {
  21172. return $this->sortJoinedTypes($matches[1]).$matches[2];
  21173. }, $matches[2]);
  21174. return $matches[1].$sorted.')';
  21175. }, $line->getContent()));
  21176. }
  21177. $tokens[$index] = new Token([T_DOC_COMMENT, $doc->getContent()]);
  21178. }
  21179. }
  21180. private function sortTypes(array $types)
  21181. {
  21182. foreach ($types as $index => $type) {
  21183. $types[$index] = Preg::replaceCallback('/^([^<]+)<(?:([\w\|]+?)(,\s*))?(.*)>$/', function (array $matches) {
  21184. return $matches[1].'<'.$this->sortJoinedTypes($matches[2]).$matches[3].$this->sortJoinedTypes($matches[4]).'>';
  21185. }, $type);
  21186. }
  21187. if ('alpha' === $this->configuration['sort_algorithm']) {
  21188. $types = Utils::stableSort(
  21189. $types,
  21190. static function ($type) { return $type; },
  21191. static function ($typeA, $typeB) {
  21192. $regexp = '/^\\??\\\?/';
  21193. return strcasecmp(
  21194. Preg::replace($regexp, '', $typeA),
  21195. Preg::replace($regexp, '', $typeB)
  21196. );
  21197. }
  21198. );
  21199. }
  21200. if ('none' !== $this->configuration['null_adjustment']) {
  21201. $nulls = [];
  21202. foreach ($types as $index => $type) {
  21203. if (Preg::match('/^\\\?null$/i', $type)) {
  21204. $nulls[$index] = $type;
  21205. unset($types[$index]);
  21206. }
  21207. }
  21208. if (\count($nulls)) {
  21209. if ('always_last' === $this->configuration['null_adjustment']) {
  21210. array_push($types, ...$nulls);
  21211. } else {
  21212. array_unshift($types, ...$nulls);
  21213. }
  21214. }
  21215. }
  21216. return $types;
  21217. }
  21218. private function sortJoinedTypes($types)
  21219. {
  21220. $types = array_filter(
  21221. Preg::split('/([^|<]+(?:<.*>)?)/', $types, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY),
  21222. static function ($value) {
  21223. return '|' !== $value;
  21224. }
  21225. );
  21226. return implode('|', $this->sortTypes($types));
  21227. }
  21228. }
  21229. <?php
  21230. namespace PhpCsFixer\Fixer\Phpdoc;
  21231. use PhpCsFixer\AbstractFixer;
  21232. use PhpCsFixer\FixerDefinition\CodeSample;
  21233. use PhpCsFixer\FixerDefinition\FixerDefinition;
  21234. use PhpCsFixer\Preg;
  21235. use PhpCsFixer\Tokenizer\Token;
  21236. use PhpCsFixer\Tokenizer\Tokens;
  21237. final class PhpdocVarAnnotationCorrectOrderFixer extends AbstractFixer
  21238. {
  21239. public function getDefinition()
  21240. {
  21241. return new FixerDefinition(
  21242. '`@var` and `@type` annotations must have type and name in the correct order.',
  21243. [new CodeSample('<?php
  21244. /** @var $foo int */
  21245. $foo = 2 + 2;
  21246. ')]
  21247. );
  21248. }
  21249. public function getPriority()
  21250. {
  21251. return 0;
  21252. }
  21253. public function isCandidate(Tokens $tokens)
  21254. {
  21255. return $tokens->isTokenKindFound(T_DOC_COMMENT);
  21256. }
  21257. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  21258. {
  21259. foreach ($tokens as $index => $token) {
  21260. if (!$token->isGivenKind(T_DOC_COMMENT)) {
  21261. continue;
  21262. }
  21263. if (false === stripos($token->getContent(), '@var') && false === stripos($token->getContent(), '@type')) {
  21264. continue;
  21265. }
  21266. $newContent = Preg::replace(
  21267. '/(@(?:type|var)\s*)(\$\S+)(\h+)([^\$](?:[^<\s]|<[^>]*>)*)(\s|\*)/i',
  21268. '$1$4$3$2$5',
  21269. $token->getContent()
  21270. );
  21271. if ($newContent === $token->getContent()) {
  21272. continue;
  21273. }
  21274. $tokens[$index] = new Token([$token->getId(), $newContent]);
  21275. }
  21276. }
  21277. }
  21278. <?php
  21279. namespace PhpCsFixer\Fixer\Phpdoc;
  21280. use PhpCsFixer\AbstractFixer;
  21281. use PhpCsFixer\DocBlock\DocBlock;
  21282. use PhpCsFixer\DocBlock\ShortDescription;
  21283. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  21284. use PhpCsFixer\FixerDefinition\CodeSample;
  21285. use PhpCsFixer\FixerDefinition\FixerDefinition;
  21286. use PhpCsFixer\Tokenizer\Token;
  21287. use PhpCsFixer\Tokenizer\Tokens;
  21288. final class PhpdocSummaryFixer extends AbstractFixer implements WhitespacesAwareFixerInterface
  21289. {
  21290. public function getDefinition()
  21291. {
  21292. return new FixerDefinition(
  21293. 'PHPDoc summary should end in either a full stop, exclamation mark, or question mark.',
  21294. [new CodeSample('<?php
  21295. /**
  21296. * Foo function is great
  21297. */
  21298. function foo () {}
  21299. ')]
  21300. );
  21301. }
  21302. public function getPriority()
  21303. {
  21304. return 0;
  21305. }
  21306. public function isCandidate(Tokens $tokens)
  21307. {
  21308. return $tokens->isTokenKindFound(T_DOC_COMMENT);
  21309. }
  21310. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  21311. {
  21312. foreach ($tokens as $index => $token) {
  21313. if (!$token->isGivenKind(T_DOC_COMMENT)) {
  21314. continue;
  21315. }
  21316. $doc = new DocBlock($token->getContent());
  21317. $end = (new ShortDescription($doc))->getEnd();
  21318. if (null !== $end) {
  21319. $line = $doc->getLine($end);
  21320. $content = rtrim($line->getContent());
  21321. if (!$this->isCorrectlyFormatted($content)) {
  21322. $line->setContent($content.'.'.$this->whitespacesConfig->getLineEnding());
  21323. $tokens[$index] = new Token([T_DOC_COMMENT, $doc->getContent()]);
  21324. }
  21325. }
  21326. }
  21327. }
  21328. private function isCorrectlyFormatted($content)
  21329. {
  21330. if (false !== stripos($content, '{@inheritdoc}')) {
  21331. return true;
  21332. }
  21333. return $content !== rtrim($content, '.。!?¡¿�?');
  21334. }
  21335. }
  21336. <?php
  21337. namespace PhpCsFixer\Fixer\Phpdoc;
  21338. use PhpCsFixer\AbstractPhpdocTypesFixer;
  21339. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  21340. use PhpCsFixer\FixerConfiguration\AllowedValueSubset;
  21341. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  21342. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  21343. use PhpCsFixer\FixerDefinition\CodeSample;
  21344. use PhpCsFixer\FixerDefinition\FixerDefinition;
  21345. /**
  21346. @gmail
  21347. */
  21348. final class PhpdocTypesFixer extends AbstractPhpdocTypesFixer implements ConfigurationDefinitionFixerInterface
  21349. {
  21350. private static $possibleTypes = [
  21351. 'simple' => [
  21352. 'array',
  21353. 'bool',
  21354. 'callable',
  21355. 'float',
  21356. 'int',
  21357. 'iterable',
  21358. 'null',
  21359. 'object',
  21360. 'string',
  21361. ],
  21362. 'alias' => [
  21363. 'boolean',
  21364. 'callback',
  21365. 'double',
  21366. 'integer',
  21367. 'real',
  21368. ],
  21369. 'meta' => [
  21370. '$this',
  21371. 'false',
  21372. 'mixed',
  21373. 'parent',
  21374. 'resource',
  21375. 'scalar',
  21376. 'self',
  21377. 'static',
  21378. 'true',
  21379. 'void',
  21380. ],
  21381. ];
  21382. private $typesToFix = [];
  21383. public function configure(array $configuration = null)
  21384. {
  21385. parent::configure($configuration);
  21386. $this->typesToFix = array_merge(...array_map(static function ($group) {
  21387. return self::$possibleTypes[$group];
  21388. }, $this->configuration['groups']));
  21389. }
  21390. public function getDefinition()
  21391. {
  21392. return new FixerDefinition(
  21393. 'The correct case must be used for standard PHP types in PHPDoc.',
  21394. [
  21395. new CodeSample(
  21396. '<?php
  21397. /**
  21398. * @param STRING|String[] $bar
  21399. *
  21400. * @return inT[]
  21401. */
  21402. '
  21403. ),
  21404. new CodeSample(
  21405. '<?php
  21406. /**
  21407. * @param BOOL $foo
  21408. *
  21409. * @return MIXED
  21410. */
  21411. ',
  21412. ['groups' => ['simple', 'alias']]
  21413. ),
  21414. ]
  21415. );
  21416. }
  21417. public function getPriority()
  21418. {
  21419. return 16;
  21420. }
  21421. protected function normalize($type)
  21422. {
  21423. $lower = strtolower($type);
  21424. if (\in_array($lower, $this->typesToFix, true)) {
  21425. return $lower;
  21426. }
  21427. return $type;
  21428. }
  21429. protected function createConfigurationDefinition()
  21430. {
  21431. $possibleGroups = array_keys(self::$possibleTypes);
  21432. return new FixerConfigurationResolver([
  21433. (new FixerOptionBuilder('groups', 'Type groups to fix.'))
  21434. ->setAllowedTypes(['array'])
  21435. ->setAllowedValues([new AllowedValueSubset($possibleGroups)])
  21436. ->setDefault($possibleGroups)
  21437. ->getOption(),
  21438. ]);
  21439. }
  21440. }
  21441. <?php
  21442. namespace PhpCsFixer\Fixer\Phpdoc;
  21443. use PhpCsFixer\AbstractFixer;
  21444. use PhpCsFixer\DocBlock\DocBlock;
  21445. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  21446. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverRootless;
  21447. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  21448. use PhpCsFixer\FixerDefinition\CodeSample;
  21449. use PhpCsFixer\FixerDefinition\FixerDefinition;
  21450. use PhpCsFixer\Preg;
  21451. use PhpCsFixer\Tokenizer\Token;
  21452. use PhpCsFixer\Tokenizer\Tokens;
  21453. use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException;
  21454. use Symfony\Component\OptionsResolver\Options;
  21455. /**
  21456. @gmail
  21457. */
  21458. final class PhpdocNoAliasTagFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface
  21459. {
  21460. public function isCandidate(Tokens $tokens)
  21461. {
  21462. return $tokens->isTokenKindFound(T_DOC_COMMENT);
  21463. }
  21464. public function getDefinition()
  21465. {
  21466. return new FixerDefinition(
  21467. 'No alias PHPDoc tags should be used.',
  21468. [
  21469. new CodeSample(
  21470. '<?php
  21471. /**
  21472. * @property string $foo
  21473. * @property-read string $bar
  21474. *
  21475. * @link baz
  21476. */
  21477. final class Example
  21478. {
  21479. }
  21480. '
  21481. ),
  21482. new CodeSample(
  21483. '<?php
  21484. /**
  21485. * @property string $foo
  21486. * @property-read string $bar
  21487. *
  21488. * @link baz
  21489. */
  21490. final class Example
  21491. {
  21492. }
  21493. ',
  21494. ['replacements' => ['link' => 'website']]
  21495. ),
  21496. ]
  21497. );
  21498. }
  21499. public function getPriority()
  21500. {
  21501. return 11;
  21502. }
  21503. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  21504. {
  21505. $searchFor = array_keys($this->configuration['replacements']);
  21506. foreach ($tokens as $index => $token) {
  21507. if (!$token->isGivenKind(T_DOC_COMMENT)) {
  21508. continue;
  21509. }
  21510. $doc = new DocBlock($token->getContent());
  21511. $annotations = $doc->getAnnotationsOfType($searchFor);
  21512. if (empty($annotations)) {
  21513. continue;
  21514. }
  21515. foreach ($annotations as $annotation) {
  21516. $annotation->getTag()->setName($this->configuration['replacements'][$annotation->getTag()->getName()]);
  21517. }
  21518. $tokens[$index] = new Token([T_DOC_COMMENT, $doc->getContent()]);
  21519. }
  21520. }
  21521. protected function createConfigurationDefinition()
  21522. {
  21523. return new FixerConfigurationResolverRootless('replacements', [
  21524. (new FixerOptionBuilder('replacements', 'Mapping between replaced annotations with new ones.'))
  21525. ->setAllowedTypes(['array'])
  21526. ->setNormalizer(static function (Options $options, $value) {
  21527. $normalizedValue = [];
  21528. foreach ($value as $from => $to) {
  21529. if (!\is_string($from)) {
  21530. throw new InvalidOptionsException('Tag to replace must be a string.');
  21531. }
  21532. if (!\is_string($to)) {
  21533. throw new InvalidOptionsException(sprintf(
  21534. 'Tag to replace to from "%s" must be a string.',
  21535. $from
  21536. ));
  21537. }
  21538. if (1 !== Preg::match('#^\S+$#', $to) || false !== strpos($to, '*/')) {
  21539. throw new InvalidOptionsException(sprintf(
  21540. 'Tag "%s" cannot be replaced by invalid tag "%s".',
  21541. $from,
  21542. $to
  21543. ));
  21544. }
  21545. $normalizedValue[trim($from)] = trim($to);
  21546. }
  21547. foreach ($normalizedValue as $from => $to) {
  21548. if (isset($normalizedValue[$to])) {
  21549. throw new InvalidOptionsException(sprintf(
  21550. 'Cannot change tag "%1$s" to tag "%2$s", as the tag "%2$s" is configured to be replaced to "%3$s".',
  21551. $from,
  21552. $to,
  21553. $normalizedValue[$to]
  21554. ));
  21555. }
  21556. }
  21557. return $normalizedValue;
  21558. })
  21559. ->setDefault([
  21560. 'property-read' => 'property',
  21561. 'property-write' => 'property',
  21562. 'type' => 'var',
  21563. 'link' => 'see',
  21564. ])
  21565. ->getOption(),
  21566. ], $this->getName());
  21567. }
  21568. }
  21569. <?php
  21570. namespace PhpCsFixer\Fixer\Phpdoc;
  21571. use PhpCsFixer\AbstractFixer;
  21572. use PhpCsFixer\FixerDefinition\CodeSample;
  21573. use PhpCsFixer\FixerDefinition\FixerDefinition;
  21574. use PhpCsFixer\Preg;
  21575. use PhpCsFixer\Tokenizer\Token;
  21576. use PhpCsFixer\Tokenizer\Tokens;
  21577. use PhpCsFixer\Utils;
  21578. /**
  21579. @alt
  21580. */
  21581. final class PhpdocIndentFixer extends AbstractFixer
  21582. {
  21583. public function getDefinition()
  21584. {
  21585. return new FixerDefinition(
  21586. 'Docblocks should have the same indentation as the documented subject.',
  21587. [new CodeSample('<?php
  21588. class DocBlocks
  21589. {
  21590. /**
  21591. * Test constants
  21592. */
  21593. const INDENT = 1;
  21594. }
  21595. ')]
  21596. );
  21597. }
  21598. public function getPriority()
  21599. {
  21600. return 20;
  21601. }
  21602. public function isCandidate(Tokens $tokens)
  21603. {
  21604. return $tokens->isTokenKindFound(T_DOC_COMMENT);
  21605. }
  21606. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  21607. {
  21608. foreach ($tokens as $index => $token) {
  21609. if (!$token->isGivenKind(T_DOC_COMMENT)) {
  21610. continue;
  21611. }
  21612. $nextIndex = $tokens->getNextMeaningfulToken($index);
  21613. if (null === $nextIndex || $tokens[$nextIndex]->equals('}')) {
  21614. continue;
  21615. }
  21616. $prevIndex = $index - 1;
  21617. $prevToken = $tokens[$prevIndex];
  21618. if (
  21619. $prevToken->isGivenKind(T_OPEN_TAG)
  21620. || ($prevToken->isWhitespace(" \t") && !$tokens[$index - 2]->isGivenKind(T_OPEN_TAG))
  21621. || $prevToken->equalsAny([';', ',', '{', '('])
  21622. ) {
  21623. continue;
  21624. }
  21625. $indent = '';
  21626. if ($tokens[$nextIndex - 1]->isWhitespace()) {
  21627. $indent = Utils::calculateTrailingWhitespaceIndent($tokens[$nextIndex - 1]);
  21628. }
  21629. $newPrevContent = $this->fixWhitespaceBeforeDocblock($prevToken->getContent(), $indent);
  21630. if ($newPrevContent) {
  21631. if ($prevToken->isArray()) {
  21632. $tokens[$prevIndex] = new Token([$prevToken->getId(), $newPrevContent]);
  21633. } else {
  21634. $tokens[$prevIndex] = new Token($newPrevContent);
  21635. }
  21636. } else {
  21637. $tokens->clearAt($prevIndex);
  21638. }
  21639. $tokens[$index] = new Token([T_DOC_COMMENT, $this->fixDocBlock($token->getContent(), $indent)]);
  21640. }
  21641. }
  21642. private function fixDocBlock($content, $indent)
  21643. {
  21644. return ltrim(Preg::replace('/^\h*\*/m', $indent.' *', $content));
  21645. }
  21646. private function fixWhitespaceBeforeDocblock($content, $indent)
  21647. {
  21648. return rtrim($content, " \t").$indent;
  21649. }
  21650. }
  21651. <?php
  21652. namespace PhpCsFixer\Fixer\Phpdoc;
  21653. use PhpCsFixer\AbstractFixer;
  21654. use PhpCsFixer\DocBlock\DocBlock;
  21655. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  21656. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  21657. use PhpCsFixer\FixerConfiguration\AllowedValueSubset;
  21658. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  21659. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  21660. use PhpCsFixer\FixerDefinition\CodeSample;
  21661. use PhpCsFixer\FixerDefinition\FixerDefinition;
  21662. use PhpCsFixer\Preg;
  21663. use PhpCsFixer\Tokenizer\Token;
  21664. use PhpCsFixer\Tokenizer\Tokens;
  21665. /**
  21666. @seld
  21667. @rollerscapes
  21668. @alt
  21669. @gmail
  21670. */
  21671. final class PhpdocAlignFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface, WhitespacesAwareFixerInterface
  21672. {
  21673. const ALIGN_LEFT = 'left';
  21674. const ALIGN_VERTICAL = 'vertical';
  21675. private $regex;
  21676. private $regexCommentLine;
  21677. private $align;
  21678. private static $alignableTags = [
  21679. 'param',
  21680. 'property',
  21681. 'property-read',
  21682. 'property-write',
  21683. 'return',
  21684. 'throws',
  21685. 'type',
  21686. 'var',
  21687. 'method',
  21688. ];
  21689. private static $tagsWithName = [
  21690. 'param',
  21691. 'property',
  21692. ];
  21693. private static $tagsWithMethodSignature = [
  21694. 'method',
  21695. ];
  21696. public function configure(array $configuration = null)
  21697. {
  21698. parent::configure($configuration);
  21699. $tagsWithNameToAlign = array_intersect($this->configuration['tags'], self::$tagsWithName);
  21700. $tagsWithMethodSignatureToAlign = array_intersect($this->configuration['tags'], self::$tagsWithMethodSignature);
  21701. $tagsWithoutNameToAlign = array_diff($this->configuration['tags'], $tagsWithNameToAlign, $tagsWithMethodSignatureToAlign);
  21702. $types = [];
  21703. $indent = '(?P<indent>(?: {2}|\t)*)';
  21704. if (!empty($tagsWithNameToAlign)) {
  21705. $types[] = '(?P<tag>'.implode('|', $tagsWithNameToAlign).')\s+(?P<hint>[^$]+?)\s+(?P<var>(?:&|\.{3})?\$[^\s]+)';
  21706. }
  21707. if (!empty($tagsWithoutNameToAlign)) {
  21708. $types[] = '(?P<tag2>'.implode('|', $tagsWithoutNameToAlign).')\s+(?P<hint2>[^\s]+?)';
  21709. }
  21710. if (!empty($tagsWithMethodSignatureToAlign)) {
  21711. $types[] = '(?P<tag3>'.implode('|', $tagsWithMethodSignatureToAlign).')(\s+(?P<hint3>[^\s(]+)|)\s+(?P<signature>.+\))';
  21712. }
  21713. $desc = '(?:\s+(?P<desc>\V*))';
  21714. $this->regex = '/^'.$indent.' \* @(?:'.implode('|', $types).')'.$desc.'\s*$/u';
  21715. $this->regexCommentLine = '/^'.$indent.' \*(?! @)(?:\s+(?P<desc>\V+))(?<!\*\/)\r?$/u';
  21716. $this->align = $this->configuration['align'];
  21717. }
  21718. public function getDefinition()
  21719. {
  21720. $code = <<<'EOF'
  21721. <?php
  21722. /**
  21723. * @param EngineInterface $templating
  21724. * @param string $format
  21725. * @param int $code an HTTP response status code
  21726. * @param bool $debug
  21727. * @param mixed &$reference a parameter passed by reference
  21728. */
  21729. EOF;
  21730. return new FixerDefinition(
  21731. 'All items of the given phpdoc tags must be either left-aligned or (by default) aligned vertically.',
  21732. [
  21733. new CodeSample($code),
  21734. new CodeSample($code, ['align' => self::ALIGN_VERTICAL]),
  21735. new CodeSample($code, ['align' => self::ALIGN_LEFT]),
  21736. ]
  21737. );
  21738. }
  21739. public function getPriority()
  21740. {
  21741. return -21;
  21742. }
  21743. public function isCandidate(Tokens $tokens)
  21744. {
  21745. return $tokens->isTokenKindFound(T_DOC_COMMENT);
  21746. }
  21747. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  21748. {
  21749. foreach ($tokens as $index => $token) {
  21750. if (!$token->isGivenKind(T_DOC_COMMENT)) {
  21751. continue;
  21752. }
  21753. $content = $token->getContent();
  21754. $docBlock = new DocBlock($content);
  21755. $this->fixDocBlock($docBlock);
  21756. $newContent = $docBlock->getContent();
  21757. if ($newContent !== $content) {
  21758. $tokens[$index] = new Token([T_DOC_COMMENT, $newContent]);
  21759. }
  21760. }
  21761. }
  21762. protected function createConfigurationDefinition()
  21763. {
  21764. $tags = new FixerOptionBuilder('tags', 'The tags that should be aligned.');
  21765. $tags
  21766. ->setAllowedTypes(['array'])
  21767. ->setAllowedValues([new AllowedValueSubset(self::$alignableTags)])
  21768. ->setDefault([
  21769. 'param',
  21770. 'return',
  21771. 'throws',
  21772. 'type',
  21773. 'var',
  21774. ])
  21775. ;
  21776. $align = new FixerOptionBuilder('align', 'Align comments');
  21777. $align
  21778. ->setAllowedTypes(['string'])
  21779. ->setAllowedValues([self::ALIGN_LEFT, self::ALIGN_VERTICAL])
  21780. ->setDefault(self::ALIGN_VERTICAL)
  21781. ;
  21782. return new FixerConfigurationResolver([$tags->getOption(), $align->getOption()]);
  21783. }
  21784. private function fixDocBlock(DocBlock $docBlock)
  21785. {
  21786. $lineEnding = $this->whitespacesConfig->getLineEnding();
  21787. for ($i = 0, $l = \count($docBlock->getLines()); $i < $l; ++$i) {
  21788. $items = [];
  21789. $matches = $this->getMatches($docBlock->getLine($i)->getContent());
  21790. if (null === $matches) {
  21791. continue;
  21792. }
  21793. $current = $i;
  21794. $items[] = $matches;
  21795. while (true) {
  21796. if (null === $docBlock->getLine(++$i)) {
  21797. break 2;
  21798. }
  21799. $matches = $this->getMatches($docBlock->getLine($i)->getContent(), true);
  21800. if (null === $matches) {
  21801. break;
  21802. }
  21803. $items[] = $matches;
  21804. }
  21805. $tagMax = 0;
  21806. $hintMax = 0;
  21807. $varMax = 0;
  21808. foreach ($items as $item) {
  21809. if (null === $item['tag']) {
  21810. continue;
  21811. }
  21812. $tagMax = max($tagMax, \strlen($item['tag']));
  21813. $hintMax = max($hintMax, \strlen($item['hint']));
  21814. $varMax = max($varMax, \strlen($item['var']));
  21815. }
  21816. $currTag = null;
  21817. foreach ($items as $j => $item) {
  21818. if (null === $item['tag']) {
  21819. if ('@' === $item['desc'][0]) {
  21820. $docBlock->getLine($current + $j)->setContent($item['indent'].' * '.$item['desc'].$lineEnding);
  21821. continue;
  21822. }
  21823. $extraIndent = 2;
  21824. if (\in_array($currTag, self::$tagsWithName, true) || \in_array($currTag, self::$tagsWithMethodSignature, true)) {
  21825. $extraIndent = 3;
  21826. }
  21827. $line =
  21828. $item['indent']
  21829. .' * '
  21830. .$this->getIndent(
  21831. $tagMax + $hintMax + $varMax + $extraIndent,
  21832. $this->getLeftAlignedDescriptionIndent($items, $j)
  21833. )
  21834. .$item['desc']
  21835. .$lineEnding;
  21836. $docBlock->getLine($current + $j)->setContent($line);
  21837. continue;
  21838. }
  21839. $currTag = $item['tag'];
  21840. $line =
  21841. $item['indent']
  21842. .' * @'
  21843. .$item['tag']
  21844. .$this->getIndent(
  21845. $tagMax - \strlen($item['tag']) + 1,
  21846. $item['hint'] ? 1 : 0
  21847. )
  21848. .$item['hint']
  21849. ;
  21850. if (!empty($item['var'])) {
  21851. $line .=
  21852. $this->getIndent(($hintMax ?: -1) - \strlen($item['hint']) + 1)
  21853. .$item['var']
  21854. .(
  21855. !empty($item['desc'])
  21856. ? $this->getIndent($varMax - \strlen($item['var']) + 1).$item['desc'].$lineEnding
  21857. : $lineEnding
  21858. )
  21859. ;
  21860. } elseif (!empty($item['desc'])) {
  21861. $line .= $this->getIndent($hintMax - \strlen($item['hint']) + 1).$item['desc'].$lineEnding;
  21862. } else {
  21863. $line .= $lineEnding;
  21864. }
  21865. $docBlock->getLine($current + $j)->setContent($line);
  21866. }
  21867. }
  21868. }
  21869. private function getMatches($line, $matchCommentOnly = false)
  21870. {
  21871. if (Preg::match($this->regex, $line, $matches)) {
  21872. if (!empty($matches['tag2'])) {
  21873. $matches['tag'] = $matches['tag2'];
  21874. $matches['hint'] = $matches['hint2'];
  21875. $matches['var'] = '';
  21876. }
  21877. if (!empty($matches['tag3'])) {
  21878. $matches['tag'] = $matches['tag3'];
  21879. $matches['hint'] = $matches['hint3'];
  21880. $matches['var'] = $matches['signature'];
  21881. }
  21882. if (isset($matches['hint'])) {
  21883. $matches['hint'] = trim($matches['hint']);
  21884. }
  21885. return $matches;
  21886. }
  21887. if ($matchCommentOnly && Preg::match($this->regexCommentLine, $line, $matches)) {
  21888. $matches['tag'] = null;
  21889. $matches['var'] = '';
  21890. $matches['hint'] = '';
  21891. return $matches;
  21892. }
  21893. return null;
  21894. }
  21895. private function getIndent($verticalAlignIndent, $leftAlignIndent = 1)
  21896. {
  21897. $indent = self::ALIGN_VERTICAL === $this->align ? $verticalAlignIndent : $leftAlignIndent;
  21898. return str_repeat(' ', $indent);
  21899. }
  21900. private function getLeftAlignedDescriptionIndent(array $items, $index)
  21901. {
  21902. if (self::ALIGN_LEFT !== $this->align) {
  21903. return 0;
  21904. }
  21905. $item = null;
  21906. for (; $index >= 0; --$index) {
  21907. $item = $items[$index];
  21908. if (null !== $item['tag']) {
  21909. break;
  21910. }
  21911. }
  21912. if (null === $item) {
  21913. return 0;
  21914. }
  21915. return
  21916. $this->getSentenceIndent($item['tag']) +
  21917. $this->getSentenceIndent($item['hint']) +
  21918. $this->getSentenceIndent($item['var']);
  21919. }
  21920. private function getSentenceIndent($sentence)
  21921. {
  21922. if (null === $sentence) {
  21923. return 0;
  21924. }
  21925. $length = \strlen($sentence);
  21926. return 0 === $length ? 0 : $length + 1;
  21927. }
  21928. }
  21929. <?php
  21930. namespace PhpCsFixer\Fixer\Phpdoc;
  21931. use PhpCsFixer\AbstractFixer;
  21932. use PhpCsFixer\FixerDefinition\CodeSample;
  21933. use PhpCsFixer\FixerDefinition\FixerDefinition;
  21934. use PhpCsFixer\Tokenizer\Token;
  21935. use PhpCsFixer\Tokenizer\Tokens;
  21936. final class NoBlankLinesAfterPhpdocFixer extends AbstractFixer
  21937. {
  21938. public function isCandidate(Tokens $tokens)
  21939. {
  21940. return $tokens->isTokenKindFound(T_DOC_COMMENT);
  21941. }
  21942. public function getDefinition()
  21943. {
  21944. return new FixerDefinition(
  21945. 'There should not be blank lines between docblock and the documented element.',
  21946. [
  21947. new CodeSample(
  21948. '<?php
  21949. /**
  21950. * This is the bar class.
  21951. */
  21952. class Bar {}
  21953. '
  21954. ),
  21955. ]
  21956. );
  21957. }
  21958. public function getPriority()
  21959. {
  21960. return -20;
  21961. }
  21962. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  21963. {
  21964. static $forbiddenSuccessors = [
  21965. T_DOC_COMMENT,
  21966. T_COMMENT,
  21967. T_WHITESPACE,
  21968. T_RETURN,
  21969. T_THROW,
  21970. T_GOTO,
  21971. T_CONTINUE,
  21972. T_BREAK,
  21973. T_DECLARE,
  21974. T_USE,
  21975. ];
  21976. foreach ($tokens as $index => $token) {
  21977. if (!$token->isGivenKind(T_DOC_COMMENT)) {
  21978. continue;
  21979. }
  21980. $next = $tokens->getNextNonWhitespace($index);
  21981. if ($index + 2 === $next && false === $tokens[$next]->isGivenKind($forbiddenSuccessors)) {
  21982. $this->fixWhitespace($tokens, $index + 1);
  21983. }
  21984. }
  21985. }
  21986. private function fixWhitespace(Tokens $tokens, $index)
  21987. {
  21988. $content = $tokens[$index]->getContent();
  21989. if (substr_count($content, "\n") > 1) {
  21990. $tokens[$index] = new Token([T_WHITESPACE, substr($content, strrpos($content, "\n"))]);
  21991. }
  21992. }
  21993. }
  21994. <?php
  21995. namespace PhpCsFixer\Fixer\Phpdoc;
  21996. use PhpCsFixer\AbstractFixer;
  21997. use PhpCsFixer\DocBlock\DocBlock;
  21998. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  21999. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  22000. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  22001. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  22002. use PhpCsFixer\FixerDefinition\CodeSample;
  22003. use PhpCsFixer\FixerDefinition\FixerDefinition;
  22004. use PhpCsFixer\Tokenizer\CT;
  22005. use PhpCsFixer\Tokenizer\Token;
  22006. use PhpCsFixer\Tokenizer\Tokens;
  22007. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  22008. final class PhpdocLineSpanFixer extends AbstractFixer implements WhitespacesAwareFixerInterface, ConfigurationDefinitionFixerInterface
  22009. {
  22010. public function getDefinition()
  22011. {
  22012. return new FixerDefinition(
  22013. 'Changes doc blocks from single to multi line, or reversed. Works for class constants, properties and methods only.',
  22014. [
  22015. new CodeSample("<?php\n\nclass Foo{\n /** @var bool */\n public \$var;\n}\n"),
  22016. new CodeSample(
  22017. "<?php\n\nclass Foo{\n /**\n * @var bool\n */\n public \$var;\n}\n",
  22018. ['property' => 'single']
  22019. ),
  22020. ]
  22021. );
  22022. }
  22023. public function getPriority()
  22024. {
  22025. return 0;
  22026. }
  22027. public function isCandidate(Tokens $tokens)
  22028. {
  22029. return $tokens->isTokenKindFound(T_DOC_COMMENT);
  22030. }
  22031. protected function createConfigurationDefinition()
  22032. {
  22033. return new FixerConfigurationResolver([
  22034. (new FixerOptionBuilder('const', 'Whether const blocks should be single or multi line'))
  22035. ->setAllowedValues(['single', 'multi'])
  22036. ->setDefault('multi')
  22037. ->getOption(),
  22038. (new FixerOptionBuilder('property', 'Whether property doc blocks should be single or multi line'))
  22039. ->setAllowedValues(['single', 'multi'])
  22040. ->setDefault('multi')
  22041. ->getOption(),
  22042. (new FixerOptionBuilder('method', 'Whether method doc blocks should be single or multi line'))
  22043. ->setAllowedValues(['single', 'multi'])
  22044. ->setDefault('multi')
  22045. ->getOption(),
  22046. ]);
  22047. }
  22048. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  22049. {
  22050. $analyzer = new TokensAnalyzer($tokens);
  22051. $elements = $analyzer->getClassyElements();
  22052. foreach ($elements as $index => $element) {
  22053. if (!$this->hasDocBlock($tokens, $index)) {
  22054. continue;
  22055. }
  22056. $type = $element['type'];
  22057. $docIndex = $this->getDocBlockIndex($tokens, $index);
  22058. $doc = new DocBlock($tokens[$docIndex]->getContent());
  22059. if ('multi' === $this->configuration[$type]) {
  22060. $doc->makeMultiLine($originalIndent = $this->detectIndent($tokens, $docIndex), $this->whitespacesConfig->getLineEnding());
  22061. } else {
  22062. $doc->makeSingleLine();
  22063. }
  22064. $tokens->offsetSet($docIndex, new Token([T_DOC_COMMENT, $doc->getContent()]));
  22065. }
  22066. }
  22067. private function hasDocBlock(Tokens $tokens, $index)
  22068. {
  22069. $docBlockIndex = $this->getDocBlockIndex($tokens, $index);
  22070. return $tokens[$docBlockIndex]->isGivenKind(T_DOC_COMMENT);
  22071. }
  22072. private function getDocBlockIndex(Tokens $tokens, $index)
  22073. {
  22074. do {
  22075. $index = $tokens->getPrevNonWhitespace($index);
  22076. } while ($tokens[$index]->isGivenKind([
  22077. T_PUBLIC,
  22078. T_PROTECTED,
  22079. T_PRIVATE,
  22080. T_FINAL,
  22081. T_ABSTRACT,
  22082. T_COMMENT,
  22083. T_VAR,
  22084. T_STATIC,
  22085. T_STRING,
  22086. T_NS_SEPARATOR,
  22087. CT::T_NULLABLE_TYPE,
  22088. ]));
  22089. return $index;
  22090. }
  22091. private function detectIndent(Tokens $tokens, $index)
  22092. {
  22093. if (!$tokens[$index - 1]->isWhitespace()) {
  22094. return '';
  22095. }
  22096. $explodedContent = explode($this->whitespacesConfig->getLineEnding(), $tokens[$index - 1]->getContent());
  22097. return end($explodedContent);
  22098. }
  22099. }
  22100. <?php
  22101. namespace PhpCsFixer\Fixer\Phpdoc;
  22102. use PhpCsFixer\AbstractFixer;
  22103. use PhpCsFixer\FixerDefinition\CodeSample;
  22104. use PhpCsFixer\FixerDefinition\FixerDefinition;
  22105. use PhpCsFixer\Preg;
  22106. use PhpCsFixer\Tokenizer\Token;
  22107. use PhpCsFixer\Tokenizer\Tokens;
  22108. final class PhpdocSingleLineVarSpacingFixer extends AbstractFixer
  22109. {
  22110. public function getDefinition()
  22111. {
  22112. return new FixerDefinition(
  22113. 'Single line `@var` PHPDoc should have proper spacing.',
  22114. [new CodeSample("<?php /**@var MyClass \$a */\n\$a = test();\n")]
  22115. );
  22116. }
  22117. public function getPriority()
  22118. {
  22119. return -10;
  22120. }
  22121. public function isCandidate(Tokens $tokens)
  22122. {
  22123. return $tokens->isAnyTokenKindsFound([T_COMMENT, T_DOC_COMMENT]);
  22124. }
  22125. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  22126. {
  22127. foreach ($tokens as $index => $token) {
  22128. if ($token->isGivenKind(T_DOC_COMMENT)) {
  22129. $tokens[$index] = new Token([T_DOC_COMMENT, $this->fixTokenContent($token->getContent())]);
  22130. continue;
  22131. }
  22132. if (!$token->isGivenKind(T_COMMENT)) {
  22133. continue;
  22134. }
  22135. $content = $token->getContent();
  22136. $fixedContent = $this->fixTokenContent($content);
  22137. if ($content !== $fixedContent) {
  22138. $tokens[$index] = new Token([T_DOC_COMMENT, $fixedContent]);
  22139. }
  22140. }
  22141. }
  22142. private function fixTokenContent($content)
  22143. {
  22144. return Preg::replaceCallback(
  22145. '#^/\*\*\h*@var\h+(\S+)\h*(\$\S+)?\h*([^\n]*)\*/$#',
  22146. static function (array $matches) {
  22147. $content = '/** @var';
  22148. for ($i = 1, $m = \count($matches); $i < $m; ++$i) {
  22149. if ('' !== $matches[$i]) {
  22150. $content .= ' '.$matches[$i];
  22151. }
  22152. }
  22153. $content = rtrim($content);
  22154. return $content.' */';
  22155. },
  22156. $content
  22157. );
  22158. }
  22159. }
  22160. <?php
  22161. namespace PhpCsFixer\Fixer\Phpdoc;
  22162. use PhpCsFixer\AbstractPhpdocTypesFixer;
  22163. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  22164. use PhpCsFixer\FixerConfiguration\AllowedValueSubset;
  22165. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  22166. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  22167. use PhpCsFixer\FixerDefinition\CodeSample;
  22168. use PhpCsFixer\FixerDefinition\FixerDefinition;
  22169. final class PhpdocScalarFixer extends AbstractPhpdocTypesFixer implements ConfigurationDefinitionFixerInterface
  22170. {
  22171. private static $types = [
  22172. 'boolean' => 'bool',
  22173. 'callback' => 'callable',
  22174. 'double' => 'float',
  22175. 'integer' => 'int',
  22176. 'real' => 'float',
  22177. 'str' => 'string',
  22178. ];
  22179. public function getDefinition()
  22180. {
  22181. return new FixerDefinition(
  22182. 'Scalar types should always be written in the same form. `int` not `integer`, `bool` not `boolean`, `float` not `real` or `double`.',
  22183. [
  22184. new CodeSample('<?php
  22185. /**
  22186. * @param integer $a
  22187. * @param boolean $b
  22188. * @param real $c
  22189. *
  22190. * @return double
  22191. */
  22192. function sample($a, $b, $c)
  22193. {
  22194. return sample2($a, $b, $c);
  22195. }
  22196. '),
  22197. new CodeSample(
  22198. '<?php
  22199. /**
  22200. * @param integer $a
  22201. * @param boolean $b
  22202. * @param real $c
  22203. */
  22204. function sample($a, $b, $c)
  22205. {
  22206. return sample2($a, $b, $c);
  22207. }
  22208. ',
  22209. ['types' => ['boolean']]
  22210. ),
  22211. ]
  22212. );
  22213. }
  22214. public function getPriority()
  22215. {
  22216. return 15;
  22217. }
  22218. protected function createConfigurationDefinition()
  22219. {
  22220. return new FixerConfigurationResolver([
  22221. (new FixerOptionBuilder('types', 'A map of types to fix.'))
  22222. ->setAllowedValues([new AllowedValueSubset(array_keys(self::$types))])
  22223. ->setDefault(['boolean', 'double', 'integer', 'real', 'str'])
  22224. ->getOption(),
  22225. ]);
  22226. }
  22227. protected function normalize($type)
  22228. {
  22229. if (\in_array($type, $this->configuration['types'], true)) {
  22230. return self::$types[$type];
  22231. }
  22232. return $type;
  22233. }
  22234. }
  22235. <?php
  22236. namespace PhpCsFixer\Fixer\Phpdoc;
  22237. use PhpCsFixer\AbstractFixer;
  22238. use PhpCsFixer\DocBlock\DocBlock;
  22239. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  22240. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverRootless;
  22241. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  22242. use PhpCsFixer\FixerDefinition\CodeSample;
  22243. use PhpCsFixer\FixerDefinition\FixerDefinition;
  22244. use PhpCsFixer\Tokenizer\Token;
  22245. use PhpCsFixer\Tokenizer\Tokens;
  22246. /**
  22247. @gmail
  22248. */
  22249. final class GeneralPhpdocAnnotationRemoveFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface
  22250. {
  22251. public function getDefinition()
  22252. {
  22253. return new FixerDefinition(
  22254. 'Configured annotations should be omitted from PHPDoc.',
  22255. [
  22256. new CodeSample(
  22257. '<?php
  22258. /**
  22259. * @internal
  22260. * @author John Doe
  22261. */
  22262. function foo() {}
  22263. ',
  22264. ['annotations' => ['author']]
  22265. ),
  22266. new CodeSample(
  22267. '<?php
  22268. /**
  22269. * @author John Doe
  22270. * @package ACME API
  22271. * @subpackage Authorization
  22272. * @version 1.0
  22273. */
  22274. function foo() {}
  22275. ',
  22276. ['annotations' => ['package', 'subpackage']]
  22277. ),
  22278. ]
  22279. );
  22280. }
  22281. public function getPriority()
  22282. {
  22283. return 10;
  22284. }
  22285. public function isCandidate(Tokens $tokens)
  22286. {
  22287. return $tokens->isTokenKindFound(T_DOC_COMMENT);
  22288. }
  22289. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  22290. {
  22291. if (!\count($this->configuration['annotations'])) {
  22292. return;
  22293. }
  22294. foreach ($tokens as $index => $token) {
  22295. if (!$token->isGivenKind(T_DOC_COMMENT)) {
  22296. continue;
  22297. }
  22298. $doc = new DocBlock($token->getContent());
  22299. $annotations = $doc->getAnnotationsOfType($this->configuration['annotations']);
  22300. if (empty($annotations)) {
  22301. continue;
  22302. }
  22303. foreach ($annotations as $annotation) {
  22304. $annotation->remove();
  22305. }
  22306. if ('' === $doc->getContent()) {
  22307. $tokens->clearTokenAndMergeSurroundingWhitespace($index);
  22308. } else {
  22309. $tokens[$index] = new Token([T_DOC_COMMENT, $doc->getContent()]);
  22310. }
  22311. }
  22312. }
  22313. protected function createConfigurationDefinition()
  22314. {
  22315. return new FixerConfigurationResolverRootless('annotations', [
  22316. (new FixerOptionBuilder('annotations', 'List of annotations to remove, e.g. `["author"]`.'))
  22317. ->setAllowedTypes(['array'])
  22318. ->setDefault([])
  22319. ->getOption(),
  22320. ], $this->getName());
  22321. }
  22322. }
  22323. <?php
  22324. namespace PhpCsFixer\Fixer\Phpdoc;
  22325. use PhpCsFixer\AbstractProxyFixer;
  22326. use PhpCsFixer\FixerDefinition\CodeSample;
  22327. use PhpCsFixer\FixerDefinition\FixerDefinition;
  22328. /**
  22329. @gmail
  22330. */
  22331. final class PhpdocNoAccessFixer extends AbstractProxyFixer
  22332. {
  22333. public function getDefinition()
  22334. {
  22335. return new FixerDefinition(
  22336. '`@access` annotations should be omitted from PHPDoc.',
  22337. [
  22338. new CodeSample(
  22339. '<?php
  22340. class Foo
  22341. {
  22342. /**
  22343. * @internal
  22344. * @access private
  22345. */
  22346. private $bar;
  22347. }
  22348. '
  22349. ),
  22350. ]
  22351. );
  22352. }
  22353. public function getPriority()
  22354. {
  22355. return parent::getPriority();
  22356. }
  22357. protected function createProxyFixers()
  22358. {
  22359. $fixer = new GeneralPhpdocAnnotationRemoveFixer();
  22360. $fixer->configure(['annotations' => ['access']]);
  22361. return [$fixer];
  22362. }
  22363. }
  22364. <?php
  22365. namespace PhpCsFixer\Fixer\Phpdoc;
  22366. use PhpCsFixer\AbstractFixer;
  22367. use PhpCsFixer\DocBlock\Annotation;
  22368. use PhpCsFixer\DocBlock\DocBlock;
  22369. use PhpCsFixer\FixerDefinition\CodeSample;
  22370. use PhpCsFixer\FixerDefinition\FixerDefinition;
  22371. use PhpCsFixer\Tokenizer\Token;
  22372. use PhpCsFixer\Tokenizer\Tokens;
  22373. final class PhpdocNoEmptyReturnFixer extends AbstractFixer
  22374. {
  22375. public function isCandidate(Tokens $tokens)
  22376. {
  22377. return $tokens->isTokenKindFound(T_DOC_COMMENT);
  22378. }
  22379. public function getDefinition()
  22380. {
  22381. return new FixerDefinition(
  22382. '`@return void` and `@return null` annotations should be omitted from PHPDoc.',
  22383. [
  22384. new CodeSample(
  22385. '<?php
  22386. /**
  22387. * @return null
  22388. */
  22389. function foo() {}
  22390. '
  22391. ),
  22392. new CodeSample(
  22393. '<?php
  22394. /**
  22395. * @return void
  22396. */
  22397. function foo() {}
  22398. '
  22399. ),
  22400. ]
  22401. );
  22402. }
  22403. public function getPriority()
  22404. {
  22405. return 10;
  22406. }
  22407. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  22408. {
  22409. foreach ($tokens as $index => $token) {
  22410. if (!$token->isGivenKind(T_DOC_COMMENT)) {
  22411. continue;
  22412. }
  22413. $doc = new DocBlock($token->getContent());
  22414. $annotations = $doc->getAnnotationsOfType('return');
  22415. if (empty($annotations)) {
  22416. continue;
  22417. }
  22418. foreach ($annotations as $annotation) {
  22419. $this->fixAnnotation($doc, $annotation);
  22420. }
  22421. $newContent = $doc->getContent();
  22422. if ($newContent === $token->getContent()) {
  22423. continue;
  22424. }
  22425. if ('' === $newContent) {
  22426. $tokens->clearTokenAndMergeSurroundingWhitespace($index);
  22427. continue;
  22428. }
  22429. $tokens[$index] = new Token([T_DOC_COMMENT, $doc->getContent()]);
  22430. }
  22431. }
  22432. private function fixAnnotation(DocBlock $doc, Annotation $annotation)
  22433. {
  22434. $types = $annotation->getNormalizedTypes();
  22435. if (1 === \count($types) && ('null' === $types[0] || 'void' === $types[0])) {
  22436. $annotation->remove();
  22437. }
  22438. }
  22439. }
  22440. <?php
  22441. namespace PhpCsFixer\Fixer\Phpdoc;
  22442. use PhpCsFixer\AbstractFixer;
  22443. use PhpCsFixer\FixerDefinition\CodeSample;
  22444. use PhpCsFixer\FixerDefinition\FixerDefinition;
  22445. use PhpCsFixer\Tokenizer\Analyzer\CommentsAnalyzer;
  22446. use PhpCsFixer\Tokenizer\Token;
  22447. use PhpCsFixer\Tokenizer\Tokens;
  22448. /**
  22449. @gmail
  22450. */
  22451. final class PhpdocToCommentFixer extends AbstractFixer
  22452. {
  22453. public function isCandidate(Tokens $tokens)
  22454. {
  22455. return $tokens->isTokenKindFound(T_DOC_COMMENT);
  22456. }
  22457. public function getPriority()
  22458. {
  22459. return 25;
  22460. }
  22461. public function getDefinition()
  22462. {
  22463. return new FixerDefinition(
  22464. 'Docblocks should only be used on structural elements.',
  22465. [
  22466. new CodeSample(
  22467. '<?php
  22468. $first = true;// needed because by default first docblock is never fixed.
  22469. /** This should not be a docblock */
  22470. foreach($connections as $key => $sqlite) {
  22471. $sqlite->open($path);
  22472. }
  22473. '
  22474. ),
  22475. ]
  22476. );
  22477. }
  22478. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  22479. {
  22480. $commentsAnalyzer = new CommentsAnalyzer();
  22481. foreach ($tokens as $index => $token) {
  22482. if (!$token->isGivenKind(T_DOC_COMMENT)) {
  22483. continue;
  22484. }
  22485. if ($commentsAnalyzer->isHeaderComment($tokens, $index)) {
  22486. continue;
  22487. }
  22488. if ($commentsAnalyzer->isBeforeStructuralElement($tokens, $index)) {
  22489. continue;
  22490. }
  22491. $tokens[$index] = new Token([T_COMMENT, '/*'.ltrim($token->getContent(), '/*')]);
  22492. }
  22493. }
  22494. }
  22495. <?php
  22496. namespace PhpCsFixer\Fixer\Phpdoc;
  22497. use PhpCsFixer\AbstractFixer;
  22498. use PhpCsFixer\FixerDefinition\CodeSample;
  22499. use PhpCsFixer\FixerDefinition\FixerDefinition;
  22500. use PhpCsFixer\Preg;
  22501. use PhpCsFixer\Tokenizer\CT;
  22502. use PhpCsFixer\Tokenizer\Token;
  22503. use PhpCsFixer\Tokenizer\Tokens;
  22504. final class PhpdocNoUselessInheritdocFixer extends AbstractFixer
  22505. {
  22506. public function getDefinition()
  22507. {
  22508. return new FixerDefinition(
  22509. 'Classy that does not inherit must not have `@inheritdoc` tags.',
  22510. [
  22511. new CodeSample("<?php\n/** {@inheritdoc} */\nclass Sample\n{\n}\n"),
  22512. new CodeSample("<?php\nclass Sample\n{\n /**\n * @inheritdoc\n */\n public function Test()\n {\n }\n}\n"),
  22513. ]
  22514. );
  22515. }
  22516. public function getPriority()
  22517. {
  22518. return 6;
  22519. }
  22520. public function isCandidate(Tokens $tokens)
  22521. {
  22522. return $tokens->isTokenKindFound(T_DOC_COMMENT) && $tokens->isAnyTokenKindsFound([T_CLASS, T_INTERFACE]);
  22523. }
  22524. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  22525. {
  22526. for ($index = 1, $count = \count($tokens) - 4; $index < $count; ++$index) {
  22527. if ($tokens[$index]->isGivenKind([T_CLASS, T_INTERFACE])) {
  22528. $index = $this->fixClassy($tokens, $index);
  22529. }
  22530. }
  22531. }
  22532. private function fixClassy(Tokens $tokens, $index)
  22533. {
  22534. $classOpenIndex = $tokens->getNextTokenOfKind($index, ['{']);
  22535. $classEndIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $classOpenIndex);
  22536. $extendingOrImplementing = $this->isExtendingOrImplementing($tokens, $index, $classOpenIndex);
  22537. if (!$extendingOrImplementing) {
  22538. $this->fixClassyOutside($tokens, $index);
  22539. }
  22540. if (!$extendingOrImplementing && $this->isUsingTrait($tokens, $index, $classOpenIndex, $classEndIndex)) {
  22541. $extendingOrImplementing = true;
  22542. }
  22543. $this->fixClassyInside($tokens, $classOpenIndex, $classEndIndex, !$extendingOrImplementing);
  22544. return $classEndIndex;
  22545. }
  22546. private function fixClassyInside(Tokens $tokens, $classOpenIndex, $classEndIndex, $fixThisLevel)
  22547. {
  22548. for ($i = $classOpenIndex; $i < $classEndIndex; ++$i) {
  22549. if ($tokens[$i]->isGivenKind(T_CLASS)) {
  22550. $i = $this->fixClassy($tokens, $i);
  22551. } elseif ($fixThisLevel && $tokens[$i]->isGivenKind(T_DOC_COMMENT)) {
  22552. $this->fixToken($tokens, $i);
  22553. }
  22554. }
  22555. }
  22556. private function fixClassyOutside(Tokens $tokens, $classIndex)
  22557. {
  22558. $previousIndex = $tokens->getPrevNonWhitespace($classIndex);
  22559. if ($tokens[$previousIndex]->isGivenKind(T_DOC_COMMENT)) {
  22560. $this->fixToken($tokens, $previousIndex);
  22561. }
  22562. }
  22563. private function fixToken(Tokens $tokens, $tokenIndex)
  22564. {
  22565. $count = 0;
  22566. $content = Preg::replaceCallback(
  22567. '#(\h*(?:@{*|{*\h*@)\h*inheritdoc\h*)([^}]*)((?:}*)\h*)#i',
  22568. static function ($matches) {
  22569. return ' '.$matches[2];
  22570. },
  22571. $tokens[$tokenIndex]->getContent(),
  22572. -1,
  22573. $count
  22574. );
  22575. if ($count) {
  22576. $tokens[$tokenIndex] = new Token([T_DOC_COMMENT, $content]);
  22577. }
  22578. }
  22579. private function isExtendingOrImplementing(Tokens $tokens, $classIndex, $classOpenIndex)
  22580. {
  22581. for ($index = $classIndex; $index < $classOpenIndex; ++$index) {
  22582. if ($tokens[$index]->isGivenKind([T_EXTENDS, T_IMPLEMENTS])) {
  22583. return true;
  22584. }
  22585. }
  22586. return false;
  22587. }
  22588. private function isUsingTrait(Tokens $tokens, $classIndex, $classOpenIndex, $classCloseIndex)
  22589. {
  22590. if ($tokens[$classIndex]->isGivenKind(T_INTERFACE)) {
  22591. return false;
  22592. }
  22593. $useIndex = $tokens->getNextTokenOfKind($classOpenIndex, [[CT::T_USE_TRAIT]]);
  22594. return null !== $useIndex && $useIndex < $classCloseIndex;
  22595. }
  22596. }
  22597. <?php
  22598. namespace PhpCsFixer\Fixer\Phpdoc;
  22599. use PhpCsFixer\AbstractFixer;
  22600. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  22601. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  22602. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  22603. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  22604. use PhpCsFixer\FixerDefinition\CodeSample;
  22605. use PhpCsFixer\FixerDefinition\FixerDefinition;
  22606. use PhpCsFixer\Preg;
  22607. use PhpCsFixer\Tokenizer\Token;
  22608. use PhpCsFixer\Tokenizer\Tokens;
  22609. /**
  22610. @gmail
  22611. */
  22612. final class AlignMultilineCommentFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface, WhitespacesAwareFixerInterface
  22613. {
  22614. private $tokenKinds;
  22615. public function configure(array $configuration = null)
  22616. {
  22617. parent::configure($configuration);
  22618. $this->tokenKinds = [T_DOC_COMMENT];
  22619. if ('phpdocs_only' !== $this->configuration['comment_type']) {
  22620. $this->tokenKinds[] = T_COMMENT;
  22621. }
  22622. }
  22623. public function getDefinition()
  22624. {
  22625. return new FixerDefinition(
  22626. 'Each line of multi-line DocComments must have an asterisk [PSR-5] and must be aligned with the first one.',
  22627. [
  22628. new CodeSample(
  22629. '<?php
  22630. /**
  22631. * This is a DOC Comment
  22632. with a line not prefixed with asterisk
  22633. */
  22634. '
  22635. ),
  22636. new CodeSample(
  22637. '<?php
  22638. /*
  22639. * This is a doc-like multiline comment
  22640. */
  22641. ',
  22642. ['comment_type' => 'phpdocs_like']
  22643. ),
  22644. new CodeSample(
  22645. '<?php
  22646. /*
  22647. * This is a doc-like multiline comment
  22648. with a line not prefixed with asterisk
  22649. */
  22650. ',
  22651. ['comment_type' => 'all_multiline']
  22652. ),
  22653. ]
  22654. );
  22655. }
  22656. public function getPriority()
  22657. {
  22658. return -40;
  22659. }
  22660. public function isCandidate(Tokens $tokens)
  22661. {
  22662. return $tokens->isAnyTokenKindsFound($this->tokenKinds);
  22663. }
  22664. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  22665. {
  22666. $lineEnding = $this->whitespacesConfig->getLineEnding();
  22667. foreach ($tokens as $index => $token) {
  22668. if (!$token->isGivenKind($this->tokenKinds)) {
  22669. continue;
  22670. }
  22671. $whitespace = '';
  22672. $previousIndex = $index - 1;
  22673. if ($tokens[$previousIndex]->isWhitespace()) {
  22674. $whitespace = $tokens[$previousIndex]->getContent();
  22675. --$previousIndex;
  22676. }
  22677. if ($tokens[$previousIndex]->isGivenKind(T_OPEN_TAG)) {
  22678. $whitespace = Preg::replace('/\S/', '', $tokens[$previousIndex]->getContent()).$whitespace;
  22679. }
  22680. if (1 !== Preg::match('/\R(\h*)$/', $whitespace, $matches)) {
  22681. continue;
  22682. }
  22683. if ($token->isGivenKind(T_COMMENT) && 'all_multiline' !== $this->configuration['comment_type'] && 1 === Preg::match('/\R(?:\R|\s*[^\s\*])/', $token->getContent())) {
  22684. continue;
  22685. }
  22686. $indentation = $matches[1];
  22687. $lines = Preg::split('/\R/u', $token->getContent());
  22688. foreach ($lines as $lineNumber => $line) {
  22689. if (0 === $lineNumber) {
  22690. continue;
  22691. }
  22692. $line = ltrim($line);
  22693. if ($token->isGivenKind(T_COMMENT) && (!isset($line[0]) || '*' !== $line[0])) {
  22694. continue;
  22695. }
  22696. if (!isset($line[0])) {
  22697. $line = '*';
  22698. } elseif ('*' !== $line[0]) {
  22699. $line = '* '.$line;
  22700. }
  22701. $lines[$lineNumber] = $indentation.' '.$line;
  22702. }
  22703. $tokens[$index] = new Token([$token->getId(), implode($lineEnding, $lines)]);
  22704. }
  22705. }
  22706. protected function createConfigurationDefinition()
  22707. {
  22708. return new FixerConfigurationResolver([
  22709. (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`).'))
  22710. ->setAllowedValues(['phpdocs_only', 'phpdocs_like', 'all_multiline'])
  22711. ->setDefault('phpdocs_only')
  22712. ->getOption(),
  22713. ]);
  22714. }
  22715. }
  22716. <?php
  22717. namespace PhpCsFixer\Fixer\Phpdoc;
  22718. use PhpCsFixer\AbstractFixer;
  22719. use PhpCsFixer\DocBlock\DocBlock;
  22720. use PhpCsFixer\FixerDefinition\CodeSample;
  22721. use PhpCsFixer\FixerDefinition\FixerDefinition;
  22722. use PhpCsFixer\Preg;
  22723. use PhpCsFixer\Tokenizer\Token;
  22724. use PhpCsFixer\Tokenizer\Tokens;
  22725. final class PhpdocAnnotationWithoutDotFixer extends AbstractFixer
  22726. {
  22727. private $tags = ['throws', 'return', 'param', 'internal', 'deprecated', 'var', 'type'];
  22728. public function getDefinition()
  22729. {
  22730. return new FixerDefinition(
  22731. 'PHPDoc annotation descriptions should not be a sentence.',
  22732. [new CodeSample('<?php
  22733. /**
  22734. * @param string $bar Some string.
  22735. */
  22736. function foo ($bar) {}
  22737. ')]
  22738. );
  22739. }
  22740. public function getPriority()
  22741. {
  22742. return 17;
  22743. }
  22744. public function isCandidate(Tokens $tokens)
  22745. {
  22746. return $tokens->isTokenKindFound(T_DOC_COMMENT);
  22747. }
  22748. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  22749. {
  22750. foreach ($tokens as $index => $token) {
  22751. if (!$token->isGivenKind(T_DOC_COMMENT)) {
  22752. continue;
  22753. }
  22754. $doc = new DocBlock($token->getContent());
  22755. $annotations = $doc->getAnnotations();
  22756. if (empty($annotations)) {
  22757. continue;
  22758. }
  22759. foreach ($annotations as $annotation) {
  22760. if (
  22761. !$annotation->getTag()->valid() || !\in_array($annotation->getTag()->getName(), $this->tags, true)
  22762. ) {
  22763. continue;
  22764. }
  22765. $lineAfterAnnotation = $doc->getLine($annotation->getEnd() + 1);
  22766. if (null !== $lineAfterAnnotation) {
  22767. $lineAfterAnnotationTrimmed = ltrim($lineAfterAnnotation->getContent());
  22768. if ('' === $lineAfterAnnotationTrimmed || '*' !== $lineAfterAnnotationTrimmed[0]) {
  22769. continue;
  22770. }
  22771. }
  22772. $content = $annotation->getContent();
  22773. if (
  22774. 1 !== Preg::match('/[.。]\h*$/u', $content)
  22775. || 0 !== Preg::match('/[.。](?!\h*$)/u', $content, $matches)
  22776. ) {
  22777. continue;
  22778. }
  22779. $endLine = $doc->getLine($annotation->getEnd());
  22780. $endLine->setContent(Preg::replace('/(?<![.。])[.。]\h*(\H+)$/u', '\1', $endLine->getContent()));
  22781. $startLine = $doc->getLine($annotation->getStart());
  22782. $optionalTypeRegEx = $annotation->supportTypes()
  22783. ? sprintf('(?:%s\s+(?:\$\w+\s+)?)?', preg_quote(implode('|', $annotation->getTypes()), '/'))
  22784. : '';
  22785. $content = Preg::replaceCallback(
  22786. '/^(\s*\*\s*@\w+\s+'.$optionalTypeRegEx.')(\p{Lu}?(?=\p{Ll}|\p{Zs}))(.*)$/',
  22787. static function (array $matches) {
  22788. if (\function_exists('mb_strtolower')) {
  22789. return $matches[1].mb_strtolower($matches[2]).$matches[3];
  22790. }
  22791. return $matches[1].strtolower($matches[2]).$matches[3];
  22792. },
  22793. $startLine->getContent(),
  22794. 1
  22795. );
  22796. $startLine->setContent($content);
  22797. }
  22798. $tokens[$index] = new Token([T_DOC_COMMENT, $doc->getContent()]);
  22799. }
  22800. }
  22801. }
  22802. <?php
  22803. namespace PhpCsFixer\Fixer\Phpdoc;
  22804. use PhpCsFixer\AbstractFixer;
  22805. use PhpCsFixer\DocBlock\DocBlock;
  22806. use PhpCsFixer\DocBlock\Line;
  22807. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  22808. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  22809. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  22810. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  22811. use PhpCsFixer\FixerDefinition\CodeSample;
  22812. use PhpCsFixer\FixerDefinition\FixerDefinition;
  22813. use PhpCsFixer\Preg;
  22814. use PhpCsFixer\Tokenizer\Analyzer\ArgumentsAnalyzer;
  22815. use PhpCsFixer\Tokenizer\Token;
  22816. use PhpCsFixer\Tokenizer\Tokens;
  22817. final class PhpdocAddMissingParamAnnotationFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface, WhitespacesAwareFixerInterface
  22818. {
  22819. public function getDefinition()
  22820. {
  22821. return new FixerDefinition(
  22822. 'PHPDoc should contain `@param` for all params.',
  22823. [
  22824. new CodeSample(
  22825. '<?php
  22826. /**
  22827. * @param int $bar
  22828. *
  22829. * @return void
  22830. */
  22831. function f9(string $foo, $bar, $baz) {}
  22832. '
  22833. ),
  22834. new CodeSample(
  22835. '<?php
  22836. /**
  22837. * @param int $bar
  22838. *
  22839. * @return void
  22840. */
  22841. function f9(string $foo, $bar, $baz) {}
  22842. ',
  22843. ['only_untyped' => true]
  22844. ),
  22845. new CodeSample(
  22846. '<?php
  22847. /**
  22848. * @param int $bar
  22849. *
  22850. * @return void
  22851. */
  22852. function f9(string $foo, $bar, $baz) {}
  22853. ',
  22854. ['only_untyped' => false]
  22855. ),
  22856. ]
  22857. );
  22858. }
  22859. public function getPriority()
  22860. {
  22861. return 10;
  22862. }
  22863. public function isCandidate(Tokens $tokens)
  22864. {
  22865. return $tokens->isTokenKindFound(T_DOC_COMMENT);
  22866. }
  22867. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  22868. {
  22869. $argumentsAnalyzer = new ArgumentsAnalyzer();
  22870. for ($index = 0, $limit = $tokens->count(); $index < $limit; ++$index) {
  22871. $mainIndex = $index;
  22872. $token = $tokens[$index];
  22873. if (!$token->isGivenKind(T_DOC_COMMENT)) {
  22874. continue;
  22875. }
  22876. $tokenContent = $token->getContent();
  22877. if (false !== stripos($tokenContent, 'inheritdoc')) {
  22878. continue;
  22879. }
  22880. if (false === strpos($tokenContent, "\n")) {
  22881. continue;
  22882. }
  22883. $index = $tokens->getNextMeaningfulToken($index);
  22884. if (null === $index) {
  22885. return;
  22886. }
  22887. while ($tokens[$index]->isGivenKind([
  22888. T_ABSTRACT,
  22889. T_FINAL,
  22890. T_PRIVATE,
  22891. T_PROTECTED,
  22892. T_PUBLIC,
  22893. T_STATIC,
  22894. T_VAR,
  22895. ])) {
  22896. $index = $tokens->getNextMeaningfulToken($index);
  22897. }
  22898. if (!$tokens[$index]->isGivenKind(T_FUNCTION)) {
  22899. continue;
  22900. }
  22901. $openIndex = $tokens->getNextTokenOfKind($index, ['(']);
  22902. $index = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $openIndex);
  22903. $arguments = [];
  22904. foreach ($argumentsAnalyzer->getArguments($tokens, $openIndex, $index) as $start => $end) {
  22905. $argumentInfo = $this->prepareArgumentInformation($tokens, $start, $end);
  22906. if (!$this->configuration['only_untyped'] || '' === $argumentInfo['type']) {
  22907. $arguments[$argumentInfo['name']] = $argumentInfo;
  22908. }
  22909. }
  22910. if (!\count($arguments)) {
  22911. continue;
  22912. }
  22913. $doc = new DocBlock($tokenContent);
  22914. $lastParamLine = null;
  22915. foreach ($doc->getAnnotationsOfType('param') as $annotation) {
  22916. $pregMatched = Preg::match('/^[^$]+(\$\w+).*$/s', $annotation->getContent(), $matches);
  22917. if (1 === $pregMatched) {
  22918. unset($arguments[$matches[1]]);
  22919. }
  22920. $lastParamLine = max($lastParamLine, $annotation->getEnd());
  22921. }
  22922. if (!\count($arguments)) {
  22923. continue;
  22924. }
  22925. $lines = $doc->getLines();
  22926. $linesCount = \count($lines);
  22927. Preg::match('/^(\s*).*$/', $lines[$linesCount - 1]->getContent(), $matches);
  22928. $indent = $matches[1];
  22929. $newLines = [];
  22930. foreach ($arguments as $argument) {
  22931. $type = $argument['type'] ?: 'mixed';
  22932. if ('?' !== $type[0] && 'null' === strtolower($argument['default'])) {
  22933. $type = 'null|'.$type;
  22934. }
  22935. $newLines[] = new Line(sprintf(
  22936. '%s* @param %s %s%s',
  22937. $indent,
  22938. $type,
  22939. $argument['name'],
  22940. $this->whitespacesConfig->getLineEnding()
  22941. ));
  22942. }
  22943. array_splice(
  22944. $lines,
  22945. $lastParamLine ? $lastParamLine + 1 : $linesCount - 1,
  22946. 0,
  22947. $newLines
  22948. );
  22949. $tokens[$mainIndex] = new Token([T_DOC_COMMENT, implode('', $lines)]);
  22950. }
  22951. }
  22952. protected function createConfigurationDefinition()
  22953. {
  22954. return new FixerConfigurationResolver([
  22955. (new FixerOptionBuilder('only_untyped', 'Whether to add missing `@param` annotations for untyped parameters only.'))
  22956. ->setDefault(true)
  22957. ->setAllowedTypes(['bool'])
  22958. ->getOption(),
  22959. ]);
  22960. }
  22961. private function prepareArgumentInformation(Tokens $tokens, $start, $end)
  22962. {
  22963. $info = [
  22964. 'default' => '',
  22965. 'name' => '',
  22966. 'type' => '',
  22967. ];
  22968. $sawName = false;
  22969. for ($index = $start; $index <= $end; ++$index) {
  22970. $token = $tokens[$index];
  22971. if ($token->isComment() || $token->isWhitespace()) {
  22972. continue;
  22973. }
  22974. if ($token->isGivenKind(T_VARIABLE)) {
  22975. $sawName = true;
  22976. $info['name'] = $token->getContent();
  22977. continue;
  22978. }
  22979. if ($token->equals('=')) {
  22980. continue;
  22981. }
  22982. if ($sawName) {
  22983. $info['default'] .= $token->getContent();
  22984. } elseif ('&' !== $token->getContent()) {
  22985. if ($token->isGivenKind(T_ELLIPSIS)) {
  22986. if ('' === $info['type']) {
  22987. $info['type'] = 'array';
  22988. } else {
  22989. $info['type'] .= '[]';
  22990. }
  22991. } else {
  22992. $info['type'] .= $token->getContent();
  22993. }
  22994. }
  22995. }
  22996. return $info;
  22997. }
  22998. }
  22999. <?php
  23000. namespace PhpCsFixer\Fixer\Phpdoc;
  23001. use PhpCsFixer\AbstractFixer;
  23002. use PhpCsFixer\DocBlock\DocBlock;
  23003. use PhpCsFixer\DocBlock\Line;
  23004. use PhpCsFixer\FixerDefinition\CodeSample;
  23005. use PhpCsFixer\FixerDefinition\FixerDefinition;
  23006. use PhpCsFixer\Preg;
  23007. use PhpCsFixer\Tokenizer\Token;
  23008. use PhpCsFixer\Tokenizer\Tokens;
  23009. /**
  23010. @gmail
  23011. */
  23012. final class PhpdocVarWithoutNameFixer extends AbstractFixer
  23013. {
  23014. public function getDefinition()
  23015. {
  23016. return new FixerDefinition(
  23017. '`@var` and `@type` annotations of classy properties should not contain the name.',
  23018. [new CodeSample('<?php
  23019. final class Foo
  23020. {
  23021. /**
  23022. * @var int $bar
  23023. */
  23024. public $bar;
  23025. /**
  23026. * @type $baz float
  23027. */
  23028. public $baz;
  23029. }
  23030. ')]
  23031. );
  23032. }
  23033. public function getPriority()
  23034. {
  23035. return 0;
  23036. }
  23037. public function isCandidate(Tokens $tokens)
  23038. {
  23039. return $tokens->isTokenKindFound(T_DOC_COMMENT) && $tokens->isAnyTokenKindsFound(Token::getClassyTokenKinds());
  23040. }
  23041. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  23042. {
  23043. foreach ($tokens as $index => $token) {
  23044. if (!$token->isGivenKind(T_DOC_COMMENT)) {
  23045. continue;
  23046. }
  23047. $nextIndex = $tokens->getNextMeaningfulToken($index);
  23048. if (null === $nextIndex) {
  23049. continue;
  23050. }
  23051. if ($tokens[$nextIndex]->isGivenKind(T_STATIC)) {
  23052. $nextIndex = $tokens->getNextMeaningfulToken($nextIndex);
  23053. }
  23054. if (!$tokens[$nextIndex]->isGivenKind([T_PRIVATE, T_PROTECTED, T_PUBLIC, T_VAR])) {
  23055. continue;
  23056. }
  23057. $doc = new DocBlock($token->getContent());
  23058. $firstLevelLines = $this->getFirstLevelLines($doc);
  23059. $annotations = $doc->getAnnotationsOfType(['type', 'var']);
  23060. foreach ($annotations as $annotation) {
  23061. if (isset($firstLevelLines[$annotation->getStart()])) {
  23062. $this->fixLine($firstLevelLines[$annotation->getStart()]);
  23063. }
  23064. }
  23065. $tokens[$index] = new Token([T_DOC_COMMENT, $doc->getContent()]);
  23066. }
  23067. }
  23068. private function fixLine(Line $line)
  23069. {
  23070. $content = $line->getContent();
  23071. Preg::matchAll('/ \$[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/', $content, $matches);
  23072. if (isset($matches[0][0])) {
  23073. $line->setContent(str_replace($matches[0][0], '', $content));
  23074. }
  23075. }
  23076. private function getFirstLevelLines(DocBlock $docBlock)
  23077. {
  23078. $nested = 0;
  23079. $lines = $docBlock->getLines();
  23080. foreach ($lines as $index => $line) {
  23081. $content = $line->getContent();
  23082. if (Preg::match('/\s*\*\s*}$/', $content)) {
  23083. --$nested;
  23084. }
  23085. if ($nested > 0) {
  23086. unset($lines[$index]);
  23087. }
  23088. if (Preg::match('/\s\{$/', $content)) {
  23089. ++$nested;
  23090. }
  23091. }
  23092. return $lines;
  23093. }
  23094. }
  23095. <?php
  23096. namespace PhpCsFixer\Fixer\Phpdoc;
  23097. use PhpCsFixer\AbstractFixer;
  23098. use PhpCsFixer\DocBlock\DocBlock;
  23099. use PhpCsFixer\DocBlock\Line;
  23100. use PhpCsFixer\DocBlock\ShortDescription;
  23101. use PhpCsFixer\FixerDefinition\CodeSample;
  23102. use PhpCsFixer\FixerDefinition\FixerDefinition;
  23103. use PhpCsFixer\Tokenizer\Token;
  23104. use PhpCsFixer\Tokenizer\Tokens;
  23105. /**
  23106. @gmail
  23107. */
  23108. final class PhpdocTrimConsecutiveBlankLineSeparationFixer extends AbstractFixer
  23109. {
  23110. public function getDefinition()
  23111. {
  23112. return new FixerDefinition(
  23113. 'Removes extra blank lines after summary and after description in PHPDoc.',
  23114. [
  23115. new CodeSample(
  23116. '<?php
  23117. /**
  23118. * Summary.
  23119. *
  23120. *
  23121. * Description that contain 4 lines,
  23122. *
  23123. *
  23124. * while 2 of them are blank!
  23125. *
  23126. *
  23127. * @param string $foo
  23128. *
  23129. *
  23130. * @dataProvider provideFixCases
  23131. */
  23132. function fnc($foo) {}
  23133. '
  23134. ),
  23135. ]
  23136. );
  23137. }
  23138. public function getPriority()
  23139. {
  23140. return 0;
  23141. }
  23142. public function isCandidate(Tokens $tokens)
  23143. {
  23144. return $tokens->isTokenKindFound(T_DOC_COMMENT);
  23145. }
  23146. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  23147. {
  23148. foreach ($tokens as $index => $token) {
  23149. if (!$token->isGivenKind(T_DOC_COMMENT)) {
  23150. continue;
  23151. }
  23152. $doc = new DocBlock($token->getContent());
  23153. $summaryEnd = (new ShortDescription($doc))->getEnd();
  23154. if (null !== $summaryEnd) {
  23155. $this->fixSummary($doc, $summaryEnd);
  23156. $this->fixDescription($doc, $summaryEnd);
  23157. }
  23158. $this->fixAllTheRest($doc);
  23159. $tokens[$index] = new Token([T_DOC_COMMENT, $doc->getContent()]);
  23160. }
  23161. }
  23162. private function fixSummary(DocBlock $doc, $summaryEnd)
  23163. {
  23164. $nonBlankLineAfterSummary = $this->findNonBlankLine($doc, $summaryEnd);
  23165. $this->removeExtraBlankLinesBetween($doc, $summaryEnd, $nonBlankLineAfterSummary);
  23166. }
  23167. private function fixDescription(DocBlock $doc, $summaryEnd)
  23168. {
  23169. $annotationStart = $this->findFirstAnnotationOrEnd($doc);
  23170. $descriptionEnd = $this->reverseFindLastUsefulContent($doc, $annotationStart);
  23171. if (null === $descriptionEnd || $summaryEnd === $descriptionEnd) {
  23172. return;
  23173. }
  23174. if ($annotationStart === \count($doc->getLines()) - 1) {
  23175. return;
  23176. }
  23177. $this->removeExtraBlankLinesBetween($doc, $descriptionEnd, $annotationStart);
  23178. }
  23179. private function fixAllTheRest(DocBlock $doc)
  23180. {
  23181. $annotationStart = $this->findFirstAnnotationOrEnd($doc);
  23182. $lastLine = $this->reverseFindLastUsefulContent($doc, \count($doc->getLines()) - 1);
  23183. if (null !== $lastLine && $annotationStart !== $lastLine) {
  23184. $this->removeExtraBlankLinesBetween($doc, $annotationStart, $lastLine);
  23185. }
  23186. }
  23187. private function removeExtraBlankLinesBetween(DocBlock $doc, $from, $to)
  23188. {
  23189. for ($index = $from + 1; $index < $to; ++$index) {
  23190. $line = $doc->getLine($index);
  23191. $next = $doc->getLine($index + 1);
  23192. $this->removeExtraBlankLine($line, $next);
  23193. }
  23194. }
  23195. private function removeExtraBlankLine(Line $current, Line $next)
  23196. {
  23197. if (!$current->isTheEnd() && !$current->containsUsefulContent()
  23198. && !$next->isTheEnd() && !$next->containsUsefulContent()) {
  23199. $current->remove();
  23200. }
  23201. }
  23202. private function findNonBlankLine(DocBlock $doc, $after)
  23203. {
  23204. foreach ($doc->getLines() as $index => $line) {
  23205. if ($index <= $after) {
  23206. continue;
  23207. }
  23208. if ($line->containsATag() || $line->containsUsefulContent() || $line->isTheEnd()) {
  23209. return $index;
  23210. }
  23211. }
  23212. return null;
  23213. }
  23214. private function findFirstAnnotationOrEnd(DocBlock $doc)
  23215. {
  23216. $index = null;
  23217. foreach ($doc->getLines() as $index => $line) {
  23218. if ($line->containsATag()) {
  23219. return $index;
  23220. }
  23221. }
  23222. return $index;
  23223. }
  23224. private function reverseFindLastUsefulContent(DocBlock $doc, $from)
  23225. {
  23226. for ($index = $from - 1; $index >= 0; --$index) {
  23227. if ($doc->getLine($index)->containsUsefulContent()) {
  23228. return $index;
  23229. }
  23230. }
  23231. return null;
  23232. }
  23233. }
  23234. <?php
  23235. namespace PhpCsFixer\Fixer\Operator;
  23236. use PhpCsFixer\AbstractFixer;
  23237. use PhpCsFixer\FixerDefinition\CodeSample;
  23238. use PhpCsFixer\FixerDefinition\FixerDefinition;
  23239. use PhpCsFixer\Tokenizer\Token;
  23240. use PhpCsFixer\Tokenizer\Tokens;
  23241. final class LogicalOperatorsFixer extends AbstractFixer
  23242. {
  23243. public function getDefinition()
  23244. {
  23245. return new FixerDefinition(
  23246. 'Use `&&` and `||` logical operators instead of `and` and `or`.',
  23247. [
  23248. new CodeSample(
  23249. '<?php
  23250. if ($a == "foo" and ($b == "bar" or $c == "baz")) {
  23251. }
  23252. '
  23253. ),
  23254. ],
  23255. null,
  23256. 'Risky, because you must double-check if using and/or with lower precedence was intentional.'
  23257. );
  23258. }
  23259. public function isCandidate(Tokens $tokens)
  23260. {
  23261. return $tokens->isAnyTokenKindsFound([T_LOGICAL_AND, T_LOGICAL_OR]);
  23262. }
  23263. public function isRisky()
  23264. {
  23265. return true;
  23266. }
  23267. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  23268. {
  23269. foreach ($tokens as $index => $token) {
  23270. if ($token->isGivenKind(T_LOGICAL_AND)) {
  23271. $tokens[$index] = new Token([T_BOOLEAN_AND, '&&']);
  23272. } elseif ($token->isGivenKind(T_LOGICAL_OR)) {
  23273. $tokens[$index] = new Token([T_BOOLEAN_OR, '||']);
  23274. }
  23275. }
  23276. }
  23277. }
  23278. <?php
  23279. namespace PhpCsFixer\Fixer\Operator;
  23280. use PhpCsFixer\AbstractFixer;
  23281. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  23282. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  23283. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  23284. use PhpCsFixer\FixerDefinition\CodeSample;
  23285. use PhpCsFixer\FixerDefinition\FixerDefinition;
  23286. use PhpCsFixer\Tokenizer\Token;
  23287. use PhpCsFixer\Tokenizer\Tokens;
  23288. final class ConcatSpaceFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface
  23289. {
  23290. private $fixCallback;
  23291. public function configure(array $configuration = null)
  23292. {
  23293. parent::configure($configuration);
  23294. if ('one' === $this->configuration['spacing']) {
  23295. $this->fixCallback = 'fixConcatenationToSingleSpace';
  23296. } else {
  23297. $this->fixCallback = 'fixConcatenationToNoSpace';
  23298. }
  23299. }
  23300. public function getDefinition()
  23301. {
  23302. return new FixerDefinition(
  23303. 'Concatenation should be spaced according configuration.',
  23304. [
  23305. new CodeSample(
  23306. "<?php\n\$foo = 'bar' . 3 . 'baz'.'qux';\n"
  23307. ),
  23308. new CodeSample(
  23309. "<?php\n\$foo = 'bar' . 3 . 'baz'.'qux';\n",
  23310. ['spacing' => 'none']
  23311. ),
  23312. new CodeSample(
  23313. "<?php\n\$foo = 'bar' . 3 . 'baz'.'qux';\n",
  23314. ['spacing' => 'one']
  23315. ),
  23316. ]
  23317. );
  23318. }
  23319. public function getPriority()
  23320. {
  23321. return 0;
  23322. }
  23323. public function isCandidate(Tokens $tokens)
  23324. {
  23325. return $tokens->isTokenKindFound('.');
  23326. }
  23327. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  23328. {
  23329. $callBack = $this->fixCallback;
  23330. for ($index = $tokens->count() - 1; $index >= 0; --$index) {
  23331. if ($tokens[$index]->equals('.')) {
  23332. $this->{$callBack}($tokens, $index);
  23333. }
  23334. }
  23335. }
  23336. protected function createConfigurationDefinition()
  23337. {
  23338. return new FixerConfigurationResolver([
  23339. (new FixerOptionBuilder('spacing', 'Spacing to apply around concatenation operator.'))
  23340. ->setAllowedValues(['one', 'none'])
  23341. ->setDefault('none')
  23342. ->getOption(),
  23343. ]);
  23344. }
  23345. private function fixConcatenationToNoSpace(Tokens $tokens, $index)
  23346. {
  23347. $prevNonWhitespaceToken = $tokens[$tokens->getPrevNonWhitespace($index)];
  23348. if (!$prevNonWhitespaceToken->isGivenKind([T_LNUMBER, T_COMMENT, T_DOC_COMMENT]) || '/*' === substr($prevNonWhitespaceToken->getContent(), 0, 2)) {
  23349. $tokens->removeLeadingWhitespace($index, " \t");
  23350. }
  23351. if (!$tokens[$tokens->getNextNonWhitespace($index)]->isGivenKind([T_LNUMBER, T_COMMENT, T_DOC_COMMENT])) {
  23352. $tokens->removeTrailingWhitespace($index, " \t");
  23353. }
  23354. }
  23355. private function fixConcatenationToSingleSpace(Tokens $tokens, $index)
  23356. {
  23357. $this->fixWhiteSpaceAroundConcatToken($tokens, $index, 1);
  23358. $this->fixWhiteSpaceAroundConcatToken($tokens, $index, -1);
  23359. }
  23360. private function fixWhiteSpaceAroundConcatToken(Tokens $tokens, $index, $offset)
  23361. {
  23362. $offsetIndex = $index + $offset;
  23363. if (!$tokens[$offsetIndex]->isWhitespace()) {
  23364. $tokens->insertAt($index + (1 === $offset ?: 0), new Token([T_WHITESPACE, ' ']));
  23365. return;
  23366. }
  23367. if (false !== strpos($tokens[$offsetIndex]->getContent(), "\n")) {
  23368. return;
  23369. }
  23370. if ($tokens[$index + $offset * 2]->isComment()) {
  23371. return;
  23372. }
  23373. $tokens[$offsetIndex] = new Token([T_WHITESPACE, ' ']);
  23374. }
  23375. }
  23376. <?php
  23377. namespace PhpCsFixer\Fixer\Operator;
  23378. use PhpCsFixer\AbstractFixer;
  23379. use PhpCsFixer\FixerDefinition\CodeSample;
  23380. use PhpCsFixer\FixerDefinition\FixerDefinition;
  23381. use PhpCsFixer\Tokenizer\Token;
  23382. use PhpCsFixer\Tokenizer\Tokens;
  23383. final class NotOperatorWithSpaceFixer extends AbstractFixer
  23384. {
  23385. public function getDefinition()
  23386. {
  23387. return new FixerDefinition(
  23388. 'Logical NOT operators (`!`) should have leading and trailing whitespaces.',
  23389. [new CodeSample(
  23390. '<?php
  23391. if (!$bar) {
  23392. echo "Help!";
  23393. }
  23394. '
  23395. )]
  23396. );
  23397. }
  23398. public function getPriority()
  23399. {
  23400. return -10;
  23401. }
  23402. public function isCandidate(Tokens $tokens)
  23403. {
  23404. return $tokens->isTokenKindFound('!');
  23405. }
  23406. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  23407. {
  23408. for ($index = $tokens->count() - 1; $index >= 0; --$index) {
  23409. $token = $tokens[$index];
  23410. if ($token->equals('!')) {
  23411. if (!$tokens[$index + 1]->isWhitespace()) {
  23412. $tokens->insertAt($index + 1, new Token([T_WHITESPACE, ' ']));
  23413. }
  23414. if (!$tokens[$index - 1]->isWhitespace()) {
  23415. $tokens->insertAt($index, new Token([T_WHITESPACE, ' ']));
  23416. }
  23417. }
  23418. }
  23419. }
  23420. }
  23421. <?php
  23422. namespace PhpCsFixer\Fixer\Operator;
  23423. use PhpCsFixer\AbstractFixer;
  23424. use PhpCsFixer\FixerDefinition\CodeSample;
  23425. use PhpCsFixer\FixerDefinition\FixerDefinition;
  23426. use PhpCsFixer\Tokenizer\CT;
  23427. use PhpCsFixer\Tokenizer\Token;
  23428. use PhpCsFixer\Tokenizer\Tokens;
  23429. final class NewWithBracesFixer extends AbstractFixer
  23430. {
  23431. public function getDefinition()
  23432. {
  23433. return new FixerDefinition(
  23434. 'All instances created with new keyword must be followed by braces.',
  23435. [new CodeSample("<?php \$x = new X;\n")]
  23436. );
  23437. }
  23438. public function isCandidate(Tokens $tokens)
  23439. {
  23440. return $tokens->isTokenKindFound(T_NEW);
  23441. }
  23442. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  23443. {
  23444. static $nextTokenKinds = null;
  23445. if (null === $nextTokenKinds) {
  23446. $nextTokenKinds = [
  23447. '?',
  23448. ';',
  23449. ',',
  23450. '(',
  23451. ')',
  23452. '[',
  23453. ']',
  23454. ':',
  23455. '<',
  23456. '>',
  23457. '+',
  23458. '-',
  23459. '*',
  23460. '/',
  23461. '%',
  23462. '&',
  23463. '^',
  23464. '|',
  23465. [T_CLASS],
  23466. [T_IS_SMALLER_OR_EQUAL],
  23467. [T_IS_GREATER_OR_EQUAL],
  23468. [T_IS_EQUAL],
  23469. [T_IS_NOT_EQUAL],
  23470. [T_IS_IDENTICAL],
  23471. [T_IS_NOT_IDENTICAL],
  23472. [T_CLOSE_TAG],
  23473. [T_LOGICAL_AND],
  23474. [T_LOGICAL_OR],
  23475. [T_LOGICAL_XOR],
  23476. [T_BOOLEAN_AND],
  23477. [T_BOOLEAN_OR],
  23478. [T_SL],
  23479. [T_SR],
  23480. [T_INSTANCEOF],
  23481. [T_AS],
  23482. [T_DOUBLE_ARROW],
  23483. [T_POW],
  23484. [CT::T_ARRAY_SQUARE_BRACE_OPEN],
  23485. [CT::T_ARRAY_SQUARE_BRACE_CLOSE],
  23486. [CT::T_BRACE_CLASS_INSTANTIATION_OPEN],
  23487. [CT::T_BRACE_CLASS_INSTANTIATION_CLOSE],
  23488. ];
  23489. if (\defined('T_SPACESHIP')) {
  23490. $nextTokenKinds[] = [T_SPACESHIP];
  23491. }
  23492. }
  23493. for ($index = $tokens->count() - 3; $index > 0; --$index) {
  23494. $token = $tokens[$index];
  23495. if (!$token->isGivenKind(T_NEW)) {
  23496. continue;
  23497. }
  23498. $nextIndex = $tokens->getNextTokenOfKind($index, $nextTokenKinds);
  23499. $nextToken = $tokens[$nextIndex];
  23500. if ($nextToken->isGivenKind(T_CLASS)) {
  23501. if (!$tokens[$tokens->getNextMeaningfulToken($nextIndex)]->equals('(')) {
  23502. $this->insertBracesAfter($tokens, $nextIndex);
  23503. }
  23504. continue;
  23505. }
  23506. while ($nextToken->equals('[') || $nextToken->isGivenKind(CT::T_ARRAY_INDEX_CURLY_BRACE_OPEN)) {
  23507. $nextIndex = $tokens->findBlockEnd($tokens->detectBlockType($nextToken)['type'], $nextIndex) + 1;
  23508. $nextToken = $tokens[$nextIndex];
  23509. }
  23510. if ($nextToken->isWhitespace()) {
  23511. $nextIndex = $tokens->getNextNonWhitespace($nextIndex);
  23512. $nextToken = $tokens[$nextIndex];
  23513. }
  23514. if ($nextToken->equals('(') || $nextToken->isGivenKind(T_OBJECT_OPERATOR)) {
  23515. continue;
  23516. }
  23517. $this->insertBracesAfter($tokens, $tokens->getPrevMeaningfulToken($nextIndex));
  23518. }
  23519. }
  23520. private function insertBracesAfter(Tokens $tokens, $index)
  23521. {
  23522. $tokens->insertAt(++$index, [new Token('('), new Token(')')]);
  23523. }
  23524. }
  23525. <?php
  23526. namespace PhpCsFixer\Fixer\Operator;
  23527. use PhpCsFixer\AbstractFixer;
  23528. use PhpCsFixer\FixerDefinition\CodeSample;
  23529. use PhpCsFixer\FixerDefinition\FixerDefinition;
  23530. use PhpCsFixer\Tokenizer\Tokens;
  23531. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  23532. final class UnaryOperatorSpacesFixer extends AbstractFixer
  23533. {
  23534. public function getDefinition()
  23535. {
  23536. return new FixerDefinition(
  23537. 'Unary operators should be placed adjacent to their operands.',
  23538. [new CodeSample("<?php\n\$sample ++;\n-- \$sample;\n\$sample = ! ! \$a;\n\$sample = ~ \$c;\nfunction & foo(){}\n")]
  23539. );
  23540. }
  23541. public function getPriority()
  23542. {
  23543. return 0;
  23544. }
  23545. public function isCandidate(Tokens $tokens)
  23546. {
  23547. return true;
  23548. }
  23549. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  23550. {
  23551. $tokensAnalyzer = new TokensAnalyzer($tokens);
  23552. for ($index = $tokens->count() - 1; $index >= 0; --$index) {
  23553. if ($tokensAnalyzer->isUnarySuccessorOperator($index)) {
  23554. if (!$tokens[$tokens->getPrevNonWhitespace($index)]->isComment()) {
  23555. $tokens->removeLeadingWhitespace($index);
  23556. }
  23557. continue;
  23558. }
  23559. if ($tokensAnalyzer->isUnaryPredecessorOperator($index)) {
  23560. $tokens->removeTrailingWhitespace($index);
  23561. continue;
  23562. }
  23563. }
  23564. }
  23565. }
  23566. <?php
  23567. namespace PhpCsFixer\Fixer\Operator;
  23568. use PhpCsFixer\AbstractFixer;
  23569. use PhpCsFixer\FixerDefinition\CodeSample;
  23570. use PhpCsFixer\FixerDefinition\FixerDefinition;
  23571. use PhpCsFixer\Tokenizer\CT;
  23572. use PhpCsFixer\Tokenizer\Token;
  23573. use PhpCsFixer\Tokenizer\Tokens;
  23574. final class StandardizeIncrementFixer extends AbstractFixer
  23575. {
  23576. const EXPRESSION_END_TOKENS = [
  23577. ';',
  23578. ')',
  23579. ']',
  23580. ',',
  23581. ':',
  23582. [CT::T_DYNAMIC_PROP_BRACE_CLOSE],
  23583. [CT::T_DYNAMIC_VAR_BRACE_CLOSE],
  23584. [T_CLOSE_TAG],
  23585. ];
  23586. public function getDefinition()
  23587. {
  23588. return new FixerDefinition(
  23589. 'Increment and decrement operators should be used if possible.',
  23590. [
  23591. new CodeSample("<?php\n\$i += 1;\n"),
  23592. new CodeSample("<?php\n\$i -= 1;\n"),
  23593. ]
  23594. );
  23595. }
  23596. public function getPriority()
  23597. {
  23598. return 1;
  23599. }
  23600. public function isCandidate(Tokens $tokens)
  23601. {
  23602. return $tokens->isAnyTokenKindsFound([T_PLUS_EQUAL, T_MINUS_EQUAL]);
  23603. }
  23604. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  23605. {
  23606. for ($index = $tokens->count() - 1; $index > 0; --$index) {
  23607. $expressionEnd = $tokens[$index];
  23608. if (!$expressionEnd->equalsAny(self::EXPRESSION_END_TOKENS)) {
  23609. continue;
  23610. }
  23611. $numberIndex = $tokens->getPrevMeaningfulToken($index);
  23612. $number = $tokens[$numberIndex];
  23613. if (!$number->isGivenKind(T_LNUMBER) || '1' !== $number->getContent()) {
  23614. continue;
  23615. }
  23616. $operatorIndex = $tokens->getPrevMeaningfulToken($numberIndex);
  23617. $operator = $tokens[$operatorIndex];
  23618. if (!$operator->isGivenKind([T_PLUS_EQUAL, T_MINUS_EQUAL])) {
  23619. continue;
  23620. }
  23621. $startIndex = $this->findStart($tokens, $tokens->getPrevMeaningfulToken($operatorIndex));
  23622. $this->clearRangeLeaveComments(
  23623. $tokens,
  23624. $tokens->getPrevMeaningfulToken($operatorIndex) + 1,
  23625. $numberIndex
  23626. );
  23627. $tokens->insertAt(
  23628. $startIndex,
  23629. new Token($operator->isGivenKind(T_PLUS_EQUAL) ? [T_INC, '++'] : [T_DEC, '--'])
  23630. );
  23631. }
  23632. }
  23633. private function findStart(Tokens $tokens, $index)
  23634. {
  23635. while (!$tokens[$index]->equalsAny(['$', [T_VARIABLE]])) {
  23636. if ($tokens[$index]->equals(']')) {
  23637. $index = $tokens->findBlockStart(Tokens::BLOCK_TYPE_INDEX_SQUARE_BRACE, $index);
  23638. } elseif ($tokens[$index]->isGivenKind(CT::T_DYNAMIC_PROP_BRACE_CLOSE)) {
  23639. $index = $tokens->findBlockStart(Tokens::BLOCK_TYPE_DYNAMIC_PROP_BRACE, $index);
  23640. } elseif ($tokens[$index]->isGivenKind(CT::T_DYNAMIC_VAR_BRACE_CLOSE)) {
  23641. $index = $tokens->findBlockStart(Tokens::BLOCK_TYPE_DYNAMIC_VAR_BRACE, $index);
  23642. } elseif ($tokens[$index]->isGivenKind(CT::T_ARRAY_INDEX_CURLY_BRACE_CLOSE)) {
  23643. $index = $tokens->findBlockStart(Tokens::BLOCK_TYPE_ARRAY_INDEX_CURLY_BRACE, $index);
  23644. } else {
  23645. $index = $tokens->getPrevMeaningfulToken($index);
  23646. }
  23647. }
  23648. while ($tokens[$tokens->getPrevMeaningfulToken($index)]->equals('$')) {
  23649. $index = $tokens->getPrevMeaningfulToken($index);
  23650. }
  23651. if ($tokens[$tokens->getPrevMeaningfulToken($index)]->isGivenKind(T_OBJECT_OPERATOR)) {
  23652. return $this->findStart($tokens, $tokens->getPrevMeaningfulToken($index));
  23653. }
  23654. return $index;
  23655. }
  23656. private function clearRangeLeaveComments(Tokens $tokens, $indexStart, $indexEnd)
  23657. {
  23658. for ($i = $indexStart; $i <= $indexEnd; ++$i) {
  23659. $token = $tokens[$i];
  23660. if ($token->isComment()) {
  23661. continue;
  23662. }
  23663. if ($token->isWhitespace("\n\r")) {
  23664. continue;
  23665. }
  23666. $tokens->clearAt($i);
  23667. }
  23668. }
  23669. }
  23670. <?php
  23671. namespace PhpCsFixer\Fixer\Operator;
  23672. use PhpCsFixer\AbstractFixer;
  23673. use PhpCsFixer\FixerDefinition\CodeSample;
  23674. use PhpCsFixer\FixerDefinition\FixerDefinition;
  23675. use PhpCsFixer\Tokenizer\Token;
  23676. use PhpCsFixer\Tokenizer\Tokens;
  23677. final class TernaryOperatorSpacesFixer extends AbstractFixer
  23678. {
  23679. public function getDefinition()
  23680. {
  23681. return new FixerDefinition(
  23682. 'Standardize spaces around ternary operator.',
  23683. [new CodeSample("<?php \$a = \$a ?1 :0;\n")]
  23684. );
  23685. }
  23686. public function getPriority()
  23687. {
  23688. return 0;
  23689. }
  23690. public function isCandidate(Tokens $tokens)
  23691. {
  23692. return $tokens->isAllTokenKindsFound(['?', ':']);
  23693. }
  23694. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  23695. {
  23696. $ternaryLevel = 0;
  23697. foreach ($tokens as $index => $token) {
  23698. if ($token->equals('?')) {
  23699. ++$ternaryLevel;
  23700. $nextNonWhitespaceIndex = $tokens->getNextNonWhitespace($index);
  23701. $nextNonWhitespaceToken = $tokens[$nextNonWhitespaceIndex];
  23702. if ($nextNonWhitespaceToken->equals(':')) {
  23703. if ($tokens[$index + 1]->isWhitespace()) {
  23704. $tokens->clearAt($index + 1);
  23705. }
  23706. } else {
  23707. $this->ensureWhitespaceExistence($tokens, $index + 1, true);
  23708. }
  23709. $this->ensureWhitespaceExistence($tokens, $index - 1, false);
  23710. continue;
  23711. }
  23712. if ($ternaryLevel && $token->equals(':')) {
  23713. $this->ensureWhitespaceExistence($tokens, $index + 1, true);
  23714. $prevNonWhitespaceToken = $tokens[$tokens->getPrevNonWhitespace($index)];
  23715. if (!$prevNonWhitespaceToken->equals('?')) {
  23716. $this->ensureWhitespaceExistence($tokens, $index - 1, false);
  23717. }
  23718. --$ternaryLevel;
  23719. }
  23720. }
  23721. }
  23722. private function ensureWhitespaceExistence(Tokens $tokens, $index, $after)
  23723. {
  23724. if ($tokens[$index]->isWhitespace()) {
  23725. if (
  23726. false === strpos($tokens[$index]->getContent(), "\n")
  23727. && !$tokens[$index - 1]->isComment()
  23728. ) {
  23729. $tokens[$index] = new Token([T_WHITESPACE, ' ']);
  23730. }
  23731. return;
  23732. }
  23733. $index += $after ? 0 : 1;
  23734. $tokens->insertAt($index, new Token([T_WHITESPACE, ' ']));
  23735. }
  23736. }
  23737. <?php
  23738. namespace PhpCsFixer\Fixer\Operator;
  23739. use PhpCsFixer\AbstractAlignFixerHelper;
  23740. use PhpCsFixer\Tokenizer\CT;
  23741. use PhpCsFixer\Tokenizer\Token;
  23742. use PhpCsFixer\Tokenizer\Tokens;
  23743. /**
  23744. @alt
  23745. */
  23746. final class AlignEqualsFixerHelper extends AbstractAlignFixerHelper
  23747. {
  23748. public function __construct()
  23749. {
  23750. @trigger_error(
  23751. sprintf(
  23752. 'The "%s" class is deprecated. You should stop using it, as it will be removed in 3.0 version.',
  23753. __CLASS__
  23754. ),
  23755. E_USER_DEPRECATED
  23756. );
  23757. }
  23758. protected function injectAlignmentPlaceholders(Tokens $tokens, $startAt, $endAt)
  23759. {
  23760. for ($index = $startAt; $index < $endAt; ++$index) {
  23761. $token = $tokens[$index];
  23762. if ($token->equals('=')) {
  23763. $tokens[$index] = new Token(sprintf(self::ALIGNABLE_PLACEHOLDER, $this->deepestLevel).$token->getContent());
  23764. continue;
  23765. }
  23766. if ($token->isGivenKind(T_FUNCTION)) {
  23767. ++$this->deepestLevel;
  23768. continue;
  23769. }
  23770. if ($token->equals('(')) {
  23771. $index = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $index);
  23772. continue;
  23773. }
  23774. if ($token->equals('[')) {
  23775. $index = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_INDEX_SQUARE_BRACE, $index);
  23776. continue;
  23777. }
  23778. if ($token->isGivenKind(CT::T_ARRAY_SQUARE_BRACE_OPEN)) {
  23779. $index = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_ARRAY_SQUARE_BRACE, $index);
  23780. continue;
  23781. }
  23782. }
  23783. }
  23784. }
  23785. <?php
  23786. namespace PhpCsFixer\Fixer\Operator;
  23787. use PhpCsFixer\AbstractFixer;
  23788. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  23789. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  23790. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  23791. use PhpCsFixer\FixerDefinition\CodeSample;
  23792. use PhpCsFixer\FixerDefinition\FixerDefinition;
  23793. use PhpCsFixer\Tokenizer\CT;
  23794. use PhpCsFixer\Tokenizer\Tokens;
  23795. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  23796. /**
  23797. @gmail
  23798. */
  23799. final class IncrementStyleFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface
  23800. {
  23801. const STYLE_PRE = 'pre';
  23802. const STYLE_POST = 'post';
  23803. public function getDefinition()
  23804. {
  23805. return new FixerDefinition(
  23806. 'Pre- or post-increment and decrement operators should be used if possible.',
  23807. [
  23808. new CodeSample("<?php\n\$a++;\n\$b--;\n"),
  23809. new CodeSample(
  23810. "<?php\n++\$a;\n--\$b;\n",
  23811. ['style' => self::STYLE_POST]
  23812. ),
  23813. ]
  23814. );
  23815. }
  23816. public function getPriority()
  23817. {
  23818. return 0;
  23819. }
  23820. public function isCandidate(Tokens $tokens)
  23821. {
  23822. return $tokens->isAnyTokenKindsFound([T_INC, T_DEC]);
  23823. }
  23824. protected function createConfigurationDefinition()
  23825. {
  23826. return new FixerConfigurationResolver([
  23827. (new FixerOptionBuilder('style', 'Whether to use pre- or post-increment and decrement operators.'))
  23828. ->setAllowedValues([self::STYLE_PRE, self::STYLE_POST])
  23829. ->setDefault(self::STYLE_PRE)
  23830. ->getOption(),
  23831. ]);
  23832. }
  23833. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  23834. {
  23835. $tokensAnalyzer = new TokensAnalyzer($tokens);
  23836. for ($index = $tokens->count() - 1; 0 <= $index; --$index) {
  23837. $token = $tokens[$index];
  23838. if (!$token->isGivenKind([T_INC, T_DEC])) {
  23839. continue;
  23840. }
  23841. if (self::STYLE_PRE === $this->configuration['style'] && $tokensAnalyzer->isUnarySuccessorOperator($index)) {
  23842. $nextToken = $tokens[$tokens->getNextMeaningfulToken($index)];
  23843. if (!$nextToken->equalsAny([';', ')'])) {
  23844. continue;
  23845. }
  23846. $startIndex = $this->findStart($tokens, $index);
  23847. $prevToken = $tokens[$tokens->getPrevMeaningfulToken($startIndex)];
  23848. if ($prevToken->equalsAny([';', '{', '}', [T_OPEN_TAG], ')'])) {
  23849. $tokens->clearAt($index);
  23850. $tokens->insertAt($startIndex, clone $token);
  23851. }
  23852. } elseif (self::STYLE_POST === $this->configuration['style'] && $tokensAnalyzer->isUnaryPredecessorOperator($index)) {
  23853. $prevToken = $tokens[$tokens->getPrevMeaningfulToken($index)];
  23854. if (!$prevToken->equalsAny([';', '{', '}', [T_OPEN_TAG], ')'])) {
  23855. continue;
  23856. }
  23857. $endIndex = $this->findEnd($tokens, $index);
  23858. $nextToken = $tokens[$tokens->getNextMeaningfulToken($endIndex)];
  23859. if ($nextToken->equalsAny([';', ')'])) {
  23860. $tokens->clearAt($index);
  23861. $tokens->insertAt($tokens->getNextNonWhitespace($endIndex), clone $token);
  23862. }
  23863. }
  23864. }
  23865. }
  23866. private function findEnd(Tokens $tokens, $index)
  23867. {
  23868. $nextIndex = $tokens->getNextMeaningfulToken($index);
  23869. $nextToken = $tokens[$nextIndex];
  23870. while ($nextToken->equalsAny([
  23871. '$',
  23872. '[',
  23873. [CT::T_DYNAMIC_PROP_BRACE_OPEN],
  23874. [CT::T_DYNAMIC_VAR_BRACE_OPEN],
  23875. [CT::T_ARRAY_INDEX_CURLY_BRACE_OPEN],
  23876. [T_NS_SEPARATOR],
  23877. [T_STATIC],
  23878. [T_STRING],
  23879. [T_VARIABLE],
  23880. ])) {
  23881. $blockType = Tokens::detectBlockType($nextToken);
  23882. if (null !== $blockType) {
  23883. $nextIndex = $tokens->findBlockEnd($blockType['type'], $nextIndex);
  23884. }
  23885. $index = $nextIndex;
  23886. $nextIndex = $tokens->getNextMeaningfulToken($nextIndex);
  23887. $nextToken = $tokens[$nextIndex];
  23888. }
  23889. if ($nextToken->isGivenKind(T_OBJECT_OPERATOR)) {
  23890. return $this->findEnd($tokens, $nextIndex);
  23891. }
  23892. if ($nextToken->isGivenKind(T_PAAMAYIM_NEKUDOTAYIM)) {
  23893. return $this->findEnd($tokens, $tokens->getNextMeaningfulToken($nextIndex));
  23894. }
  23895. return $index;
  23896. }
  23897. private function findStart(Tokens $tokens, $index)
  23898. {
  23899. do {
  23900. $index = $tokens->getPrevMeaningfulToken($index);
  23901. $token = $tokens[$index];
  23902. $blockType = Tokens::detectBlockType($token);
  23903. if (null !== $blockType && !$blockType['isStart']) {
  23904. $index = $tokens->findBlockStart($blockType['type'], $index);
  23905. $token = $tokens[$index];
  23906. }
  23907. } while (!$token->equalsAny(['$', [T_VARIABLE]]));
  23908. $prevIndex = $tokens->getPrevMeaningfulToken($index);
  23909. $prevToken = $tokens[$prevIndex];
  23910. if ($prevToken->equals('$')) {
  23911. $index = $prevIndex;
  23912. $prevIndex = $tokens->getPrevMeaningfulToken($index);
  23913. $prevToken = $tokens[$prevIndex];
  23914. }
  23915. if ($prevToken->isGivenKind(T_OBJECT_OPERATOR)) {
  23916. return $this->findStart($tokens, $prevIndex);
  23917. }
  23918. if ($prevToken->isGivenKind(T_PAAMAYIM_NEKUDOTAYIM)) {
  23919. $prevPrevIndex = $tokens->getPrevMeaningfulToken($prevIndex);
  23920. if (!$tokens[$prevPrevIndex]->isGivenKind([T_STATIC, T_STRING])) {
  23921. return $this->findStart($tokens, $prevIndex);
  23922. }
  23923. $index = $tokens->getTokenNotOfKindSibling($prevIndex, -1, [[T_NS_SEPARATOR], [T_STATIC], [T_STRING]]);
  23924. $index = $tokens->getNextMeaningfulToken($index);
  23925. }
  23926. return $index;
  23927. }
  23928. }
  23929. <?php
  23930. namespace PhpCsFixer\Fixer\Operator;
  23931. use PhpCsFixer\AbstractFixer;
  23932. use PhpCsFixer\FixerDefinition\CodeSample;
  23933. use PhpCsFixer\FixerDefinition\FixerDefinition;
  23934. use PhpCsFixer\Tokenizer\Token;
  23935. use PhpCsFixer\Tokenizer\Tokens;
  23936. final class NotOperatorWithSuccessorSpaceFixer extends AbstractFixer
  23937. {
  23938. public function getDefinition()
  23939. {
  23940. return new FixerDefinition(
  23941. 'Logical NOT operators (`!`) should have one trailing whitespace.',
  23942. [new CodeSample(
  23943. '<?php
  23944. if (!$bar) {
  23945. echo "Help!";
  23946. }
  23947. '
  23948. )]
  23949. );
  23950. }
  23951. public function getPriority()
  23952. {
  23953. return -10;
  23954. }
  23955. public function isCandidate(Tokens $tokens)
  23956. {
  23957. return $tokens->isTokenKindFound('!');
  23958. }
  23959. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  23960. {
  23961. for ($index = $tokens->count() - 1; $index >= 0; --$index) {
  23962. $token = $tokens[$index];
  23963. if ($token->equals('!')) {
  23964. if (!$tokens[$index + 1]->isWhitespace()) {
  23965. $tokens->insertAt($index + 1, new Token([T_WHITESPACE, ' ']));
  23966. } else {
  23967. $tokens[$index + 1] = new Token([T_WHITESPACE, ' ']);
  23968. }
  23969. }
  23970. }
  23971. }
  23972. }
  23973. <?php
  23974. namespace PhpCsFixer\Fixer\Operator;
  23975. use PhpCsFixer\AbstractFixer;
  23976. use PhpCsFixer\FixerDefinition\CodeSample;
  23977. use PhpCsFixer\FixerDefinition\FixerDefinition;
  23978. use PhpCsFixer\Tokenizer\Token;
  23979. use PhpCsFixer\Tokenizer\Tokens;
  23980. final class StandardizeNotEqualsFixer extends AbstractFixer
  23981. {
  23982. public function getDefinition()
  23983. {
  23984. return new FixerDefinition(
  23985. 'Replace all `<>` with `!=`.',
  23986. [new CodeSample("<?php\n\$a = \$b <> \$c;\n")]
  23987. );
  23988. }
  23989. public function getPriority()
  23990. {
  23991. return 0;
  23992. }
  23993. public function isCandidate(Tokens $tokens)
  23994. {
  23995. return $tokens->isTokenKindFound(T_IS_NOT_EQUAL);
  23996. }
  23997. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  23998. {
  23999. foreach ($tokens as $index => $token) {
  24000. if ($token->isGivenKind(T_IS_NOT_EQUAL)) {
  24001. $tokens[$index] = new Token([T_IS_NOT_EQUAL, '!=']);
  24002. }
  24003. }
  24004. }
  24005. }
  24006. <?php
  24007. namespace PhpCsFixer\Fixer\Operator;
  24008. use PhpCsFixer\AbstractFixer;
  24009. use PhpCsFixer\FixerDefinition\FixerDefinition;
  24010. use PhpCsFixer\FixerDefinition\VersionSpecification;
  24011. use PhpCsFixer\FixerDefinition\VersionSpecificCodeSample;
  24012. use PhpCsFixer\Tokenizer\Token;
  24013. use PhpCsFixer\Tokenizer\Tokens;
  24014. final class TernaryToNullCoalescingFixer extends AbstractFixer
  24015. {
  24016. public function getDefinition()
  24017. {
  24018. return new FixerDefinition(
  24019. 'Use `null` coalescing operator `??` where possible. Requires PHP >= 7.0.',
  24020. [
  24021. new VersionSpecificCodeSample(
  24022. "<?php\n\$sample = isset(\$a) ? \$a : \$b;\n",
  24023. new VersionSpecification(70000)
  24024. ),
  24025. ]
  24026. );
  24027. }
  24028. public function isCandidate(Tokens $tokens)
  24029. {
  24030. return \PHP_VERSION_ID >= 70000 && $tokens->isTokenKindFound(T_ISSET);
  24031. }
  24032. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  24033. {
  24034. $issetIndexes = array_keys($tokens->findGivenKind(T_ISSET));
  24035. while ($issetIndex = array_pop($issetIndexes)) {
  24036. $this->fixIsset($tokens, $issetIndex);
  24037. }
  24038. }
  24039. private function fixIsset(Tokens $tokens, $index)
  24040. {
  24041. $prevTokenIndex = $tokens->getPrevMeaningfulToken($index);
  24042. if ($this->isHigherPrecedenceAssociativityOperator($tokens[$prevTokenIndex])) {
  24043. return;
  24044. }
  24045. $startBraceIndex = $tokens->getNextTokenOfKind($index, ['(']);
  24046. $endBraceIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $startBraceIndex);
  24047. $ternaryQuestionMarkIndex = $tokens->getNextMeaningfulToken($endBraceIndex);
  24048. if (!$tokens[$ternaryQuestionMarkIndex]->equals('?')) {
  24049. return;
  24050. }
  24051. $issetTokens = $this->getMeaningfulSequence($tokens, $startBraceIndex, $endBraceIndex);
  24052. if ($this->hasChangingContent($issetTokens)) {
  24053. return;
  24054. }
  24055. $ternaryColonIndex = $tokens->getNextTokenOfKind($ternaryQuestionMarkIndex, [':']);
  24056. $ternaryFirstOperandTokens = $this->getMeaningfulSequence($tokens, $ternaryQuestionMarkIndex, $ternaryColonIndex);
  24057. if ($issetTokens->generateCode() !== $ternaryFirstOperandTokens->generateCode()) {
  24058. return;
  24059. }
  24060. $ternaryFirstOperandIndex = $tokens->getNextMeaningfulToken($ternaryQuestionMarkIndex);
  24061. $comments = [];
  24062. $commentStarted = false;
  24063. for ($loopIndex = $index; $loopIndex < $ternaryFirstOperandIndex; ++$loopIndex) {
  24064. if ($tokens[$loopIndex]->isComment()) {
  24065. $comments[] = $tokens[$loopIndex];
  24066. $commentStarted = true;
  24067. } elseif ($commentStarted) {
  24068. if ($tokens[$loopIndex]->isWhitespace()) {
  24069. $comments[] = $tokens[$loopIndex];
  24070. }
  24071. $commentStarted = false;
  24072. }
  24073. }
  24074. $tokens[$ternaryColonIndex] = new Token([T_COALESCE, '??']);
  24075. $tokens->overrideRange($index, $ternaryFirstOperandIndex - 1, $comments);
  24076. }
  24077. private function getMeaningfulSequence(Tokens $tokens, $start, $end)
  24078. {
  24079. $sequence = [];
  24080. $index = $start;
  24081. while ($index < $end) {
  24082. $index = $tokens->getNextMeaningfulToken($index);
  24083. if ($index >= $end || null === $index) {
  24084. break;
  24085. }
  24086. $sequence[] = $tokens[$index];
  24087. }
  24088. return Tokens::fromArray($sequence);
  24089. }
  24090. private function isHigherPrecedenceAssociativityOperator(Token $token)
  24091. {
  24092. static $operatorsPerId = [
  24093. T_ARRAY_CAST => true,
  24094. T_BOOLEAN_AND => true,
  24095. T_BOOLEAN_OR => true,
  24096. T_BOOL_CAST => true,
  24097. T_COALESCE => true,
  24098. T_DEC => true,
  24099. T_DOUBLE_CAST => true,
  24100. T_INC => true,
  24101. T_INT_CAST => true,
  24102. T_IS_EQUAL => true,
  24103. T_IS_GREATER_OR_EQUAL => true,
  24104. T_IS_IDENTICAL => true,
  24105. T_IS_NOT_EQUAL => true,
  24106. T_IS_NOT_IDENTICAL => true,
  24107. T_IS_SMALLER_OR_EQUAL => true,
  24108. T_OBJECT_CAST => true,
  24109. T_POW => true,
  24110. T_SL => true,
  24111. T_SPACESHIP => true,
  24112. T_SR => true,
  24113. T_STRING_CAST => true,
  24114. T_UNSET_CAST => true,
  24115. ];
  24116. static $operatorsPerContent = [
  24117. '!',
  24118. '%',
  24119. '&',
  24120. '*',
  24121. '+',
  24122. '-',
  24123. '/',
  24124. ':',
  24125. '^',
  24126. '|',
  24127. '~',
  24128. ];
  24129. return isset($operatorsPerId[$token->getId()]) || $token->equalsAny($operatorsPerContent);
  24130. }
  24131. private function hasChangingContent(Tokens $tokens)
  24132. {
  24133. static $operatorsPerId = [
  24134. T_DEC,
  24135. T_INC,
  24136. T_STRING,
  24137. T_YIELD,
  24138. T_YIELD_FROM,
  24139. ];
  24140. foreach ($tokens as $token) {
  24141. if ($token->isGivenKind($operatorsPerId) || $token->equals('(')) {
  24142. return true;
  24143. }
  24144. }
  24145. return false;
  24146. }
  24147. }
  24148. <?php
  24149. namespace PhpCsFixer\Fixer\Operator;
  24150. use PhpCsFixer\AbstractFixer;
  24151. use PhpCsFixer\ConfigurationException\InvalidFixerConfigurationException;
  24152. use PhpCsFixer\Console\Command\HelpCommand;
  24153. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  24154. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  24155. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  24156. use PhpCsFixer\FixerDefinition\CodeSample;
  24157. use PhpCsFixer\FixerDefinition\FixerDefinition;
  24158. use PhpCsFixer\Preg;
  24159. use PhpCsFixer\Tokenizer\CT;
  24160. use PhpCsFixer\Tokenizer\Token;
  24161. use PhpCsFixer\Tokenizer\Tokens;
  24162. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  24163. use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException;
  24164. final class BinaryOperatorSpacesFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface
  24165. {
  24166. const SINGLE_SPACE = 'single_space';
  24167. const NO_SPACE = 'no_space';
  24168. const ALIGN = 'align';
  24169. const ALIGN_SINGLE_SPACE = 'align_single_space';
  24170. const ALIGN_SINGLE_SPACE_MINIMAL = 'align_single_space_minimal';
  24171. /**
  24172. @const
  24173. */
  24174. const ALIGN_PLACEHOLDER = "\x2 ALIGNABLE%d \x3";
  24175. private $deepestLevel;
  24176. private $currentLevel;
  24177. private static $allowedValues = [
  24178. self::ALIGN,
  24179. self::ALIGN_SINGLE_SPACE,
  24180. self::ALIGN_SINGLE_SPACE_MINIMAL,
  24181. self::SINGLE_SPACE,
  24182. self::NO_SPACE,
  24183. null,
  24184. ];
  24185. private static $supportedOperators = [
  24186. '=',
  24187. '*',
  24188. '/',
  24189. '%',
  24190. '<',
  24191. '>',
  24192. '|',
  24193. '^',
  24194. '+',
  24195. '-',
  24196. '&',
  24197. '&=',
  24198. '&&',
  24199. '||',
  24200. '.=',
  24201. '/=',
  24202. '=>',
  24203. '==',
  24204. '>=',
  24205. '===',
  24206. '!=',
  24207. '<>',
  24208. '!==',
  24209. '<=',
  24210. 'and',
  24211. 'or',
  24212. 'xor',
  24213. '-=',
  24214. '%=',
  24215. '*=',
  24216. '|=',
  24217. '+=',
  24218. '<<',
  24219. '<<=',
  24220. '>>',
  24221. '>>=',
  24222. '^=',
  24223. '**',
  24224. '**=',
  24225. '<=>',
  24226. '??',
  24227. '??=',
  24228. ];
  24229. private $tokensAnalyzer;
  24230. private $alignOperatorTokens = [];
  24231. private $operators = [];
  24232. public function configure(array $configuration = null)
  24233. {
  24234. if (
  24235. null !== $configuration &&
  24236. (\array_key_exists('align_equals', $configuration) || \array_key_exists('align_double_arrow', $configuration))
  24237. ) {
  24238. $configuration = $this->resolveOldConfig($configuration);
  24239. }
  24240. parent::configure($configuration);
  24241. $this->operators = $this->resolveOperatorsFromConfig();
  24242. }
  24243. public function getDefinition()
  24244. {
  24245. return new FixerDefinition(
  24246. 'Binary operators should be surrounded by space as configured.',
  24247. [
  24248. new CodeSample(
  24249. "<?php\n\$a= 1 + \$b^ \$d !== \$e or \$f;\n"
  24250. ),
  24251. new CodeSample(
  24252. '<?php
  24253. $aa= 1;
  24254. $b=2;
  24255. $c = $d xor $e;
  24256. $f -= 1;
  24257. ',
  24258. ['operators' => ['=' => 'align', 'xor' => null]]
  24259. ),
  24260. new CodeSample(
  24261. '<?php
  24262. $a = $b +=$c;
  24263. $d = $ee+=$f;
  24264. $g = $b +=$c;
  24265. $h = $ee+=$f;
  24266. ',
  24267. ['operators' => ['+=' => 'align_single_space']]
  24268. ),
  24269. new CodeSample(
  24270. '<?php
  24271. $a = $b===$c;
  24272. $d = $f === $g;
  24273. $h = $i=== $j;
  24274. ',
  24275. ['operators' => ['===' => 'align_single_space_minimal']]
  24276. ),
  24277. new CodeSample(
  24278. '<?php
  24279. $foo = \json_encode($bar, JSON_PRESERVE_ZERO_FRACTION | JSON_PRETTY_PRINT);
  24280. ',
  24281. ['operators' => ['|' => 'no_space']]
  24282. ),
  24283. ]
  24284. );
  24285. }
  24286. public function getPriority()
  24287. {
  24288. return -32;
  24289. }
  24290. public function isCandidate(Tokens $tokens)
  24291. {
  24292. return true;
  24293. }
  24294. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  24295. {
  24296. $this->tokensAnalyzer = new TokensAnalyzer($tokens);
  24297. for ($index = $tokens->count() - 2; $index > 0; --$index) {
  24298. if (!$this->tokensAnalyzer->isBinaryOperator($index)) {
  24299. continue;
  24300. }
  24301. if ('=' === $tokens[$index]->getContent()) {
  24302. $isDeclare = $this->isEqualPartOfDeclareStatement($tokens, $index);
  24303. if (false === $isDeclare) {
  24304. $this->fixWhiteSpaceAroundOperator($tokens, $index);
  24305. } else {
  24306. $index = $isDeclare;
  24307. }
  24308. } else {
  24309. $this->fixWhiteSpaceAroundOperator($tokens, $index);
  24310. }
  24311. --$index;
  24312. }
  24313. if (\count($this->alignOperatorTokens)) {
  24314. $this->fixAlignment($tokens, $this->alignOperatorTokens);
  24315. }
  24316. }
  24317. protected function createConfigurationDefinition()
  24318. {
  24319. return new FixerConfigurationResolver([
  24320. (new FixerOptionBuilder('default', 'Default fix strategy.'))
  24321. ->setDefault(self::SINGLE_SPACE)
  24322. ->setAllowedValues(self::$allowedValues)
  24323. ->getOption(),
  24324. (new FixerOptionBuilder('operators', 'Dictionary of `binary operator` => `fix strategy` values that differ from the default strategy.'))
  24325. ->setAllowedTypes(['array'])
  24326. ->setAllowedValues([static function ($option) {
  24327. foreach ($option as $operator => $value) {
  24328. if (!\in_array($operator, self::$supportedOperators, true)) {
  24329. throw new InvalidOptionsException(
  24330. sprintf(
  24331. 'Unexpected "operators" key, expected any of "%s", got "%s".',
  24332. implode('", "', self::$supportedOperators),
  24333. \is_object($operator) ? \get_class($operator) : \gettype($operator).'#'.$operator
  24334. )
  24335. );
  24336. }
  24337. if (!\in_array($value, self::$allowedValues, true)) {
  24338. throw new InvalidOptionsException(
  24339. sprintf(
  24340. 'Unexpected value for operator "%s", expected any of "%s", got "%s".',
  24341. $operator,
  24342. implode('", "', self::$allowedValues),
  24343. \is_object($value) ? \get_class($value) : (null === $value ? 'null' : \gettype($value).'#'.$value)
  24344. )
  24345. );
  24346. }
  24347. }
  24348. return true;
  24349. }])
  24350. ->setDefault([])
  24351. ->getOption(),
  24352. (new FixerOptionBuilder('align_double_arrow', 'Whether to apply, remove or ignore double arrows alignment.'))
  24353. ->setDefault(false)
  24354. ->setAllowedValues([true, false, null])
  24355. ->setDeprecationMessage('Use options `operators` and `default` instead.')
  24356. ->getOption(),
  24357. (new FixerOptionBuilder('align_equals', 'Whether to apply, remove or ignore equals alignment.'))
  24358. ->setDefault(false)
  24359. ->setAllowedValues([true, false, null])
  24360. ->setDeprecationMessage('Use options `operators` and `default` instead.')
  24361. ->getOption(),
  24362. ]);
  24363. }
  24364. private function fixWhiteSpaceAroundOperator(Tokens $tokens, $index)
  24365. {
  24366. $tokenContent = strtolower($tokens[$index]->getContent());
  24367. if (!\array_key_exists($tokenContent, $this->operators)) {
  24368. return;
  24369. }
  24370. if (self::SINGLE_SPACE === $this->operators[$tokenContent]) {
  24371. $this->fixWhiteSpaceAroundOperatorToSingleSpace($tokens, $index);
  24372. return;
  24373. }
  24374. if (self::NO_SPACE === $this->operators[$tokenContent]) {
  24375. $this->fixWhiteSpaceAroundOperatorToNoSpace($tokens, $index);
  24376. return;
  24377. }
  24378. $this->alignOperatorTokens[$tokenContent] = $this->operators[$tokenContent];
  24379. if (self::ALIGN === $this->operators[$tokenContent]) {
  24380. return;
  24381. }
  24382. if ($tokens[$index + 1]->isWhitespace()) {
  24383. if (self::ALIGN_SINGLE_SPACE_MINIMAL === $this->operators[$tokenContent]) {
  24384. $tokens[$index + 1] = new Token([T_WHITESPACE, ' ']);
  24385. }
  24386. return;
  24387. }
  24388. $tokens->insertAt($index + 1, new Token([T_WHITESPACE, ' ']));
  24389. }
  24390. private function fixWhiteSpaceAroundOperatorToSingleSpace(Tokens $tokens, $index)
  24391. {
  24392. if ($tokens[$index + 1]->isWhitespace()) {
  24393. $content = $tokens[$index + 1]->getContent();
  24394. if (' ' !== $content && false === strpos($content, "\n") && !$tokens[$tokens->getNextNonWhitespace($index + 1)]->isComment()) {
  24395. $tokens[$index + 1] = new Token([T_WHITESPACE, ' ']);
  24396. }
  24397. } else {
  24398. $tokens->insertAt($index + 1, new Token([T_WHITESPACE, ' ']));
  24399. }
  24400. if ($tokens[$index - 1]->isWhitespace()) {
  24401. $content = $tokens[$index - 1]->getContent();
  24402. if (' ' !== $content && false === strpos($content, "\n") && !$tokens[$tokens->getPrevNonWhitespace($index - 1)]->isComment()) {
  24403. $tokens[$index - 1] = new Token([T_WHITESPACE, ' ']);
  24404. }
  24405. } else {
  24406. $tokens->insertAt($index, new Token([T_WHITESPACE, ' ']));
  24407. }
  24408. }
  24409. private function fixWhiteSpaceAroundOperatorToNoSpace(Tokens $tokens, $index)
  24410. {
  24411. if ($tokens[$index + 1]->isWhitespace()) {
  24412. $content = $tokens[$index + 1]->getContent();
  24413. if (false === strpos($content, "\n") && !$tokens[$tokens->getNextNonWhitespace($index + 1)]->isComment()) {
  24414. $tokens->clearAt($index + 1);
  24415. }
  24416. }
  24417. if ($tokens[$index - 1]->isWhitespace()) {
  24418. $content = $tokens[$index - 1]->getContent();
  24419. if (false === strpos($content, "\n") && !$tokens[$tokens->getPrevNonWhitespace($index - 1)]->isComment()) {
  24420. $tokens->clearAt($index - 1);
  24421. }
  24422. }
  24423. }
  24424. private function isEqualPartOfDeclareStatement(Tokens $tokens, $index)
  24425. {
  24426. $prevMeaningfulIndex = $tokens->getPrevMeaningfulToken($index);
  24427. if ($tokens[$prevMeaningfulIndex]->isGivenKind(T_STRING)) {
  24428. $prevMeaningfulIndex = $tokens->getPrevMeaningfulToken($prevMeaningfulIndex);
  24429. if ($tokens[$prevMeaningfulIndex]->equals('(')) {
  24430. $prevMeaningfulIndex = $tokens->getPrevMeaningfulToken($prevMeaningfulIndex);
  24431. if ($tokens[$prevMeaningfulIndex]->isGivenKind(T_DECLARE)) {
  24432. return $prevMeaningfulIndex;
  24433. }
  24434. }
  24435. }
  24436. return false;
  24437. }
  24438. private function resolveOperatorsFromConfig()
  24439. {
  24440. $operators = [];
  24441. if (null !== $this->configuration['default']) {
  24442. foreach (self::$supportedOperators as $operator) {
  24443. $operators[$operator] = $this->configuration['default'];
  24444. }
  24445. }
  24446. foreach ($this->configuration['operators'] as $operator => $value) {
  24447. if (null === $value) {
  24448. unset($operators[$operator]);
  24449. } else {
  24450. $operators[$operator] = $value;
  24451. }
  24452. }
  24453. if (!\defined('T_SPACESHIP')) {
  24454. unset($operators['<=>']);
  24455. }
  24456. if (!\defined('T_COALESCE')) {
  24457. unset($operators['??']);
  24458. }
  24459. if (!\defined('T_COALESCE_EQUAL')) {
  24460. unset($operators['??=']);
  24461. }
  24462. return $operators;
  24463. }
  24464. private function resolveOldConfig(array $configuration)
  24465. {
  24466. $newConfig = [
  24467. 'operators' => [],
  24468. ];
  24469. foreach ($configuration as $name => $setting) {
  24470. if ('align_double_arrow' === $name) {
  24471. if (true === $configuration[$name]) {
  24472. $newConfig['operators']['=>'] = self::ALIGN;
  24473. } elseif (false === $configuration[$name]) {
  24474. $newConfig['operators']['=>'] = self::SINGLE_SPACE;
  24475. } elseif (null !== $configuration[$name]) {
  24476. throw new InvalidFixerConfigurationException(
  24477. $this->getName(),
  24478. sprintf(
  24479. 'Invalid configuration: The option "align_double_arrow" with value %s is invalid. Accepted values are: true, false, null.',
  24480. $configuration[$name]
  24481. )
  24482. );
  24483. }
  24484. } elseif ('align_equals' === $name) {
  24485. if (true === $configuration[$name]) {
  24486. $newConfig['operators']['='] = self::ALIGN;
  24487. } elseif (false === $configuration[$name]) {
  24488. $newConfig['operators']['='] = self::SINGLE_SPACE;
  24489. } elseif (null !== $configuration[$name]) {
  24490. throw new InvalidFixerConfigurationException(
  24491. $this->getName(),
  24492. sprintf(
  24493. 'Invalid configuration: The option "align_equals" with value %s is invalid. Accepted values are: true, false, null.',
  24494. $configuration[$name]
  24495. )
  24496. );
  24497. }
  24498. } else {
  24499. throw new InvalidFixerConfigurationException($this->getName(), 'Mixing old configuration with new configuration is not allowed.');
  24500. }
  24501. }
  24502. $message = sprintf(
  24503. 'Given configuration is deprecated and will be removed in 3.0. Use configuration %s as replacement for %s.',
  24504. HelpCommand::toString($newConfig),
  24505. HelpCommand::toString($configuration)
  24506. );
  24507. if (getenv('PHP_CS_FIXER_FUTURE_MODE')) {
  24508. throw new InvalidFixerConfigurationException($this->getName(), "{$message} This check was performed as `PHP_CS_FIXER_FUTURE_MODE` env var is set.");
  24509. }
  24510. @trigger_error($message, E_USER_DEPRECATED);
  24511. return $newConfig;
  24512. }
  24513. private function fixAlignment(Tokens $tokens, array $toAlign)
  24514. {
  24515. $this->deepestLevel = 0;
  24516. $this->currentLevel = 0;
  24517. foreach ($toAlign as $tokenContent => $alignStrategy) {
  24518. $tokensClone = clone $tokens;
  24519. if ('=>' === $tokenContent) {
  24520. $this->injectAlignmentPlaceholdersForArrow($tokensClone, 0, \count($tokens));
  24521. } else {
  24522. $this->injectAlignmentPlaceholders($tokensClone, 0, \count($tokens), $tokenContent);
  24523. }
  24524. if (self::ALIGN_SINGLE_SPACE === $alignStrategy || self::ALIGN_SINGLE_SPACE_MINIMAL === $alignStrategy) {
  24525. if ('=>' === $tokenContent) {
  24526. for ($index = $tokens->count() - 2; $index > 0; --$index) {
  24527. if ($tokens[$index]->isGivenKind(T_DOUBLE_ARROW)) {
  24528. $this->fixWhiteSpaceBeforeOperator($tokensClone, $index, $alignStrategy);
  24529. }
  24530. }
  24531. } elseif ('=' === $tokenContent) {
  24532. for ($index = $tokens->count() - 2; $index > 0; --$index) {
  24533. if ('=' === $tokens[$index]->getContent() && !$this->isEqualPartOfDeclareStatement($tokens, $index) && $this->tokensAnalyzer->isBinaryOperator($index)) {
  24534. $this->fixWhiteSpaceBeforeOperator($tokensClone, $index, $alignStrategy);
  24535. }
  24536. }
  24537. } else {
  24538. for ($index = $tokens->count() - 2; $index > 0; --$index) {
  24539. $content = $tokens[$index]->getContent();
  24540. if (strtolower($content) === $tokenContent && $this->tokensAnalyzer->isBinaryOperator($index)) {
  24541. $this->fixWhiteSpaceBeforeOperator($tokensClone, $index, $alignStrategy);
  24542. }
  24543. }
  24544. }
  24545. }
  24546. $tokens->setCode($this->replacePlaceholders($tokensClone, $alignStrategy));
  24547. }
  24548. }
  24549. private function injectAlignmentPlaceholders(Tokens $tokens, $startAt, $endAt, $tokenContent)
  24550. {
  24551. for ($index = $startAt; $index < $endAt; ++$index) {
  24552. $token = $tokens[$index];
  24553. $content = $token->getContent();
  24554. if (
  24555. strtolower($content) === $tokenContent
  24556. && $this->tokensAnalyzer->isBinaryOperator($index)
  24557. && ('=' !== $content || !$this->isEqualPartOfDeclareStatement($tokens, $index))
  24558. ) {
  24559. $tokens[$index] = new Token(sprintf(self::ALIGN_PLACEHOLDER, $this->deepestLevel).$content);
  24560. continue;
  24561. }
  24562. if ($token->isGivenKind(T_FUNCTION)) {
  24563. ++$this->deepestLevel;
  24564. continue;
  24565. }
  24566. if ($token->equals('(')) {
  24567. $index = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $index);
  24568. continue;
  24569. }
  24570. if ($token->equals('[')) {
  24571. $index = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_INDEX_SQUARE_BRACE, $index);
  24572. continue;
  24573. }
  24574. if ($token->isGivenKind(CT::T_ARRAY_SQUARE_BRACE_OPEN)) {
  24575. $index = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_ARRAY_SQUARE_BRACE, $index);
  24576. continue;
  24577. }
  24578. }
  24579. }
  24580. private function injectAlignmentPlaceholdersForArrow(Tokens $tokens, $startAt, $endAt)
  24581. {
  24582. for ($index = $startAt; $index < $endAt; ++$index) {
  24583. $token = $tokens[$index];
  24584. if ($token->isGivenKind([T_FOREACH, T_FOR, T_WHILE, T_IF, T_SWITCH])) {
  24585. $index = $tokens->getNextMeaningfulToken($index);
  24586. $index = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $index);
  24587. continue;
  24588. }
  24589. if ($token->isGivenKind(T_ARRAY)) {
  24590. $from = $tokens->getNextMeaningfulToken($index);
  24591. $until = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $from);
  24592. $index = $until;
  24593. $this->injectArrayAlignmentPlaceholders($tokens, $from + 1, $until - 1);
  24594. continue;
  24595. }
  24596. if ($token->isGivenKind(CT::T_ARRAY_SQUARE_BRACE_OPEN)) {
  24597. $from = $index;
  24598. $until = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_ARRAY_SQUARE_BRACE, $from);
  24599. $index = $until;
  24600. $this->injectArrayAlignmentPlaceholders($tokens, $from + 1, $until - 1);
  24601. continue;
  24602. }
  24603. if ($token->isGivenKind(T_DOUBLE_ARROW)) {
  24604. $tokenContent = sprintf(self::ALIGN_PLACEHOLDER, $this->currentLevel).$token->getContent();
  24605. $nextToken = $tokens[$index + 1];
  24606. if (!$nextToken->isWhitespace()) {
  24607. $tokenContent .= ' ';
  24608. } elseif ($nextToken->isWhitespace(" \t")) {
  24609. $tokens[$index + 1] = new Token([T_WHITESPACE, ' ']);
  24610. }
  24611. $tokens[$index] = new Token([T_DOUBLE_ARROW, $tokenContent]);
  24612. continue;
  24613. }
  24614. if ($token->equals(';')) {
  24615. ++$this->deepestLevel;
  24616. ++$this->currentLevel;
  24617. continue;
  24618. }
  24619. if ($token->equals(',')) {
  24620. for ($i = $index; $i < $endAt - 1; ++$i) {
  24621. if (false !== strpos($tokens[$i - 1]->getContent(), "\n")) {
  24622. break;
  24623. }
  24624. if ($tokens[$i + 1]->isGivenKind([T_ARRAY, CT::T_ARRAY_SQUARE_BRACE_OPEN])) {
  24625. $arrayStartIndex = $tokens[$i + 1]->isGivenKind(T_ARRAY)
  24626. ? $tokens->getNextMeaningfulToken($i + 1)
  24627. : $i + 1
  24628. ;
  24629. $blockType = Tokens::detectBlockType($tokens[$arrayStartIndex]);
  24630. $arrayEndIndex = $tokens->findBlockEnd($blockType['type'], $arrayStartIndex);
  24631. if ($tokens->isPartialCodeMultiline($arrayStartIndex, $arrayEndIndex)) {
  24632. break;
  24633. }
  24634. }
  24635. ++$index;
  24636. }
  24637. }
  24638. }
  24639. }
  24640. private function injectArrayAlignmentPlaceholders(Tokens $tokens, $from, $until)
  24641. {
  24642. if ($tokens->isPartialCodeMultiline($from, $until)) {
  24643. ++$this->deepestLevel;
  24644. ++$this->currentLevel;
  24645. $this->injectAlignmentPlaceholdersForArrow($tokens, $from, $until);
  24646. --$this->currentLevel;
  24647. }
  24648. }
  24649. private function fixWhiteSpaceBeforeOperator(Tokens $tokens, $index, $alignStrategy)
  24650. {
  24651. if (!$tokens[$index - 1]->isWhitespace()) {
  24652. $tokens->insertAt($index, new Token([T_WHITESPACE, ' ']));
  24653. return;
  24654. }
  24655. if (self::ALIGN_SINGLE_SPACE_MINIMAL !== $alignStrategy || $tokens[$tokens->getPrevNonWhitespace($index - 1)]->isComment()) {
  24656. return;
  24657. }
  24658. $content = $tokens[$index - 1]->getContent();
  24659. if (' ' !== $content && false === strpos($content, "\n")) {
  24660. $tokens[$index - 1] = new Token([T_WHITESPACE, ' ']);
  24661. }
  24662. }
  24663. private function replacePlaceholders(Tokens $tokens, $alignStrategy)
  24664. {
  24665. $tmpCode = $tokens->generateCode();
  24666. for ($j = 0; $j <= $this->deepestLevel; ++$j) {
  24667. $placeholder = sprintf(self::ALIGN_PLACEHOLDER, $j);
  24668. if (false === strpos($tmpCode, $placeholder)) {
  24669. continue;
  24670. }
  24671. $lines = explode("\n", $tmpCode);
  24672. $groups = [];
  24673. $groupIndex = 0;
  24674. $groups[$groupIndex] = [];
  24675. foreach ($lines as $index => $line) {
  24676. if (substr_count($line, $placeholder) > 0) {
  24677. $groups[$groupIndex][] = $index;
  24678. } else {
  24679. ++$groupIndex;
  24680. $groups[$groupIndex] = [];
  24681. }
  24682. }
  24683. foreach ($groups as $group) {
  24684. if (\count($group) < 1) {
  24685. continue;
  24686. }
  24687. if (self::ALIGN !== $alignStrategy) {
  24688. foreach ($group as $index) {
  24689. $currentPosition = strpos($lines[$index], $placeholder);
  24690. $before = substr($lines[$index], 0, $currentPosition);
  24691. if (self::ALIGN_SINGLE_SPACE === $alignStrategy) {
  24692. if (1 > \strlen($before) || ' ' !== substr($before, -1)) {
  24693. $before .= ' ';
  24694. }
  24695. } elseif (self::ALIGN_SINGLE_SPACE_MINIMAL === $alignStrategy) {
  24696. if (1 !== Preg::match('/^\h+$/', $before)) {
  24697. $before = rtrim($before).' ';
  24698. }
  24699. }
  24700. $lines[$index] = $before.substr($lines[$index], $currentPosition);
  24701. }
  24702. }
  24703. $rightmostSymbol = 0;
  24704. foreach ($group as $index) {
  24705. $rightmostSymbol = max($rightmostSymbol, strpos(utf8_decode($lines[$index]), $placeholder));
  24706. }
  24707. foreach ($group as $index) {
  24708. $line = $lines[$index];
  24709. $currentSymbol = strpos(utf8_decode($line), $placeholder);
  24710. $delta = abs($rightmostSymbol - $currentSymbol);
  24711. if ($delta > 0) {
  24712. $line = str_replace($placeholder, str_repeat(' ', $delta).$placeholder, $line);
  24713. $lines[$index] = $line;
  24714. }
  24715. }
  24716. }
  24717. $tmpCode = str_replace($placeholder, '', implode("\n", $lines));
  24718. }
  24719. return $tmpCode;
  24720. }
  24721. }
  24722. <?php
  24723. namespace PhpCsFixer\Fixer\Operator;
  24724. use PhpCsFixer\AbstractFixer;
  24725. use PhpCsFixer\FixerDefinition\CodeSample;
  24726. use PhpCsFixer\FixerDefinition\FixerDefinition;
  24727. use PhpCsFixer\Tokenizer\Tokens;
  24728. /**
  24729. @gmail
  24730. */
  24731. final class ObjectOperatorWithoutWhitespaceFixer extends AbstractFixer
  24732. {
  24733. public function getDefinition()
  24734. {
  24735. return new FixerDefinition(
  24736. 'There should not be space before or after object `T_OBJECT_OPERATOR` `->`.',
  24737. [new CodeSample("<?php \$a -> b;\n")]
  24738. );
  24739. }
  24740. public function isCandidate(Tokens $tokens)
  24741. {
  24742. return $tokens->isTokenKindFound(T_OBJECT_OPERATOR);
  24743. }
  24744. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  24745. {
  24746. foreach ($tokens as $index => $token) {
  24747. if (!$token->isGivenKind(T_OBJECT_OPERATOR)) {
  24748. continue;
  24749. }
  24750. if ($tokens[$index - 1]->isWhitespace(" \t") && !$tokens[$index - 2]->isComment()) {
  24751. $tokens->clearAt($index - 1);
  24752. }
  24753. if ($tokens[$index + 1]->isWhitespace(" \t") && !$tokens[$index + 2]->isComment()) {
  24754. $tokens->clearAt($index + 1);
  24755. }
  24756. }
  24757. }
  24758. }
  24759. <?php
  24760. namespace PhpCsFixer\Fixer\Operator;
  24761. use PhpCsFixer\AbstractAlignFixerHelper;
  24762. use PhpCsFixer\Tokenizer\CT;
  24763. use PhpCsFixer\Tokenizer\Token;
  24764. use PhpCsFixer\Tokenizer\Tokens;
  24765. /**
  24766. @gmail
  24767. @alt
  24768. */
  24769. final class AlignDoubleArrowFixerHelper extends AbstractAlignFixerHelper
  24770. {
  24771. private $currentLevel = 0;
  24772. public function __construct()
  24773. {
  24774. @trigger_error(
  24775. sprintf(
  24776. 'The "%s" class is deprecated. You should stop using it, as it will be removed in 3.0 version.',
  24777. __CLASS__
  24778. ),
  24779. E_USER_DEPRECATED
  24780. );
  24781. }
  24782. protected function injectAlignmentPlaceholders(Tokens $tokens, $startAt, $endAt)
  24783. {
  24784. for ($index = $startAt; $index < $endAt; ++$index) {
  24785. $token = $tokens[$index];
  24786. if ($token->isGivenKind([T_FOREACH, T_FOR, T_WHILE, T_IF, T_SWITCH])) {
  24787. $index = $tokens->getNextMeaningfulToken($index);
  24788. $index = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $index);
  24789. continue;
  24790. }
  24791. if ($token->isGivenKind(T_ARRAY)) {
  24792. $from = $tokens->getNextMeaningfulToken($index);
  24793. $until = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $from);
  24794. $index = $until;
  24795. $this->injectArrayAlignmentPlaceholders($tokens, $from, $until);
  24796. continue;
  24797. }
  24798. if ($token->isGivenKind(CT::T_ARRAY_SQUARE_BRACE_OPEN)) {
  24799. $prevToken = $tokens[$tokens->getPrevMeaningfulToken($index)];
  24800. if ($prevToken->isGivenKind([T_STRING, T_VARIABLE])) {
  24801. continue;
  24802. }
  24803. $from = $index;
  24804. $until = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_ARRAY_SQUARE_BRACE, $from);
  24805. $index = $until;
  24806. $this->injectArrayAlignmentPlaceholders($tokens, $from + 1, $until - 1);
  24807. continue;
  24808. }
  24809. if ($token->isGivenKind(T_DOUBLE_ARROW)) {
  24810. $tokenContent = sprintf(self::ALIGNABLE_PLACEHOLDER, $this->currentLevel).$token->getContent();
  24811. $nextIndex = $index + 1;
  24812. $nextToken = $tokens[$nextIndex];
  24813. if (!$nextToken->isWhitespace()) {
  24814. $tokenContent .= ' ';
  24815. } elseif ($nextToken->isWhitespace(" \t")) {
  24816. $tokens[$nextIndex] = new Token([T_WHITESPACE, ' ']);
  24817. }
  24818. $tokens[$index] = new Token([T_DOUBLE_ARROW, $tokenContent]);
  24819. continue;
  24820. }
  24821. if ($token->equals(';')) {
  24822. ++$this->deepestLevel;
  24823. ++$this->currentLevel;
  24824. continue;
  24825. }
  24826. if ($token->equals(',')) {
  24827. for ($i = $index; $i < $endAt - 1; ++$i) {
  24828. if (false !== strpos($tokens[$i - 1]->getContent(), "\n")) {
  24829. break;
  24830. }
  24831. if ($tokens[$i + 1]->isGivenKind([T_ARRAY, CT::T_ARRAY_SQUARE_BRACE_OPEN])) {
  24832. $arrayStartIndex = $tokens[$i + 1]->isGivenKind(T_ARRAY)
  24833. ? $tokens->getNextMeaningfulToken($i + 1)
  24834. : $i + 1
  24835. ;
  24836. $blockType = Tokens::detectBlockType($tokens[$arrayStartIndex]);
  24837. $arrayEndIndex = $tokens->findBlockEnd($blockType['type'], $arrayStartIndex);
  24838. if ($tokens->isPartialCodeMultiline($arrayStartIndex, $arrayEndIndex)) {
  24839. break;
  24840. }
  24841. }
  24842. ++$index;
  24843. }
  24844. }
  24845. }
  24846. }
  24847. private function injectArrayAlignmentPlaceholders(Tokens $tokens, $from, $until)
  24848. {
  24849. if ($tokens->isPartialCodeMultiline($from, $until)) {
  24850. ++$this->deepestLevel;
  24851. ++$this->currentLevel;
  24852. $this->injectAlignmentPlaceholders($tokens, $from, $until);
  24853. --$this->currentLevel;
  24854. }
  24855. }
  24856. }
  24857. <?php
  24858. namespace PhpCsFixer\Fixer\Operator;
  24859. use PhpCsFixer\AbstractProxyFixer;
  24860. use PhpCsFixer\Fixer\DeprecatedFixerInterface;
  24861. use PhpCsFixer\FixerDefinition\CodeSample;
  24862. use PhpCsFixer\FixerDefinition\FixerDefinition;
  24863. final class PreIncrementFixer extends AbstractProxyFixer implements DeprecatedFixerInterface
  24864. {
  24865. public function getDefinition()
  24866. {
  24867. return new FixerDefinition(
  24868. 'Pre incrementation/decrementation should be used if possible.',
  24869. [new CodeSample("<?php\n\$a++;\n\$b--;\n")]
  24870. );
  24871. }
  24872. public function getSuccessorsNames()
  24873. {
  24874. return array_keys($this->proxyFixers);
  24875. }
  24876. protected function createProxyFixers()
  24877. {
  24878. $fixer = new IncrementStyleFixer();
  24879. $fixer->configure(['style' => 'pre']);
  24880. return [$fixer];
  24881. }
  24882. }
  24883. <?php
  24884. namespace PhpCsFixer\Fixer\ClassNotation;
  24885. use PhpCsFixer\AbstractFixer;
  24886. use PhpCsFixer\FixerDefinition\CodeSample;
  24887. use PhpCsFixer\FixerDefinition\FixerDefinition;
  24888. use PhpCsFixer\Preg;
  24889. use PhpCsFixer\Tokenizer\Analyzer\NamespacesAnalyzer;
  24890. use PhpCsFixer\Tokenizer\CT;
  24891. use PhpCsFixer\Tokenizer\Token;
  24892. use PhpCsFixer\Tokenizer\Tokens;
  24893. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  24894. final class SelfAccessorFixer extends AbstractFixer
  24895. {
  24896. public function getDefinition()
  24897. {
  24898. return new FixerDefinition(
  24899. 'Inside class or interface element `self` should be preferred to the class name itself.',
  24900. [
  24901. new CodeSample(
  24902. '<?php
  24903. class Sample
  24904. {
  24905. const BAZ = 1;
  24906. const BAR = Sample::BAZ;
  24907. public function getBar()
  24908. {
  24909. return Sample::BAR;
  24910. }
  24911. }
  24912. '
  24913. ),
  24914. ],
  24915. null,
  24916. 'Risky when using dynamic calls like get_called_class() or late static binding.'
  24917. );
  24918. }
  24919. public function isCandidate(Tokens $tokens)
  24920. {
  24921. return $tokens->isAnyTokenKindsFound([T_CLASS, T_INTERFACE]);
  24922. }
  24923. public function isRisky()
  24924. {
  24925. return true;
  24926. }
  24927. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  24928. {
  24929. $tokensAnalyzer = new TokensAnalyzer($tokens);
  24930. foreach ((new NamespacesAnalyzer())->getDeclarations($tokens) as $namespace) {
  24931. for ($index = $namespace->getScopeStartIndex(); $index < $namespace->getScopeEndIndex(); ++$index) {
  24932. if (!$tokens[$index]->isGivenKind([T_CLASS, T_INTERFACE]) || $tokensAnalyzer->isAnonymousClass($index)) {
  24933. continue;
  24934. }
  24935. $nameIndex = $tokens->getNextTokenOfKind($index, [[T_STRING]]);
  24936. $startIndex = $tokens->getNextTokenOfKind($nameIndex, ['{']);
  24937. $endIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $startIndex);
  24938. $name = $tokens[$nameIndex]->getContent();
  24939. $this->replaceNameOccurrences($tokens, $namespace->getFullName(), $name, $startIndex, $endIndex);
  24940. $index = $endIndex;
  24941. }
  24942. }
  24943. }
  24944. private function replaceNameOccurrences(Tokens $tokens, $namespace, $name, $startIndex, $endIndex)
  24945. {
  24946. $tokensAnalyzer = new TokensAnalyzer($tokens);
  24947. $insideMethodSignatureUntil = null;
  24948. for ($i = $startIndex; $i < $endIndex; ++$i) {
  24949. if ($i === $insideMethodSignatureUntil) {
  24950. $insideMethodSignatureUntil = null;
  24951. }
  24952. $token = $tokens[$i];
  24953. if ($token->isGivenKind(T_CLASS) && $tokensAnalyzer->isAnonymousClass($i)) {
  24954. $i = $tokens->getNextTokenOfKind($i, ['{']);
  24955. $i = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $i);
  24956. continue;
  24957. }
  24958. if ($token->isGivenKind(T_FUNCTION)) {
  24959. $i = $tokens->getNextTokenOfKind($i, ['(']);
  24960. $insideMethodSignatureUntil = $tokens->getNextTokenOfKind($i, ['{', ';']);
  24961. continue;
  24962. }
  24963. if (!$token->equals([T_STRING, $name], false)) {
  24964. continue;
  24965. }
  24966. $nextToken = $tokens[$tokens->getNextMeaningfulToken($i)];
  24967. if ($nextToken->isGivenKind(T_NS_SEPARATOR)) {
  24968. continue;
  24969. }
  24970. $classStartIndex = $i;
  24971. $prevToken = $tokens[$tokens->getPrevMeaningfulToken($i)];
  24972. if ($prevToken->isGivenKind(T_NS_SEPARATOR)) {
  24973. $classStartIndex = $this->getClassStart($tokens, $i, $namespace);
  24974. if (null === $classStartIndex) {
  24975. continue;
  24976. }
  24977. $prevToken = $tokens[$tokens->getPrevMeaningfulToken($classStartIndex)];
  24978. }
  24979. if ($prevToken->isGivenKind([T_OBJECT_OPERATOR, T_STRING])) {
  24980. continue;
  24981. }
  24982. if (
  24983. $prevToken->isGivenKind([T_INSTANCEOF, T_NEW])
  24984. || $nextToken->isGivenKind(T_PAAMAYIM_NEKUDOTAYIM)
  24985. || (
  24986. null !== $insideMethodSignatureUntil
  24987. && $i < $insideMethodSignatureUntil
  24988. && $prevToken->equalsAny(['(', ',', [CT::T_TYPE_COLON], [CT::T_NULLABLE_TYPE]])
  24989. )
  24990. ) {
  24991. for ($j = $classStartIndex; $j < $i; ++$j) {
  24992. $tokens->clearTokenAndMergeSurroundingWhitespace($j);
  24993. }
  24994. $tokens[$i] = new Token([T_STRING, 'self']);
  24995. }
  24996. }
  24997. }
  24998. private function getClassStart(Tokens $tokens, $index, $namespace)
  24999. {
  25000. $namespace = ('' !== $namespace ? '\\'.$namespace : '').'\\';
  25001. foreach (array_reverse(Preg::split('/(\\\\)/', $namespace, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE)) as $piece) {
  25002. $index = $tokens->getPrevMeaningfulToken($index);
  25003. if ('\\' === $piece) {
  25004. if (!$tokens[$index]->isGivenKind(T_NS_SEPARATOR)) {
  25005. return null;
  25006. }
  25007. } elseif (!$tokens[$index]->equals([T_STRING, $piece], false)) {
  25008. return null;
  25009. }
  25010. }
  25011. return $index;
  25012. }
  25013. }
  25014. <?php
  25015. namespace PhpCsFixer\Fixer\ClassNotation;
  25016. use PhpCsFixer\AbstractFixer;
  25017. use PhpCsFixer\FixerDefinition\CodeSample;
  25018. use PhpCsFixer\FixerDefinition\FixerDefinition;
  25019. use PhpCsFixer\Tokenizer\Tokens;
  25020. final class NoUnneededFinalMethodFixer extends AbstractFixer
  25021. {
  25022. public function getDefinition()
  25023. {
  25024. return new FixerDefinition(
  25025. 'A `final` class must not have `final` methods and `private` methods must not be `final`.',
  25026. [
  25027. new CodeSample(
  25028. '<?php
  25029. final class Foo
  25030. {
  25031. final public function foo1() {}
  25032. final protected function bar() {}
  25033. final private function baz() {}
  25034. }
  25035. class Bar
  25036. {
  25037. final private function bar1() {}
  25038. }
  25039. '
  25040. ),
  25041. ],
  25042. null,
  25043. 'Risky when child class overrides a `private` method.'
  25044. );
  25045. }
  25046. public function isCandidate(Tokens $tokens)
  25047. {
  25048. return $tokens->isAllTokenKindsFound([T_CLASS, T_FINAL]);
  25049. }
  25050. public function isRisky()
  25051. {
  25052. return true;
  25053. }
  25054. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  25055. {
  25056. $tokensCount = \count($tokens);
  25057. for ($index = 0; $index < $tokensCount; ++$index) {
  25058. if (!$tokens[$index]->isGivenKind(T_CLASS)) {
  25059. continue;
  25060. }
  25061. $classOpen = $tokens->getNextTokenOfKind($index, ['{']);
  25062. $prevToken = $tokens[$tokens->getPrevMeaningfulToken($index)];
  25063. $classIsFinal = $prevToken->isGivenKind(T_FINAL);
  25064. $this->fixClass($tokens, $classOpen, $classIsFinal);
  25065. }
  25066. }
  25067. private function fixClass(Tokens $tokens, $classOpenIndex, $classIsFinal)
  25068. {
  25069. $tokensCount = \count($tokens);
  25070. for ($index = $classOpenIndex + 1; $index < $tokensCount; ++$index) {
  25071. if ($tokens[$index]->equals('}')) {
  25072. return;
  25073. }
  25074. if ($tokens[$index]->equals('{')) {
  25075. $index = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $index);
  25076. continue;
  25077. }
  25078. if (!$tokens[$index]->isGivenKind(T_FINAL)) {
  25079. continue;
  25080. }
  25081. if (!$classIsFinal && !$this->isPrivateMethod($tokens, $index, $classOpenIndex)) {
  25082. continue;
  25083. }
  25084. $tokens->clearAt($index);
  25085. $nextTokenIndex = $index + 1;
  25086. if ($tokens[$nextTokenIndex]->isWhitespace()) {
  25087. $tokens->clearAt($nextTokenIndex);
  25088. }
  25089. }
  25090. }
  25091. private function isPrivateMethod(Tokens $tokens, $index, $classOpenIndex)
  25092. {
  25093. $index = max($classOpenIndex + 1, $tokens->getPrevTokenOfKind($index, [';', '{', '}']));
  25094. while (!$tokens[$index]->isGivenKind(T_FUNCTION)) {
  25095. if ($tokens[$index]->isGivenKind(T_PRIVATE)) {
  25096. return true;
  25097. }
  25098. ++$index;
  25099. }
  25100. return false;
  25101. }
  25102. }
  25103. <?php
  25104. namespace PhpCsFixer\Fixer\ClassNotation;
  25105. use PhpCsFixer\AbstractFixer;
  25106. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  25107. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  25108. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  25109. use PhpCsFixer\FixerDefinition\CodeSample;
  25110. use PhpCsFixer\FixerDefinition\FixerDefinition;
  25111. use PhpCsFixer\Tokenizer\Token;
  25112. use PhpCsFixer\Tokenizer\Tokens;
  25113. final class OrderedInterfacesFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface
  25114. {
  25115. const OPTION_DIRECTION = 'direction';
  25116. const OPTION_ORDER = 'order';
  25117. const DIRECTION_ASCEND = 'ascend';
  25118. const DIRECTION_DESCEND = 'descend';
  25119. const ORDER_ALPHA = 'alpha';
  25120. const ORDER_LENGTH = 'length';
  25121. private $supportedDirectionOptions = [
  25122. self::DIRECTION_ASCEND,
  25123. self::DIRECTION_DESCEND,
  25124. ];
  25125. private $supportedOrderOptions = [
  25126. self::ORDER_ALPHA,
  25127. self::ORDER_LENGTH,
  25128. ];
  25129. public function getDefinition()
  25130. {
  25131. return new FixerDefinition(
  25132. 'Orders the interfaces in an `implements` or `interface extends` clause.',
  25133. [
  25134. new CodeSample(
  25135. "<?php\n\nfinal class ExampleA implements Gamma, Alpha, Beta {}\n\ninterface ExampleB extends Gamma, Alpha, Beta {}\n"
  25136. ),
  25137. new CodeSample(
  25138. "<?php\n\nfinal class ExampleA implements Gamma, Alpha, Beta {}\n\ninterface ExampleB extends Gamma, Alpha, Beta {}\n",
  25139. [self::OPTION_DIRECTION => self::DIRECTION_DESCEND]
  25140. ),
  25141. new CodeSample(
  25142. "<?php\n\nfinal class ExampleA implements MuchLonger, Short, Longer {}\n\ninterface ExampleB extends MuchLonger, Short, Longer {}\n",
  25143. [self::OPTION_ORDER => self::ORDER_LENGTH]
  25144. ),
  25145. new CodeSample(
  25146. "<?php\n\nfinal class ExampleA implements MuchLonger, Short, Longer {}\n\ninterface ExampleB extends MuchLonger, Short, Longer {}\n",
  25147. [
  25148. self::OPTION_ORDER => self::ORDER_LENGTH,
  25149. self::OPTION_DIRECTION => self::DIRECTION_DESCEND,
  25150. ]
  25151. ),
  25152. ],
  25153. null,
  25154. "Risky for `implements` when specifying both an interface and its parent interface, because PHP doesn't break on `parent, child` but does on `child, parent`."
  25155. );
  25156. }
  25157. public function isCandidate(Tokens $tokens)
  25158. {
  25159. return $tokens->isTokenKindFound(T_IMPLEMENTS)
  25160. || $tokens->isAllTokenKindsFound([T_INTERFACE, T_EXTENDS]);
  25161. }
  25162. public function isRisky()
  25163. {
  25164. return true;
  25165. }
  25166. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  25167. {
  25168. foreach ($tokens as $index => $token) {
  25169. if (!$token->isGivenKind(T_IMPLEMENTS)) {
  25170. if (!$token->isGivenKind(T_EXTENDS)) {
  25171. continue;
  25172. }
  25173. $nameTokenIndex = $tokens->getPrevMeaningfulToken($index);
  25174. $interfaceTokenIndex = $tokens->getPrevMeaningfulToken($nameTokenIndex);
  25175. $interfaceToken = $tokens[$interfaceTokenIndex];
  25176. if (!$interfaceToken->isGivenKind(T_INTERFACE)) {
  25177. continue;
  25178. }
  25179. }
  25180. $interfaceIndex = 0;
  25181. $interfaces = [['tokens' => []]];
  25182. $implementsStart = $index + 1;
  25183. $classStart = $tokens->getNextTokenOfKind($implementsStart, ['{']);
  25184. $implementsEnd = $tokens->getPrevNonWhitespace($classStart);
  25185. for ($i = $implementsStart; $i <= $implementsEnd; ++$i) {
  25186. if ($tokens[$i]->equals(',')) {
  25187. ++$interfaceIndex;
  25188. $interfaces[$interfaceIndex] = ['tokens' => []];
  25189. continue;
  25190. }
  25191. $interfaces[$interfaceIndex]['tokens'][] = $tokens[$i];
  25192. }
  25193. if (1 === \count($interfaces)) {
  25194. continue;
  25195. }
  25196. foreach ($interfaces as $interfaceIndex => $interface) {
  25197. $interfaceTokens = Tokens::fromArray($interface['tokens'], false);
  25198. $normalized = '';
  25199. $actualInterfaceIndex = $interfaceTokens->getNextMeaningfulToken(-1);
  25200. while ($interfaceTokens->offsetExists($actualInterfaceIndex)) {
  25201. $token = $interfaceTokens[$actualInterfaceIndex];
  25202. if (null === $token || $token->isComment() || $token->isWhitespace()) {
  25203. break;
  25204. }
  25205. $normalized .= str_replace('\\', ' ', $token->getContent());
  25206. ++$actualInterfaceIndex;
  25207. }
  25208. $interfaces[$interfaceIndex]['normalized'] = $normalized;
  25209. $interfaces[$interfaceIndex]['originalIndex'] = $interfaceIndex;
  25210. }
  25211. usort($interfaces, function (array $first, array $second) {
  25212. $score = self::ORDER_LENGTH === $this->configuration[self::OPTION_ORDER]
  25213. ? \strlen($first['normalized']) - \strlen($second['normalized'])
  25214. : strcasecmp($first['normalized'], $second['normalized']);
  25215. if (self::DIRECTION_DESCEND === $this->configuration[self::OPTION_DIRECTION]) {
  25216. $score *= -1;
  25217. }
  25218. return $score;
  25219. });
  25220. $changed = false;
  25221. foreach ($interfaces as $interfaceIndex => $interface) {
  25222. if ($interface['originalIndex'] !== $interfaceIndex) {
  25223. $changed = true;
  25224. break;
  25225. }
  25226. }
  25227. if (!$changed) {
  25228. continue;
  25229. }
  25230. $newTokens = array_shift($interfaces)['tokens'];
  25231. foreach ($interfaces as $interface) {
  25232. array_push($newTokens, new Token(','), ...$interface['tokens']);
  25233. }
  25234. $tokens->overrideRange($implementsStart, $implementsEnd, $newTokens);
  25235. }
  25236. }
  25237. protected function createConfigurationDefinition()
  25238. {
  25239. return new FixerConfigurationResolver([
  25240. (new FixerOptionBuilder(self::OPTION_ORDER, 'How the interfaces should be ordered'))
  25241. ->setAllowedValues($this->supportedOrderOptions)
  25242. ->setDefault(self::ORDER_ALPHA)
  25243. ->getOption(),
  25244. (new FixerOptionBuilder(self::OPTION_DIRECTION, 'Which direction the interfaces should be ordered'))
  25245. ->setAllowedValues($this->supportedDirectionOptions)
  25246. ->setDefault(self::DIRECTION_ASCEND)
  25247. ->getOption(),
  25248. ]);
  25249. }
  25250. }
  25251. <?php
  25252. namespace PhpCsFixer\Fixer\ClassNotation;
  25253. use PhpCsFixer\AbstractFixer;
  25254. use PhpCsFixer\FixerDefinition\CodeSample;
  25255. use PhpCsFixer\FixerDefinition\FixerDefinition;
  25256. use PhpCsFixer\Tokenizer\CT;
  25257. use PhpCsFixer\Tokenizer\Token;
  25258. use PhpCsFixer\Tokenizer\Tokens;
  25259. final class ProtectedToPrivateFixer extends AbstractFixer
  25260. {
  25261. public function getDefinition()
  25262. {
  25263. return new FixerDefinition(
  25264. 'Converts `protected` variables and methods to `private` where possible.',
  25265. [
  25266. new CodeSample(
  25267. '<?php
  25268. final class Sample
  25269. {
  25270. protected $a;
  25271. protected function test()
  25272. {
  25273. }
  25274. }
  25275. '
  25276. ),
  25277. ]
  25278. );
  25279. }
  25280. public function getPriority()
  25281. {
  25282. return 66;
  25283. }
  25284. public function isCandidate(Tokens $tokens)
  25285. {
  25286. return $tokens->isAllTokenKindsFound([T_CLASS, T_FINAL, T_PROTECTED]);
  25287. }
  25288. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  25289. {
  25290. $end = \count($tokens) - 3;
  25291. for ($index = 0; $index < $end; ++$index) {
  25292. if (!$tokens[$index]->isGivenKind(T_CLASS)) {
  25293. continue;
  25294. }
  25295. $classOpen = $tokens->getNextTokenOfKind($index, ['{']);
  25296. $classClose = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $classOpen);
  25297. if (!$this->skipClass($tokens, $index, $classOpen, $classClose)) {
  25298. $this->fixClass($tokens, $classOpen, $classClose);
  25299. }
  25300. $index = $classClose;
  25301. }
  25302. }
  25303. private function fixClass(Tokens $tokens, $classOpenIndex, $classCloseIndex)
  25304. {
  25305. for ($index = $classOpenIndex + 1; $index < $classCloseIndex; ++$index) {
  25306. if ($tokens[$index]->equals('{')) {
  25307. $index = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $index);
  25308. continue;
  25309. }
  25310. if (!$tokens[$index]->isGivenKind(T_PROTECTED)) {
  25311. continue;
  25312. }
  25313. $tokens[$index] = new Token([T_PRIVATE, 'private']);
  25314. }
  25315. }
  25316. private function skipClass(Tokens $tokens, $classIndex, $classOpenIndex, $classCloseIndex)
  25317. {
  25318. $prevToken = $tokens[$tokens->getPrevMeaningfulToken($classIndex)];
  25319. if (!$prevToken->isGivenKind(T_FINAL)) {
  25320. return true;
  25321. }
  25322. for ($index = $classIndex; $index < $classOpenIndex; ++$index) {
  25323. if ($tokens[$index]->isGivenKind(T_EXTENDS)) {
  25324. return true;
  25325. }
  25326. }
  25327. $useIndex = $tokens->getNextTokenOfKind($classIndex, [[CT::T_USE_TRAIT]]);
  25328. return $useIndex && $useIndex < $classCloseIndex;
  25329. }
  25330. }
  25331. <?php
  25332. namespace PhpCsFixer\Fixer\ClassNotation;
  25333. use PhpCsFixer\AbstractFixer;
  25334. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  25335. use PhpCsFixer\FixerConfiguration\AllowedValueSubset;
  25336. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverRootless;
  25337. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  25338. use PhpCsFixer\FixerDefinition\CodeSample;
  25339. use PhpCsFixer\FixerDefinition\FixerDefinition;
  25340. use PhpCsFixer\FixerDefinition\VersionSpecification;
  25341. use PhpCsFixer\FixerDefinition\VersionSpecificCodeSample;
  25342. use PhpCsFixer\Tokenizer\CT;
  25343. use PhpCsFixer\Tokenizer\Token;
  25344. use PhpCsFixer\Tokenizer\Tokens;
  25345. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  25346. final class VisibilityRequiredFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface
  25347. {
  25348. public function getDefinition()
  25349. {
  25350. return new FixerDefinition(
  25351. 'Visibility MUST be declared on all properties and methods; `abstract` and `final` MUST be declared before the visibility; `static` MUST be declared after the visibility.',
  25352. [
  25353. new CodeSample(
  25354. '<?php
  25355. class Sample
  25356. {
  25357. var $a;
  25358. static protected $var_foo2;
  25359. function A()
  25360. {
  25361. }
  25362. }
  25363. '
  25364. ),
  25365. new VersionSpecificCodeSample(
  25366. '<?php
  25367. class Sample
  25368. {
  25369. const SAMPLE = 1;
  25370. }
  25371. ',
  25372. new VersionSpecification(70100),
  25373. ['elements' => ['const']]
  25374. ),
  25375. ]
  25376. );
  25377. }
  25378. public function isCandidate(Tokens $tokens)
  25379. {
  25380. return $tokens->isAnyTokenKindsFound(Token::getClassyTokenKinds());
  25381. }
  25382. protected function createConfigurationDefinition()
  25383. {
  25384. return new FixerConfigurationResolverRootless('elements', [
  25385. (new FixerOptionBuilder('elements', 'The structural elements to fix (PHP >= 7.1 required for `const`).'))
  25386. ->setAllowedTypes(['array'])
  25387. ->setAllowedValues([new AllowedValueSubset(['property', 'method', 'const'])])
  25388. ->setDefault(['property', 'method'])
  25389. ->getOption(),
  25390. ], $this->getName());
  25391. }
  25392. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  25393. {
  25394. $tokensAnalyzer = new TokensAnalyzer($tokens);
  25395. $elements = $tokensAnalyzer->getClassyElements();
  25396. $propertyTypeDeclarationKinds = [T_STRING, T_NS_SEPARATOR, CT::T_NULLABLE_TYPE, CT::T_ARRAY_TYPEHINT];
  25397. foreach (array_reverse($elements, true) as $index => $element) {
  25398. if (!\in_array($element['type'], $this->configuration['elements'], true)) {
  25399. continue;
  25400. }
  25401. if (\PHP_VERSION_ID < 70100 && 'const' === $element['type']) {
  25402. continue;
  25403. }
  25404. $abstractFinalIndex = null;
  25405. $visibilityIndex = null;
  25406. $staticIndex = null;
  25407. $typeIndex = null;
  25408. $prevIndex = $tokens->getPrevMeaningfulToken($index);
  25409. $expectedKinds = [T_ABSTRACT, T_FINAL, T_PRIVATE, T_PROTECTED, T_PUBLIC, T_STATIC, T_VAR];
  25410. if ('property' === $element['type']) {
  25411. $expectedKinds = array_merge($expectedKinds, $propertyTypeDeclarationKinds);
  25412. }
  25413. while ($tokens[$prevIndex]->isGivenKind($expectedKinds)) {
  25414. if ($tokens[$prevIndex]->isGivenKind([T_ABSTRACT, T_FINAL])) {
  25415. $abstractFinalIndex = $prevIndex;
  25416. } elseif ($tokens[$prevIndex]->isGivenKind(T_STATIC)) {
  25417. $staticIndex = $prevIndex;
  25418. } elseif ($tokens[$prevIndex]->isGivenKind($propertyTypeDeclarationKinds)) {
  25419. $typeIndex = $prevIndex;
  25420. } else {
  25421. $visibilityIndex = $prevIndex;
  25422. }
  25423. $prevIndex = $tokens->getPrevMeaningfulToken($prevIndex);
  25424. }
  25425. if (null !== $typeIndex) {
  25426. $index = $typeIndex;
  25427. }
  25428. if ($tokens[$prevIndex]->equals(',')) {
  25429. continue;
  25430. }
  25431. if (null !== $staticIndex) {
  25432. if ($this->isKeywordPlacedProperly($tokens, $staticIndex, $index)) {
  25433. $index = $staticIndex;
  25434. } else {
  25435. $this->moveTokenAndEnsureSingleSpaceFollows($tokens, $staticIndex, $index);
  25436. }
  25437. }
  25438. if (null === $visibilityIndex) {
  25439. $tokens->insertAt($index, [new Token([T_PUBLIC, 'public']), new Token([T_WHITESPACE, ' '])]);
  25440. } else {
  25441. if ($tokens[$visibilityIndex]->isGivenKind(T_VAR)) {
  25442. $tokens[$visibilityIndex] = new Token([T_PUBLIC, 'public']);
  25443. }
  25444. if ($this->isKeywordPlacedProperly($tokens, $visibilityIndex, $index)) {
  25445. $index = $visibilityIndex;
  25446. } else {
  25447. $this->moveTokenAndEnsureSingleSpaceFollows($tokens, $visibilityIndex, $index);
  25448. }
  25449. }
  25450. if (null === $abstractFinalIndex) {
  25451. continue;
  25452. }
  25453. if ($this->isKeywordPlacedProperly($tokens, $abstractFinalIndex, $index)) {
  25454. continue;
  25455. }
  25456. $this->moveTokenAndEnsureSingleSpaceFollows($tokens, $abstractFinalIndex, $index);
  25457. }
  25458. }
  25459. private function isKeywordPlacedProperly(Tokens $tokens, $keywordIndex, $comparedIndex)
  25460. {
  25461. return $keywordIndex + 2 === $comparedIndex && ' ' === $tokens[$keywordIndex + 1]->getContent();
  25462. }
  25463. private function moveTokenAndEnsureSingleSpaceFollows(Tokens $tokens, $fromIndex, $toIndex)
  25464. {
  25465. $tokens->insertAt($toIndex, [$tokens[$fromIndex], new Token([T_WHITESPACE, ' '])]);
  25466. $tokens->clearAt($fromIndex);
  25467. if ($tokens[$fromIndex + 1]->isWhitespace()) {
  25468. $tokens->clearAt($fromIndex + 1);
  25469. }
  25470. }
  25471. }
  25472. <?php
  25473. namespace PhpCsFixer\Fixer\ClassNotation;
  25474. use PhpCsFixer\AbstractProxyFixer;
  25475. use PhpCsFixer\Fixer\DeprecatedFixerInterface;
  25476. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  25477. use PhpCsFixer\FixerDefinition\CodeSample;
  25478. use PhpCsFixer\FixerDefinition\FixerDefinition;
  25479. final class MethodSeparationFixer extends AbstractProxyFixer implements DeprecatedFixerInterface, WhitespacesAwareFixerInterface
  25480. {
  25481. public function getDefinition()
  25482. {
  25483. return new FixerDefinition(
  25484. 'Methods must be separated with one blank line.',
  25485. [
  25486. new CodeSample(
  25487. '<?php
  25488. final class Sample
  25489. {
  25490. protected function foo()
  25491. {
  25492. }
  25493. protected function bar()
  25494. {
  25495. }
  25496. }
  25497. '
  25498. ),
  25499. ]
  25500. );
  25501. }
  25502. public function getPriority()
  25503. {
  25504. return parent::getPriority();
  25505. }
  25506. public function getSuccessorsNames()
  25507. {
  25508. return array_keys($this->proxyFixers);
  25509. }
  25510. protected function createProxyFixers()
  25511. {
  25512. $fixer = new ClassAttributesSeparationFixer();
  25513. $fixer->configure(['elements' => ['method']]);
  25514. return [$fixer];
  25515. }
  25516. }
  25517. <?php
  25518. namespace PhpCsFixer\Fixer\ClassNotation;
  25519. use PhpCsFixer\AbstractFixer;
  25520. use PhpCsFixer\FixerDefinition\CodeSample;
  25521. use PhpCsFixer\FixerDefinition\FixerDefinition;
  25522. use PhpCsFixer\FixerDefinition\VersionSpecification;
  25523. use PhpCsFixer\FixerDefinition\VersionSpecificCodeSample;
  25524. use PhpCsFixer\Tokenizer\Token;
  25525. use PhpCsFixer\Tokenizer\Tokens;
  25526. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  25527. final class SelfStaticAccessorFixer extends AbstractFixer
  25528. {
  25529. private $tokensAnalyzer;
  25530. public function getDefinition()
  25531. {
  25532. return new FixerDefinition(
  25533. 'Inside a `final` class or anonymous class `self` should be preferred to `static`.',
  25534. [
  25535. new CodeSample(
  25536. '<?php
  25537. final class Sample
  25538. {
  25539. private static $A = 1;
  25540. public function getBar()
  25541. {
  25542. return static::class.static::test().static::$A;
  25543. }
  25544. private static function test()
  25545. {
  25546. return \'test\';
  25547. }
  25548. }
  25549. '
  25550. ),
  25551. new CodeSample(
  25552. '<?php
  25553. final class Foo
  25554. {
  25555. public function bar()
  25556. {
  25557. return new static();
  25558. }
  25559. }
  25560. '
  25561. ),
  25562. new CodeSample(
  25563. '<?php
  25564. final class Foo
  25565. {
  25566. public function isBar()
  25567. {
  25568. return $foo instanceof static;
  25569. }
  25570. }
  25571. '
  25572. ),
  25573. new VersionSpecificCodeSample(
  25574. '<?php
  25575. $a = new class() {
  25576. public function getBar()
  25577. {
  25578. return static::class;
  25579. }
  25580. };
  25581. ',
  25582. new VersionSpecification(70000)
  25583. ),
  25584. ]
  25585. );
  25586. }
  25587. public function isCandidate(Tokens $tokens)
  25588. {
  25589. return $tokens->isAllTokenKindsFound([T_CLASS, T_STATIC]) && $tokens->isAnyTokenKindsFound([T_DOUBLE_COLON, T_NEW, T_INSTANCEOF]);
  25590. }
  25591. public function getPriority()
  25592. {
  25593. return -10;
  25594. }
  25595. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  25596. {
  25597. $this->tokensAnalyzer = $tokensAnalyzer = new TokensAnalyzer($tokens);
  25598. $classIndex = $tokens->getNextTokenOfKind(0, [[T_CLASS]]);
  25599. while (null !== $classIndex) {
  25600. if (
  25601. $tokens[$tokens->getPrevMeaningfulToken($classIndex)]->isGivenKind(T_FINAL)
  25602. || $tokensAnalyzer->isAnonymousClass($classIndex)
  25603. ) {
  25604. $classIndex = $this->fixClass($tokens, $classIndex);
  25605. }
  25606. $classIndex = $tokens->getNextTokenOfKind($classIndex, [[T_CLASS]]);
  25607. }
  25608. }
  25609. private function fixClass(Tokens $tokens, $index)
  25610. {
  25611. $index = $tokens->getNextTokenOfKind($index, ['{']);
  25612. $classOpenCount = 1;
  25613. while ($classOpenCount > 0) {
  25614. ++$index;
  25615. if ($tokens[$index]->equals('{')) {
  25616. ++$classOpenCount;
  25617. continue;
  25618. }
  25619. if ($tokens[$index]->equals('}')) {
  25620. --$classOpenCount;
  25621. continue;
  25622. }
  25623. if ($tokens[$index]->isGivenKind(T_FUNCTION)) {
  25624. if ($this->tokensAnalyzer->isLambda($index)) {
  25625. $index = $tokens->getNextTokenOfKind($index, ['{']);
  25626. $openCount = 1;
  25627. do {
  25628. $index = $tokens->getNextTokenOfKind($index, ['}', '{', [T_CLASS]]);
  25629. if ($tokens[$index]->equals('}')) {
  25630. --$openCount;
  25631. } elseif ($tokens[$index]->equals('{')) {
  25632. ++$openCount;
  25633. } else {
  25634. $index = $this->fixClass($tokens, $index);
  25635. }
  25636. } while ($openCount > 0);
  25637. }
  25638. continue;
  25639. }
  25640. if ($tokens[$index]->isGivenKind([T_NEW, T_INSTANCEOF])) {
  25641. $index = $tokens->getNextMeaningfulToken($index);
  25642. if ($tokens[$index]->isGivenKind(T_STATIC)) {
  25643. $tokens[$index] = new Token([T_STRING, 'self']);
  25644. }
  25645. continue;
  25646. }
  25647. if (!$tokens[$index]->isGivenKind(T_STATIC)) {
  25648. continue;
  25649. }
  25650. $staticIndex = $index;
  25651. $index = $tokens->getNextMeaningfulToken($index);
  25652. if (!$tokens[$index]->isGivenKind(T_DOUBLE_COLON)) {
  25653. continue;
  25654. }
  25655. $tokens[$staticIndex] = new Token([T_STRING, 'self']);
  25656. }
  25657. return $index;
  25658. }
  25659. }
  25660. <?php
  25661. namespace PhpCsFixer\Fixer\ClassNotation;
  25662. use PhpCsFixer\AbstractFixer;
  25663. use PhpCsFixer\FixerDefinition\CodeSample;
  25664. use PhpCsFixer\FixerDefinition\FixerDefinition;
  25665. use PhpCsFixer\Preg;
  25666. use PhpCsFixer\Tokenizer\CT;
  25667. use PhpCsFixer\Tokenizer\Token;
  25668. use PhpCsFixer\Tokenizer\Tokens;
  25669. final class SingleTraitInsertPerStatementFixer extends AbstractFixer
  25670. {
  25671. public function getDefinition()
  25672. {
  25673. return new FixerDefinition(
  25674. 'Each trait `use` must be done as single statement.',
  25675. [
  25676. new CodeSample(
  25677. '<?php
  25678. final class Example
  25679. {
  25680. use Foo, Bar;
  25681. }
  25682. '
  25683. ),
  25684. ]
  25685. );
  25686. }
  25687. public function getPriority()
  25688. {
  25689. return 1;
  25690. }
  25691. public function isCandidate(Tokens $tokens)
  25692. {
  25693. return $tokens->isTokenKindFound(CT::T_USE_TRAIT);
  25694. }
  25695. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  25696. {
  25697. for ($index = \count($tokens) - 1; 1 < $index; --$index) {
  25698. if ($tokens[$index]->isGivenKind(CT::T_USE_TRAIT)) {
  25699. $candidates = $this->getCandidates($tokens, $index);
  25700. if (\count($candidates) > 0) {
  25701. $this->fixTraitUse($tokens, $index, $candidates);
  25702. }
  25703. }
  25704. }
  25705. }
  25706. private function fixTraitUse(Tokens $tokens, $useTraitIndex, array $candidates)
  25707. {
  25708. foreach ($candidates as $commaIndex) {
  25709. $inserts = [
  25710. new Token([CT::T_USE_TRAIT, 'use']),
  25711. new Token([T_WHITESPACE, ' ']),
  25712. ];
  25713. $nextImportStartIndex = $tokens->getNextMeaningfulToken($commaIndex);
  25714. if ($tokens[$nextImportStartIndex - 1]->isWhitespace()) {
  25715. if (1 === Preg::match('/\R/', $tokens[$nextImportStartIndex - 1]->getContent())) {
  25716. array_unshift($inserts, clone $tokens[$useTraitIndex - 1]);
  25717. }
  25718. $tokens->clearAt($nextImportStartIndex - 1);
  25719. }
  25720. $tokens[$commaIndex] = new Token(';');
  25721. $tokens->insertAt($nextImportStartIndex, $inserts);
  25722. }
  25723. }
  25724. private function getCandidates(Tokens $tokens, $index)
  25725. {
  25726. $indexes = [];
  25727. $index = $tokens->getNextTokenOfKind($index, [',', ';', '{']);
  25728. while (!$tokens[$index]->equals(';')) {
  25729. if ($tokens[$index]->equals('{')) {
  25730. return [];
  25731. }
  25732. $indexes[] = $index;
  25733. $index = $tokens->getNextTokenOfKind($index, [',', ';', '{']);
  25734. }
  25735. return array_reverse($indexes);
  25736. }
  25737. }
  25738. <?php
  25739. namespace PhpCsFixer\Fixer\ClassNotation;
  25740. use PhpCsFixer\AbstractFixer;
  25741. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  25742. use PhpCsFixer\FixerConfiguration\AllowedValueSubset;
  25743. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverRootless;
  25744. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  25745. use PhpCsFixer\FixerDefinition\CodeSample;
  25746. use PhpCsFixer\FixerDefinition\FixerDefinition;
  25747. use PhpCsFixer\Tokenizer\CT;
  25748. use PhpCsFixer\Tokenizer\Token;
  25749. use PhpCsFixer\Tokenizer\Tokens;
  25750. final class OrderedClassElementsFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface
  25751. {
  25752. const SORT_ALPHA = 'alpha';
  25753. const SORT_NONE = 'none';
  25754. private static $typeHierarchy = [
  25755. 'use_trait' => null,
  25756. 'public' => null,
  25757. 'protected' => null,
  25758. 'private' => null,
  25759. 'constant' => null,
  25760. 'constant_public' => ['constant', 'public'],
  25761. 'constant_protected' => ['constant', 'protected'],
  25762. 'constant_private' => ['constant', 'private'],
  25763. 'property' => null,
  25764. 'property_static' => ['property'],
  25765. 'property_public' => ['property', 'public'],
  25766. 'property_protected' => ['property', 'protected'],
  25767. 'property_private' => ['property', 'private'],
  25768. 'property_public_static' => ['property_static', 'property_public'],
  25769. 'property_protected_static' => ['property_static', 'property_protected'],
  25770. 'property_private_static' => ['property_static', 'property_private'],
  25771. 'method' => null,
  25772. 'method_static' => ['method'],
  25773. 'method_public' => ['method', 'public'],
  25774. 'method_protected' => ['method', 'protected'],
  25775. 'method_private' => ['method', 'private'],
  25776. 'method_public_static' => ['method_static', 'method_public'],
  25777. 'method_protected_static' => ['method_static', 'method_protected'],
  25778. 'method_private_static' => ['method_static', 'method_private'],
  25779. ];
  25780. private static $specialTypes = [
  25781. 'construct' => null,
  25782. 'destruct' => null,
  25783. 'magic' => null,
  25784. 'phpunit' => null,
  25785. ];
  25786. private $supportedSortAlgorithms = [
  25787. self::SORT_NONE,
  25788. self::SORT_ALPHA,
  25789. ];
  25790. private $typePosition;
  25791. public function configure(array $configuration = null)
  25792. {
  25793. parent::configure($configuration);
  25794. $this->typePosition = [];
  25795. $pos = 0;
  25796. foreach ($this->configuration['order'] as $type) {
  25797. $this->typePosition[$type] = $pos++;
  25798. }
  25799. foreach (self::$typeHierarchy as $type => $parents) {
  25800. if (isset($this->typePosition[$type])) {
  25801. continue;
  25802. }
  25803. if (!$parents) {
  25804. $this->typePosition[$type] = null;
  25805. continue;
  25806. }
  25807. foreach ($parents as $parent) {
  25808. if (isset($this->typePosition[$parent])) {
  25809. $this->typePosition[$type] = $this->typePosition[$parent];
  25810. continue 2;
  25811. }
  25812. }
  25813. $this->typePosition[$type] = null;
  25814. }
  25815. $lastPosition = \count($this->configuration['order']);
  25816. foreach ($this->typePosition as &$pos) {
  25817. if (null === $pos) {
  25818. $pos = $lastPosition;
  25819. }
  25820. $pos *= 10;
  25821. }
  25822. }
  25823. public function isCandidate(Tokens $tokens)
  25824. {
  25825. return $tokens->isAnyTokenKindsFound(Token::getClassyTokenKinds());
  25826. }
  25827. public function getDefinition()
  25828. {
  25829. return new FixerDefinition(
  25830. 'Orders the elements of classes/interfaces/traits.',
  25831. [
  25832. new CodeSample(
  25833. '<?php
  25834. final class Example
  25835. {
  25836. use BarTrait;
  25837. use BazTrait;
  25838. const C1 = 1;
  25839. const C2 = 2;
  25840. protected static $protStatProp;
  25841. public static $pubStatProp1;
  25842. public $pubProp1;
  25843. protected $protProp;
  25844. var $pubProp2;
  25845. private static $privStatProp;
  25846. private $privProp;
  25847. public static $pubStatProp2;
  25848. public $pubProp3;
  25849. protected function __construct() {}
  25850. private static function privStatFunc() {}
  25851. public function pubFunc1() {}
  25852. public function __toString() {}
  25853. protected function protFunc() {}
  25854. function pubFunc2() {}
  25855. public static function pubStatFunc1() {}
  25856. public function pubFunc3() {}
  25857. static function pubStatFunc2() {}
  25858. private function privFunc() {}
  25859. public static function pubStatFunc3() {}
  25860. protected static function protStatFunc() {}
  25861. public function __destruct() {}
  25862. }
  25863. '
  25864. ),
  25865. new CodeSample(
  25866. '<?php
  25867. class Example
  25868. {
  25869. public function A(){}
  25870. private function B(){}
  25871. }
  25872. ',
  25873. ['order' => ['method_private', 'method_public']]
  25874. ),
  25875. new CodeSample(
  25876. '<?php
  25877. class Example
  25878. {
  25879. public function D(){}
  25880. public function B(){}
  25881. public function A(){}
  25882. public function C(){}
  25883. }
  25884. ',
  25885. ['order' => ['method_public'], 'sortAlgorithm' => 'alpha']
  25886. ),
  25887. ]
  25888. );
  25889. }
  25890. public function getPriority()
  25891. {
  25892. return 65;
  25893. }
  25894. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  25895. {
  25896. for ($i = 1, $count = $tokens->count(); $i < $count; ++$i) {
  25897. if (!$tokens[$i]->isClassy()) {
  25898. continue;
  25899. }
  25900. $i = $tokens->getNextTokenOfKind($i, ['{']);
  25901. $elements = $this->getElements($tokens, $i);
  25902. if (0 === \count($elements)) {
  25903. continue;
  25904. }
  25905. $sorted = $this->sortElements($elements);
  25906. $endIndex = $elements[\count($elements) - 1]['end'];
  25907. if ($sorted !== $elements) {
  25908. $this->sortTokens($tokens, $i, $endIndex, $sorted);
  25909. }
  25910. $i = $endIndex;
  25911. }
  25912. }
  25913. protected function createConfigurationDefinition()
  25914. {
  25915. return new FixerConfigurationResolverRootless('order', [
  25916. (new FixerOptionBuilder('order', 'List of strings defining order of elements.'))
  25917. ->setAllowedTypes(['array'])
  25918. ->setAllowedValues([new AllowedValueSubset(array_keys(array_merge(self::$typeHierarchy, self::$specialTypes)))])
  25919. ->setDefault([
  25920. 'use_trait',
  25921. 'constant_public',
  25922. 'constant_protected',
  25923. 'constant_private',
  25924. 'property_public',
  25925. 'property_protected',
  25926. 'property_private',
  25927. 'construct',
  25928. 'destruct',
  25929. 'magic',
  25930. 'phpunit',
  25931. 'method_public',
  25932. 'method_protected',
  25933. 'method_private',
  25934. ])
  25935. ->getOption(),
  25936. (new FixerOptionBuilder('sortAlgorithm', 'How multiple occurrences of same type statements should be sorted'))
  25937. ->setAllowedValues($this->supportedSortAlgorithms)
  25938. ->setDefault(self::SORT_NONE)
  25939. ->getOption(),
  25940. ], $this->getName());
  25941. }
  25942. private function getElements(Tokens $tokens, $startIndex)
  25943. {
  25944. static $elementTokenKinds = [CT::T_USE_TRAIT, T_CONST, T_VARIABLE, T_FUNCTION];
  25945. ++$startIndex;
  25946. $elements = [];
  25947. while (true) {
  25948. $element = [
  25949. 'start' => $startIndex,
  25950. 'visibility' => 'public',
  25951. 'static' => false,
  25952. ];
  25953. for ($i = $startIndex;; ++$i) {
  25954. $token = $tokens[$i];
  25955. if ($token->equals('}')) {
  25956. return $elements;
  25957. }
  25958. if ($token->isGivenKind(T_STATIC)) {
  25959. $element['static'] = true;
  25960. continue;
  25961. }
  25962. if ($token->isGivenKind([T_PROTECTED, T_PRIVATE])) {
  25963. $element['visibility'] = strtolower($token->getContent());
  25964. continue;
  25965. }
  25966. if (!$token->isGivenKind($elementTokenKinds)) {
  25967. continue;
  25968. }
  25969. $type = $this->detectElementType($tokens, $i);
  25970. if (\is_array($type)) {
  25971. $element['type'] = $type[0];
  25972. $element['name'] = $type[1];
  25973. } else {
  25974. $element['type'] = $type;
  25975. }
  25976. if ('property' === $element['type']) {
  25977. $element['name'] = $tokens[$i]->getContent();
  25978. } elseif (\in_array($element['type'], ['use_trait', 'constant', 'method', 'magic', 'construct', 'destruct'], true)) {
  25979. $element['name'] = $tokens[$tokens->getNextMeaningfulToken($i)]->getContent();
  25980. }
  25981. $element['end'] = $this->findElementEnd($tokens, $i);
  25982. break;
  25983. }
  25984. $elements[] = $element;
  25985. $startIndex = $element['end'] + 1;
  25986. }
  25987. }
  25988. private function detectElementType(Tokens $tokens, $index)
  25989. {
  25990. $token = $tokens[$index];
  25991. if ($token->isGivenKind(CT::T_USE_TRAIT)) {
  25992. return 'use_trait';
  25993. }
  25994. if ($token->isGivenKind(T_CONST)) {
  25995. return 'constant';
  25996. }
  25997. if ($token->isGivenKind(T_VARIABLE)) {
  25998. return 'property';
  25999. }
  26000. $nameToken = $tokens[$tokens->getNextMeaningfulToken($index)];
  26001. if ($nameToken->equals([T_STRING, '__construct'], false)) {
  26002. return 'construct';
  26003. }
  26004. if ($nameToken->equals([T_STRING, '__destruct'], false)) {
  26005. return 'destruct';
  26006. }
  26007. if (
  26008. $nameToken->equalsAny([
  26009. [T_STRING, 'setUpBeforeClass'],
  26010. [T_STRING, 'tearDownAfterClass'],
  26011. [T_STRING, 'setUp'],
  26012. [T_STRING, 'tearDown'],
  26013. ], false)
  26014. ) {
  26015. return ['phpunit', strtolower($nameToken->getContent())];
  26016. }
  26017. if ('__' === substr($nameToken->getContent(), 0, 2)) {
  26018. return 'magic';
  26019. }
  26020. return 'method';
  26021. }
  26022. private function findElementEnd(Tokens $tokens, $index)
  26023. {
  26024. $index = $tokens->getNextTokenOfKind($index, ['{', ';']);
  26025. if ($tokens[$index]->equals('{')) {
  26026. $index = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $index);
  26027. }
  26028. for (++$index; $tokens[$index]->isWhitespace(" \t") || $tokens[$index]->isComment(); ++$index);
  26029. --$index;
  26030. return $tokens[$index]->isWhitespace() ? $index - 1 : $index;
  26031. }
  26032. private function sortElements(array $elements)
  26033. {
  26034. static $phpunitPositions = [
  26035. 'setupbeforeclass' => 1,
  26036. 'teardownafterclass' => 2,
  26037. 'setup' => 3,
  26038. 'teardown' => 4,
  26039. ];
  26040. foreach ($elements as &$element) {
  26041. $type = $element['type'];
  26042. if (\array_key_exists($type, self::$specialTypes)) {
  26043. if (isset($this->typePosition[$type])) {
  26044. $element['position'] = $this->typePosition[$type];
  26045. if ('phpunit' === $type) {
  26046. $element['position'] += $phpunitPositions[$element['name']];
  26047. }
  26048. continue;
  26049. }
  26050. $type = 'method';
  26051. }
  26052. if (\in_array($type, ['constant', 'property', 'method'], true)) {
  26053. $type .= '_'.$element['visibility'];
  26054. if ($element['static']) {
  26055. $type .= '_static';
  26056. }
  26057. }
  26058. $element['position'] = $this->typePosition[$type];
  26059. }
  26060. unset($element);
  26061. usort($elements, function (array $a, array $b) {
  26062. if ($a['position'] === $b['position']) {
  26063. return $this->sortGroupElements($a, $b);
  26064. }
  26065. return $a['position'] > $b['position'] ? 1 : -1;
  26066. });
  26067. return $elements;
  26068. }
  26069. private function sortGroupElements(array $a, array $b)
  26070. {
  26071. $selectedSortAlgorithm = $this->configuration['sortAlgorithm'];
  26072. if (self::SORT_ALPHA === $selectedSortAlgorithm) {
  26073. return strcasecmp($a['name'], $b['name']);
  26074. }
  26075. return $a['start'] > $b['start'] ? 1 : -1;
  26076. }
  26077. private function sortTokens(Tokens $tokens, $startIndex, $endIndex, array $elements)
  26078. {
  26079. $replaceTokens = [];
  26080. foreach ($elements as $element) {
  26081. for ($i = $element['start']; $i <= $element['end']; ++$i) {
  26082. $replaceTokens[] = clone $tokens[$i];
  26083. }
  26084. }
  26085. $tokens->overrideRange($startIndex + 1, $endIndex, $replaceTokens);
  26086. }
  26087. }
  26088. <?php
  26089. namespace PhpCsFixer\Fixer\ClassNotation;
  26090. use PhpCsFixer\AbstractFixer;
  26091. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  26092. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  26093. use PhpCsFixer\FixerConfiguration\AliasedFixerOptionBuilder;
  26094. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  26095. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  26096. use PhpCsFixer\FixerDefinition\CodeSample;
  26097. use PhpCsFixer\FixerDefinition\FixerDefinition;
  26098. use PhpCsFixer\FixerDefinition\VersionSpecification;
  26099. use PhpCsFixer\FixerDefinition\VersionSpecificCodeSample;
  26100. use PhpCsFixer\Tokenizer\Token;
  26101. use PhpCsFixer\Tokenizer\Tokens;
  26102. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  26103. final class ClassDefinitionFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface, WhitespacesAwareFixerInterface
  26104. {
  26105. public function getDefinition()
  26106. {
  26107. return new FixerDefinition(
  26108. 'Whitespace around the keywords of a class, trait or interfaces definition should be one space.',
  26109. [
  26110. new CodeSample(
  26111. '<?php
  26112. class Foo extends Bar implements Baz, BarBaz
  26113. {
  26114. }
  26115. final class Foo extends Bar implements Baz, BarBaz
  26116. {
  26117. }
  26118. trait Foo
  26119. {
  26120. }
  26121. '
  26122. ),
  26123. new VersionSpecificCodeSample(
  26124. '<?php
  26125. $foo = new class extends Bar implements Baz, BarBaz {};
  26126. ',
  26127. new VersionSpecification(70100)
  26128. ),
  26129. new CodeSample(
  26130. '<?php
  26131. class Foo
  26132. extends Bar
  26133. implements Baz, BarBaz
  26134. {}
  26135. ',
  26136. ['single_line' => true]
  26137. ),
  26138. new CodeSample(
  26139. '<?php
  26140. class Foo
  26141. extends Bar
  26142. implements Baz
  26143. {}
  26144. ',
  26145. ['single_item_single_line' => true]
  26146. ),
  26147. new CodeSample(
  26148. '<?php
  26149. interface Bar extends
  26150. Bar, BarBaz, FooBarBaz
  26151. {}
  26152. ',
  26153. ['multi_line_extends_each_single_line' => true]
  26154. ),
  26155. ]
  26156. );
  26157. }
  26158. public function isCandidate(Tokens $tokens)
  26159. {
  26160. return $tokens->isAnyTokenKindsFound(Token::getClassyTokenKinds());
  26161. }
  26162. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  26163. {
  26164. for ($index = $tokens->getSize() - 4; $index > 0; --$index) {
  26165. if ($tokens[$index]->isClassy()) {
  26166. $this->fixClassyDefinition($tokens, $index);
  26167. }
  26168. }
  26169. }
  26170. protected function createConfigurationDefinition()
  26171. {
  26172. return new FixerConfigurationResolver([
  26173. (new AliasedFixerOptionBuilder(
  26174. new FixerOptionBuilder('multi_line_extends_each_single_line', 'Whether definitions should be multiline.'),
  26175. 'multiLineExtendsEachSingleLine'
  26176. ))
  26177. ->setAllowedTypes(['bool'])
  26178. ->setDefault(false)
  26179. ->getOption(),
  26180. (new AliasedFixerOptionBuilder(
  26181. new FixerOptionBuilder('single_item_single_line', 'Whether definitions should be single line when including a single item.'),
  26182. 'singleItemSingleLine'
  26183. ))
  26184. ->setAllowedTypes(['bool'])
  26185. ->setDefault(false)
  26186. ->getOption(),
  26187. (new AliasedFixerOptionBuilder(
  26188. new FixerOptionBuilder('single_line', 'Whether definitions should be single line.'),
  26189. 'singleLine'
  26190. ))
  26191. ->setAllowedTypes(['bool'])
  26192. ->setDefault(false)
  26193. ->getOption(),
  26194. ]);
  26195. }
  26196. private function fixClassyDefinition(Tokens $tokens, $classyIndex)
  26197. {
  26198. $classDefInfo = $this->getClassyDefinitionInfo($tokens, $classyIndex);
  26199. if (false !== $classDefInfo['implements']) {
  26200. $classDefInfo['implements'] = $this->fixClassyDefinitionImplements(
  26201. $tokens,
  26202. $classDefInfo['open'],
  26203. $classDefInfo['implements']
  26204. );
  26205. }
  26206. if (false !== $classDefInfo['extends']) {
  26207. $classDefInfo['extends'] = $this->fixClassyDefinitionExtends(
  26208. $tokens,
  26209. false === $classDefInfo['implements'] ? $classDefInfo['open'] : $classDefInfo['implements']['start'],
  26210. $classDefInfo['extends']
  26211. );
  26212. }
  26213. $classDefInfo['open'] = $this->fixClassyDefinitionOpenSpacing($tokens, $classDefInfo);
  26214. if ($classDefInfo['implements']) {
  26215. $end = $classDefInfo['implements']['start'];
  26216. } elseif ($classDefInfo['extends']) {
  26217. $end = $classDefInfo['extends']['start'];
  26218. } else {
  26219. $end = $tokens->getPrevNonWhitespace($classDefInfo['open']);
  26220. }
  26221. $this->makeClassyDefinitionSingleLine(
  26222. $tokens,
  26223. $classDefInfo['anonymousClass'] ? $tokens->getPrevMeaningfulToken($classyIndex) : $classDefInfo['start'],
  26224. $end
  26225. );
  26226. }
  26227. private function fixClassyDefinitionExtends(Tokens $tokens, $classOpenIndex, array $classExtendsInfo)
  26228. {
  26229. $endIndex = $tokens->getPrevNonWhitespace($classOpenIndex);
  26230. if ($this->configuration['single_line'] || false === $classExtendsInfo['multiLine']) {
  26231. $this->makeClassyDefinitionSingleLine($tokens, $classExtendsInfo['start'], $endIndex);
  26232. $classExtendsInfo['multiLine'] = false;
  26233. } elseif ($this->configuration['single_item_single_line'] && 1 === $classExtendsInfo['numberOfExtends']) {
  26234. $this->makeClassyDefinitionSingleLine($tokens, $classExtendsInfo['start'], $endIndex);
  26235. $classExtendsInfo['multiLine'] = false;
  26236. } elseif ($this->configuration['multi_line_extends_each_single_line'] && $classExtendsInfo['multiLine']) {
  26237. $this->makeClassyInheritancePartMultiLine($tokens, $classExtendsInfo['start'], $endIndex);
  26238. $classExtendsInfo['multiLine'] = true;
  26239. }
  26240. return $classExtendsInfo;
  26241. }
  26242. private function fixClassyDefinitionImplements(Tokens $tokens, $classOpenIndex, array $classImplementsInfo)
  26243. {
  26244. $endIndex = $tokens->getPrevNonWhitespace($classOpenIndex);
  26245. if ($this->configuration['single_line'] || false === $classImplementsInfo['multiLine']) {
  26246. $this->makeClassyDefinitionSingleLine($tokens, $classImplementsInfo['start'], $endIndex);
  26247. $classImplementsInfo['multiLine'] = false;
  26248. } elseif ($this->configuration['single_item_single_line'] && 1 === $classImplementsInfo['numberOfImplements']) {
  26249. $this->makeClassyDefinitionSingleLine($tokens, $classImplementsInfo['start'], $endIndex);
  26250. $classImplementsInfo['multiLine'] = false;
  26251. } else {
  26252. $this->makeClassyInheritancePartMultiLine($tokens, $classImplementsInfo['start'], $endIndex);
  26253. $classImplementsInfo['multiLine'] = true;
  26254. }
  26255. return $classImplementsInfo;
  26256. }
  26257. private function fixClassyDefinitionOpenSpacing(Tokens $tokens, array $classDefInfo)
  26258. {
  26259. if ($classDefInfo['anonymousClass']) {
  26260. if (false !== $classDefInfo['implements']) {
  26261. $spacing = $classDefInfo['implements']['multiLine'] ? $this->whitespacesConfig->getLineEnding() : ' ';
  26262. } elseif (false !== $classDefInfo['extends']) {
  26263. $spacing = $classDefInfo['extends']['multiLine'] ? $this->whitespacesConfig->getLineEnding() : ' ';
  26264. } else {
  26265. $spacing = ' ';
  26266. }
  26267. } else {
  26268. $spacing = $this->whitespacesConfig->getLineEnding();
  26269. }
  26270. $openIndex = $tokens->getNextTokenOfKind($classDefInfo['classy'], ['{']);
  26271. if (' ' !== $spacing && false !== strpos($tokens[$openIndex - 1]->getContent(), "\n")) {
  26272. return $openIndex;
  26273. }
  26274. if ($tokens[$openIndex - 1]->isWhitespace()) {
  26275. if (' ' !== $spacing || !$tokens[$tokens->getPrevNonWhitespace($openIndex - 1)]->isComment()) {
  26276. $tokens[$openIndex - 1] = new Token([T_WHITESPACE, $spacing]);
  26277. }
  26278. return $openIndex;
  26279. }
  26280. $tokens->insertAt($openIndex, new Token([T_WHITESPACE, $spacing]));
  26281. return $openIndex + 1;
  26282. }
  26283. private function getClassyDefinitionInfo(Tokens $tokens, $classyIndex)
  26284. {
  26285. $openIndex = $tokens->getNextTokenOfKind($classyIndex, ['{']);
  26286. $prev = $tokens->getPrevMeaningfulToken($classyIndex);
  26287. $startIndex = $tokens[$prev]->isGivenKind([T_FINAL, T_ABSTRACT]) ? $prev : $classyIndex;
  26288. $extends = false;
  26289. $implements = false;
  26290. $anonymousClass = false;
  26291. if (!$tokens[$classyIndex]->isGivenKind(T_TRAIT)) {
  26292. $extends = $tokens->findGivenKind(T_EXTENDS, $classyIndex, $openIndex);
  26293. $extends = \count($extends) ? $this->getClassyInheritanceInfo($tokens, key($extends), 'numberOfExtends') : false;
  26294. if (!$tokens[$classyIndex]->isGivenKind(T_INTERFACE)) {
  26295. $implements = $tokens->findGivenKind(T_IMPLEMENTS, $classyIndex, $openIndex);
  26296. $implements = \count($implements) ? $this->getClassyInheritanceInfo($tokens, key($implements), 'numberOfImplements') : false;
  26297. $tokensAnalyzer = new TokensAnalyzer($tokens);
  26298. $anonymousClass = $tokensAnalyzer->isAnonymousClass($classyIndex);
  26299. }
  26300. }
  26301. return [
  26302. 'start' => $startIndex,
  26303. 'classy' => $classyIndex,
  26304. 'open' => $openIndex,
  26305. 'extends' => $extends,
  26306. 'implements' => $implements,
  26307. 'anonymousClass' => $anonymousClass,
  26308. ];
  26309. }
  26310. private function getClassyInheritanceInfo(Tokens $tokens, $startIndex, $label)
  26311. {
  26312. $implementsInfo = ['start' => $startIndex, $label => 1, 'multiLine' => false];
  26313. ++$startIndex;
  26314. $endIndex = $tokens->getNextTokenOfKind($startIndex, ['{', [T_IMPLEMENTS], [T_EXTENDS]]);
  26315. $endIndex = $tokens[$endIndex]->equals('{') ? $tokens->getPrevNonWhitespace($endIndex) : $endIndex;
  26316. for ($i = $startIndex; $i < $endIndex; ++$i) {
  26317. if ($tokens[$i]->equals(',')) {
  26318. ++$implementsInfo[$label];
  26319. continue;
  26320. }
  26321. if (!$implementsInfo['multiLine'] && false !== strpos($tokens[$i]->getContent(), "\n")) {
  26322. $implementsInfo['multiLine'] = true;
  26323. }
  26324. }
  26325. return $implementsInfo;
  26326. }
  26327. private function makeClassyDefinitionSingleLine(Tokens $tokens, $startIndex, $endIndex)
  26328. {
  26329. for ($i = $endIndex; $i >= $startIndex; --$i) {
  26330. if ($tokens[$i]->isWhitespace()) {
  26331. $prevNonWhite = $tokens->getPrevNonWhitespace($i);
  26332. $nextNonWhite = $tokens->getNextNonWhitespace($i);
  26333. if ($tokens[$prevNonWhite]->isComment() || $tokens[$nextNonWhite]->isComment()) {
  26334. $content = $tokens[$prevNonWhite]->getContent();
  26335. if (!('#' === $content || '//' === substr($content, 0, 2))) {
  26336. $content = $tokens[$nextNonWhite]->getContent();
  26337. if (!('#' === $content || '//' === substr($content, 0, 2))) {
  26338. $tokens[$i] = new Token([T_WHITESPACE, ' ']);
  26339. }
  26340. }
  26341. continue;
  26342. }
  26343. if ($tokens[$i + 1]->equalsAny([',', '(', ')']) || $tokens[$i - 1]->equals('(')) {
  26344. $tokens->clearAt($i);
  26345. continue;
  26346. }
  26347. $tokens[$i] = new Token([T_WHITESPACE, ' ']);
  26348. continue;
  26349. }
  26350. if ($tokens[$i]->equals(',') && !$tokens[$i + 1]->isWhitespace()) {
  26351. $tokens->insertAt($i + 1, new Token([T_WHITESPACE, ' ']));
  26352. continue;
  26353. }
  26354. if (!$tokens[$i]->isComment()) {
  26355. continue;
  26356. }
  26357. if (!$tokens[$i + 1]->isWhitespace() && !$tokens[$i + 1]->isComment() && false === strpos($tokens[$i]->getContent(), "\n")) {
  26358. $tokens->insertAt($i + 1, new Token([T_WHITESPACE, ' ']));
  26359. }
  26360. if (!$tokens[$i - 1]->isWhitespace() && !$tokens[$i - 1]->isComment()) {
  26361. $tokens->insertAt($i, new Token([T_WHITESPACE, ' ']));
  26362. }
  26363. }
  26364. }
  26365. private function makeClassyInheritancePartMultiLine(Tokens $tokens, $startIndex, $endIndex)
  26366. {
  26367. for ($i = $endIndex; $i > $startIndex; --$i) {
  26368. $previousInterfaceImplementingIndex = $tokens->getPrevTokenOfKind($i, [',', [T_IMPLEMENTS], [T_EXTENDS]]);
  26369. $breakAtIndex = $tokens->getNextMeaningfulToken($previousInterfaceImplementingIndex);
  26370. $this->makeClassyDefinitionSingleLine(
  26371. $tokens,
  26372. $breakAtIndex,
  26373. $i
  26374. );
  26375. $isOnOwnLine = false;
  26376. for ($j = $breakAtIndex; $j > $previousInterfaceImplementingIndex; --$j) {
  26377. if (false !== strpos($tokens[$j]->getContent(), "\n")) {
  26378. $isOnOwnLine = true;
  26379. break;
  26380. }
  26381. }
  26382. if (!$isOnOwnLine) {
  26383. if ($tokens[$breakAtIndex - 1]->isWhitespace()) {
  26384. $tokens[$breakAtIndex - 1] = new Token([
  26385. T_WHITESPACE,
  26386. $this->whitespacesConfig->getLineEnding().$this->whitespacesConfig->getIndent(),
  26387. ]);
  26388. } else {
  26389. $tokens->insertAt($breakAtIndex, new Token([T_WHITESPACE, $this->whitespacesConfig->getLineEnding().$this->whitespacesConfig->getIndent()]));
  26390. }
  26391. }
  26392. $i = $previousInterfaceImplementingIndex + 1;
  26393. }
  26394. }
  26395. }
  26396. <?php
  26397. namespace PhpCsFixer\Fixer\ClassNotation;
  26398. use PhpCsFixer\AbstractFixer;
  26399. use PhpCsFixer\FixerDefinition\CodeSample;
  26400. use PhpCsFixer\FixerDefinition\FixerDefinition;
  26401. use PhpCsFixer\Tokenizer\Token;
  26402. use PhpCsFixer\Tokenizer\Tokens;
  26403. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  26404. final class NoPhp4ConstructorFixer extends AbstractFixer
  26405. {
  26406. public function getDefinition()
  26407. {
  26408. return new FixerDefinition(
  26409. 'Convert PHP4-style constructors to `__construct`.',
  26410. [
  26411. new CodeSample('<?php
  26412. class Foo
  26413. {
  26414. public function Foo($bar)
  26415. {
  26416. }
  26417. }
  26418. '),
  26419. ],
  26420. null,
  26421. 'Risky when old style constructor being fixed is overridden or overrides parent one.'
  26422. );
  26423. }
  26424. public function getPriority()
  26425. {
  26426. return 75;
  26427. }
  26428. public function isCandidate(Tokens $tokens)
  26429. {
  26430. return $tokens->isTokenKindFound(T_CLASS);
  26431. }
  26432. public function isRisky()
  26433. {
  26434. return true;
  26435. }
  26436. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  26437. {
  26438. $tokensAnalyzer = new TokensAnalyzer($tokens);
  26439. $classes = array_keys($tokens->findGivenKind(T_CLASS));
  26440. $numClasses = \count($classes);
  26441. for ($i = 0; $i < $numClasses; ++$i) {
  26442. $index = $classes[$i];
  26443. if ($tokensAnalyzer->isAnonymousClass($index)) {
  26444. continue;
  26445. }
  26446. $nspIndex = $tokens->getPrevTokenOfKind($index, [[T_NAMESPACE, 'namespace']]);
  26447. if (null !== $nspIndex) {
  26448. $nspIndex = $tokens->getNextMeaningfulToken($nspIndex);
  26449. if (!$tokens[$nspIndex]->equals('{')) {
  26450. $nspIndex = $tokens->getNextTokenOfKind($nspIndex, [';', '{']);
  26451. if ($tokens[$nspIndex]->equals(';')) {
  26452. break;
  26453. }
  26454. $nspEnd = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $nspIndex);
  26455. if ($index < $nspEnd) {
  26456. for ($j = $i + 1; $j < $numClasses; ++$j) {
  26457. if ($classes[$j] < $nspEnd) {
  26458. ++$i;
  26459. }
  26460. }
  26461. continue;
  26462. }
  26463. }
  26464. }
  26465. $classNameIndex = $tokens->getNextMeaningfulToken($index);
  26466. $className = $tokens[$classNameIndex]->getContent();
  26467. $classStart = $tokens->getNextTokenOfKind($classNameIndex, ['{']);
  26468. $classEnd = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $classStart);
  26469. $this->fixConstructor($tokens, $className, $classStart, $classEnd);
  26470. $this->fixParent($tokens, $classStart, $classEnd);
  26471. }
  26472. }
  26473. private function fixConstructor(Tokens $tokens, $className, $classStart, $classEnd)
  26474. {
  26475. $php4 = $this->findFunction($tokens, $className, $classStart, $classEnd);
  26476. if (null === $php4) {
  26477. return;
  26478. }
  26479. if (!empty($php4['modifiers'][T_ABSTRACT]) || !empty($php4['modifiers'][T_STATIC])) {
  26480. return;
  26481. }
  26482. $php5 = $this->findFunction($tokens, '__construct', $classStart, $classEnd);
  26483. if (null === $php5) {
  26484. $tokens[$php4['nameIndex']] = new Token([T_STRING, '__construct']);
  26485. $this->fixInfiniteRecursion($tokens, $php4['bodyIndex'], $php4['endIndex']);
  26486. return;
  26487. }
  26488. list($seq, $case) = $this->getWrapperMethodSequence($tokens, '__construct', $php4['startIndex'], $php4['bodyIndex']);
  26489. if (null !== $tokens->findSequence($seq, $php4['bodyIndex'] - 1, $php4['endIndex'], $case)) {
  26490. for ($i = $php4['startIndex']; $i <= $php4['endIndex']; ++$i) {
  26491. $tokens->clearAt($i);
  26492. }
  26493. return;
  26494. }
  26495. list($seq, $case) = $this->getWrapperMethodSequence($tokens, $className, $php4['startIndex'], $php4['bodyIndex']);
  26496. if (null !== $tokens->findSequence($seq, $php5['bodyIndex'] - 1, $php5['endIndex'], $case)) {
  26497. for ($i = $php5['startIndex']; $i <= $php5['endIndex']; ++$i) {
  26498. $tokens->clearAt($i);
  26499. }
  26500. $tokens[$php4['nameIndex']] = new Token([T_STRING, '__construct']);
  26501. }
  26502. }
  26503. private function fixParent(Tokens $tokens, $classStart, $classEnd)
  26504. {
  26505. foreach ($tokens->findGivenKind(T_EXTENDS) as $index => $token) {
  26506. $parentIndex = $tokens->getNextMeaningfulToken($index);
  26507. $parentClass = $tokens[$parentIndex]->getContent();
  26508. $parentSeq = $tokens->findSequence([
  26509. [T_STRING],
  26510. [T_DOUBLE_COLON],
  26511. [T_STRING, $parentClass],
  26512. '(',
  26513. ], $classStart, $classEnd, [2 => false]);
  26514. if (null !== $parentSeq) {
  26515. $parentSeq = array_keys($parentSeq);
  26516. if ($tokens[$parentSeq[0]]->equalsAny([[T_STRING, 'parent'], [T_STRING, $parentClass]], false)) {
  26517. $tokens[$parentSeq[0]] = new Token([T_STRING, 'parent']);
  26518. $tokens[$parentSeq[2]] = new Token([T_STRING, '__construct']);
  26519. }
  26520. }
  26521. $parentSeq = $tokens->findSequence([
  26522. [T_VARIABLE, '$this'],
  26523. [T_OBJECT_OPERATOR],
  26524. [T_STRING, $parentClass],
  26525. '(',
  26526. ], $classStart, $classEnd, [2 => false]);
  26527. if (null !== $parentSeq) {
  26528. $parentSeq = array_keys($parentSeq);
  26529. $tokens[$parentSeq[0]] = new Token([
  26530. T_STRING,
  26531. 'parent',
  26532. ]);
  26533. $tokens[$parentSeq[1]] = new Token([
  26534. T_DOUBLE_COLON,
  26535. '::',
  26536. ]);
  26537. $tokens[$parentSeq[2]] = new Token([T_STRING, '__construct']);
  26538. }
  26539. }
  26540. }
  26541. private function fixInfiniteRecursion(Tokens $tokens, $start, $end)
  26542. {
  26543. $seq = [
  26544. [T_VARIABLE, '$this'],
  26545. [T_OBJECT_OPERATOR],
  26546. [T_STRING, '__construct'],
  26547. ];
  26548. while (true) {
  26549. $callSeq = $tokens->findSequence($seq, $start, $end, [2 => false]);
  26550. if (null === $callSeq) {
  26551. return;
  26552. }
  26553. $callSeq = array_keys($callSeq);
  26554. $tokens[$callSeq[0]] = new Token([T_STRING, 'parent']);
  26555. $tokens[$callSeq[1]] = new Token([T_DOUBLE_COLON, '::']);
  26556. }
  26557. }
  26558. private function getWrapperMethodSequence(Tokens $tokens, $method, $startIndex, $bodyIndex)
  26559. {
  26560. $seq = [
  26561. '{',
  26562. [T_VARIABLE, '$this'],
  26563. [T_OBJECT_OPERATOR],
  26564. [T_STRING, $method],
  26565. '(',
  26566. ];
  26567. $case = [3 => false];
  26568. $index = $startIndex;
  26569. while (true) {
  26570. $index = $tokens->getNextTokenOfKind($index, [[T_VARIABLE]]);
  26571. if (null === $index || $index >= $bodyIndex) {
  26572. break;
  26573. }
  26574. if (\count($seq) > 5) {
  26575. $seq[] = ',';
  26576. }
  26577. $seq[] = [T_VARIABLE, $tokens[$index]->getContent()];
  26578. }
  26579. $seq[] = ')';
  26580. $seq[] = ';';
  26581. $seq[] = '}';
  26582. return [$seq, $case];
  26583. }
  26584. private function findFunction(Tokens $tokens, $name, $startIndex, $endIndex)
  26585. {
  26586. $function = $tokens->findSequence([
  26587. [T_FUNCTION],
  26588. [T_STRING, $name],
  26589. '(',
  26590. ], $startIndex, $endIndex, false);
  26591. if (null === $function) {
  26592. return null;
  26593. }
  26594. $function = array_keys($function);
  26595. $possibleModifiers = [T_PUBLIC, T_PROTECTED, T_PRIVATE, T_STATIC, T_ABSTRACT, T_FINAL];
  26596. $modifiers = [];
  26597. $prevBlock = $tokens->getPrevMeaningfulToken($function[0]);
  26598. while (null !== $prevBlock && $tokens[$prevBlock]->isGivenKind($possibleModifiers)) {
  26599. $modifiers[$tokens[$prevBlock]->getId()] = $prevBlock;
  26600. $prevBlock = $tokens->getPrevMeaningfulToken($prevBlock);
  26601. }
  26602. if (isset($modifiers[T_ABSTRACT])) {
  26603. $bodyStart = null;
  26604. $funcEnd = $tokens->getNextTokenOfKind($function[2], [';']);
  26605. } else {
  26606. $bodyStart = $tokens->getNextTokenOfKind($function[2], ['{']);
  26607. $funcEnd = null !== $bodyStart ? $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $bodyStart) : null;
  26608. }
  26609. return [
  26610. 'nameIndex' => $function[1],
  26611. 'startIndex' => $prevBlock + 1,
  26612. 'endIndex' => $funcEnd,
  26613. 'bodyIndex' => $bodyStart,
  26614. 'modifiers' => $modifiers,
  26615. ];
  26616. }
  26617. }
  26618. <?php
  26619. namespace PhpCsFixer\Fixer\ClassNotation;
  26620. use PhpCsFixer\AbstractFixer;
  26621. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  26622. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  26623. use PhpCsFixer\FixerConfiguration\AllowedValueSubset;
  26624. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverRootless;
  26625. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  26626. use PhpCsFixer\FixerDefinition\CodeSample;
  26627. use PhpCsFixer\FixerDefinition\FixerDefinition;
  26628. use PhpCsFixer\Preg;
  26629. use PhpCsFixer\Tokenizer\CT;
  26630. use PhpCsFixer\Tokenizer\Token;
  26631. use PhpCsFixer\Tokenizer\Tokens;
  26632. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  26633. /**
  26634. @gmail
  26635. */
  26636. final class SingleClassElementPerStatementFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface, WhitespacesAwareFixerInterface
  26637. {
  26638. public function isCandidate(Tokens $tokens)
  26639. {
  26640. return $tokens->isAnyTokenKindsFound(Token::getClassyTokenKinds());
  26641. }
  26642. public function getPriority()
  26643. {
  26644. return 56;
  26645. }
  26646. public function getDefinition()
  26647. {
  26648. return new FixerDefinition(
  26649. 'There MUST NOT be more than one property or constant declared per statement.',
  26650. [
  26651. new CodeSample(
  26652. '<?php
  26653. final class Example
  26654. {
  26655. const FOO_1 = 1, FOO_2 = 2;
  26656. private static $bar1 = array(1,2,3), $bar2 = [1,2,3];
  26657. }
  26658. '
  26659. ),
  26660. new CodeSample(
  26661. '<?php
  26662. final class Example
  26663. {
  26664. const FOO_1 = 1, FOO_2 = 2;
  26665. private static $bar1 = array(1,2,3), $bar2 = [1,2,3];
  26666. }
  26667. ',
  26668. ['elements' => ['property']]
  26669. ),
  26670. ]
  26671. );
  26672. }
  26673. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  26674. {
  26675. $analyzer = new TokensAnalyzer($tokens);
  26676. $elements = array_reverse($analyzer->getClassyElements(), true);
  26677. foreach ($elements as $index => $element) {
  26678. if (!\in_array($element['type'], $this->configuration['elements'], true)) {
  26679. continue;
  26680. }
  26681. $this->fixElement($tokens, $element['type'], $index);
  26682. }
  26683. }
  26684. protected function createConfigurationDefinition()
  26685. {
  26686. $values = ['const', 'property'];
  26687. return new FixerConfigurationResolverRootless('elements', [
  26688. (new FixerOptionBuilder('elements', 'List of strings which element should be modified.'))
  26689. ->setDefault($values)
  26690. ->setAllowedTypes(['array'])
  26691. ->setAllowedValues([new AllowedValueSubset($values)])
  26692. ->getOption(),
  26693. ], $this->getName());
  26694. }
  26695. private function fixElement(Tokens $tokens, $type, $index)
  26696. {
  26697. $tokensAnalyzer = new TokensAnalyzer($tokens);
  26698. $repeatIndex = $index;
  26699. while (true) {
  26700. $repeatIndex = $tokens->getNextMeaningfulToken($repeatIndex);
  26701. $repeatToken = $tokens[$repeatIndex];
  26702. if ($tokensAnalyzer->isArray($repeatIndex)) {
  26703. if ($repeatToken->isGivenKind(T_ARRAY)) {
  26704. $repeatIndex = $tokens->getNextTokenOfKind($repeatIndex, ['(']);
  26705. $repeatIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $repeatIndex);
  26706. } else {
  26707. $repeatIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_ARRAY_SQUARE_BRACE, $repeatIndex);
  26708. }
  26709. continue;
  26710. }
  26711. if ($repeatToken->equals(';')) {
  26712. return;
  26713. }
  26714. if ($repeatToken->equals(',')) {
  26715. break;
  26716. }
  26717. }
  26718. $start = $tokens->getPrevTokenOfKind($index, [';', '{', '}']);
  26719. $this->expandElement(
  26720. $tokens,
  26721. $type,
  26722. $tokens->getNextMeaningfulToken($start),
  26723. $tokens->getNextTokenOfKind($index, [';'])
  26724. );
  26725. }
  26726. private function expandElement(Tokens $tokens, $type, $startIndex, $endIndex)
  26727. {
  26728. $divisionContent = null;
  26729. if ($tokens[$startIndex - 1]->isWhitespace()) {
  26730. $divisionContent = $tokens[$startIndex - 1]->getContent();
  26731. if (Preg::match('#(\n|\r\n)#', $divisionContent, $matches)) {
  26732. $divisionContent = $matches[0].trim($divisionContent, "\r\n");
  26733. }
  26734. }
  26735. for ($i = $endIndex - 1; $i > $startIndex; --$i) {
  26736. $token = $tokens[$i];
  26737. if ($token->equals(')')) {
  26738. $i = $tokens->findBlockStart(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $i);
  26739. continue;
  26740. }
  26741. if ($token->isGivenKind(CT::T_ARRAY_SQUARE_BRACE_CLOSE)) {
  26742. $i = $tokens->findBlockStart(Tokens::BLOCK_TYPE_ARRAY_SQUARE_BRACE, $i);
  26743. continue;
  26744. }
  26745. if (!$tokens[$i]->equals(',')) {
  26746. continue;
  26747. }
  26748. $tokens[$i] = new Token(';');
  26749. if ($tokens[$i + 1]->isWhitespace()) {
  26750. $tokens->clearAt($i + 1);
  26751. }
  26752. if (null !== $divisionContent && '' !== $divisionContent) {
  26753. $tokens->insertAt($i + 1, new Token([T_WHITESPACE, $divisionContent]));
  26754. }
  26755. $sequence = $this->getModifiersSequences($tokens, $type, $startIndex, $endIndex);
  26756. $tokens->insertAt($i + 2, $sequence);
  26757. }
  26758. }
  26759. private function getModifiersSequences(Tokens $tokens, $type, $startIndex, $endIndex)
  26760. {
  26761. if ('property' === $type) {
  26762. $tokenKinds = [T_PUBLIC, T_PROTECTED, T_PRIVATE, T_STATIC, T_VAR, T_STRING, T_NS_SEPARATOR, CT::T_NULLABLE_TYPE, CT::T_ARRAY_TYPEHINT];
  26763. } else {
  26764. $tokenKinds = [T_PUBLIC, T_PROTECTED, T_PRIVATE, T_CONST];
  26765. }
  26766. $sequence = [];
  26767. for ($i = $startIndex; $i < $endIndex - 1; ++$i) {
  26768. if ($tokens[$i]->isComment()) {
  26769. continue;
  26770. }
  26771. if (!$tokens[$i]->isWhitespace() && !$tokens[$i]->isGivenKind($tokenKinds)) {
  26772. break;
  26773. }
  26774. $sequence[] = clone $tokens[$i];
  26775. }
  26776. return $sequence;
  26777. }
  26778. }
  26779. <?php
  26780. namespace PhpCsFixer\Fixer\ClassNotation;
  26781. use PhpCsFixer\AbstractFixer;
  26782. use PhpCsFixer\FixerDefinition\CodeSample;
  26783. use PhpCsFixer\FixerDefinition\FixerDefinition;
  26784. use PhpCsFixer\Tokenizer\Tokens;
  26785. final class NoNullPropertyInitializationFixer extends AbstractFixer
  26786. {
  26787. public function getDefinition()
  26788. {
  26789. return new FixerDefinition(
  26790. 'Properties MUST not be explicitly initialized with `null` except when they have a type declaration (PHP 7.4).',
  26791. [
  26792. new CodeSample(
  26793. '<?php
  26794. class Foo {
  26795. public $foo = null;
  26796. }
  26797. '
  26798. ),
  26799. ]
  26800. );
  26801. }
  26802. public function isCandidate(Tokens $tokens)
  26803. {
  26804. return $tokens->isAnyTokenKindsFound([T_CLASS, T_TRAIT]) && $tokens->isAnyTokenKindsFound([T_PUBLIC, T_PROTECTED, T_PRIVATE, T_VAR]);
  26805. }
  26806. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  26807. {
  26808. for ($index = 0, $count = $tokens->count(); $index < $count; ++$index) {
  26809. if (!$tokens[$index]->isGivenKind([T_PUBLIC, T_PROTECTED, T_PRIVATE, T_VAR])) {
  26810. continue;
  26811. }
  26812. while (true) {
  26813. $varTokenIndex = $index = $tokens->getNextMeaningfulToken($index);
  26814. if (!$tokens[$index]->isGivenKind(T_VARIABLE)) {
  26815. break;
  26816. }
  26817. $index = $tokens->getNextMeaningfulToken($index);
  26818. if ($tokens[$index]->equals('=')) {
  26819. $index = $tokens->getNextMeaningfulToken($index);
  26820. if ($tokens[$index]->isGivenKind(T_NS_SEPARATOR)) {
  26821. $index = $tokens->getNextMeaningfulToken($index);
  26822. }
  26823. if ($tokens[$index]->equals([T_STRING, 'null'], false)) {
  26824. for ($i = $varTokenIndex + 1; $i <= $index; ++$i) {
  26825. if (
  26826. !($tokens[$i]->isWhitespace() && false !== strpos($tokens[$i]->getContent(), "\n"))
  26827. && !$tokens[$i]->isComment()
  26828. ) {
  26829. $tokens->clearAt($i);
  26830. }
  26831. }
  26832. }
  26833. ++$index;
  26834. }
  26835. if (!$tokens[$index]->equals(',')) {
  26836. break;
  26837. }
  26838. }
  26839. }
  26840. }
  26841. }
  26842. <?php
  26843. namespace PhpCsFixer\Fixer\ClassNotation;
  26844. use PhpCsFixer\AbstractProxyFixer;
  26845. use PhpCsFixer\FixerDefinition\CodeSample;
  26846. use PhpCsFixer\FixerDefinition\FixerDefinition;
  26847. final class FinalClassFixer extends AbstractProxyFixer
  26848. {
  26849. public function getDefinition()
  26850. {
  26851. return new FixerDefinition(
  26852. 'All classes must be final, except abstract ones and Doctrine entities.',
  26853. [
  26854. new CodeSample(
  26855. '<?php
  26856. class MyApp {}
  26857. '
  26858. ),
  26859. ],
  26860. '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. '
  26861. .'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. '
  26862. .'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. '
  26863. .'If you need to extend a standalone class, create an interface and use the Composite pattern. '
  26864. .'If you aren\'t ready yet for serious OOP, go with FinalInternalClassFixer, it\'s fine.',
  26865. 'Risky when subclassing non-abstract classes.'
  26866. );
  26867. }
  26868. protected function createProxyFixers()
  26869. {
  26870. $fixer = new FinalInternalClassFixer();
  26871. $fixer->configure([
  26872. 'annotation-white-list' => [],
  26873. 'consider-absent-docblock-as-internal-class' => true,
  26874. ]);
  26875. return [$fixer];
  26876. }
  26877. }
  26878. <?php
  26879. namespace PhpCsFixer\Fixer\ClassNotation;
  26880. use PhpCsFixer\AbstractFixer;
  26881. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  26882. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  26883. use PhpCsFixer\FixerConfiguration\AllowedValueSubset;
  26884. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  26885. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  26886. use PhpCsFixer\FixerDefinition\CodeSample;
  26887. use PhpCsFixer\FixerDefinition\FixerDefinition;
  26888. use PhpCsFixer\Preg;
  26889. use PhpCsFixer\Tokenizer\CT;
  26890. use PhpCsFixer\Tokenizer\Token;
  26891. use PhpCsFixer\Tokenizer\Tokens;
  26892. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  26893. use SplFileInfo;
  26894. final class ClassAttributesSeparationFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface, WhitespacesAwareFixerInterface
  26895. {
  26896. private $classElementTypes = [];
  26897. public function configure(array $configuration = null)
  26898. {
  26899. parent::configure($configuration);
  26900. $this->classElementTypes = [];
  26901. foreach ($this->configuration['elements'] as $element) {
  26902. $this->classElementTypes[$element] = true;
  26903. }
  26904. }
  26905. public function getDefinition()
  26906. {
  26907. return new FixerDefinition(
  26908. 'Class, trait and interface elements must be separated with one blank line.',
  26909. [
  26910. new CodeSample(
  26911. '<?php
  26912. final class Sample
  26913. {
  26914. protected function foo()
  26915. {
  26916. }
  26917. protected function bar()
  26918. {
  26919. }
  26920. }
  26921. '
  26922. ),
  26923. new CodeSample(
  26924. '<?php
  26925. class Sample
  26926. {private $a; // a is awesome
  26927. /** second in a hour */
  26928. private $b;
  26929. }
  26930. ',
  26931. ['elements' => ['property']]
  26932. ),
  26933. new CodeSample(
  26934. '<?php
  26935. class Sample
  26936. {
  26937. const A = 1;
  26938. /** seconds in some hours */
  26939. const B = 3600;
  26940. }
  26941. ',
  26942. ['elements' => ['const']]
  26943. ),
  26944. ]
  26945. );
  26946. }
  26947. public function getPriority()
  26948. {
  26949. return 55;
  26950. }
  26951. public function isCandidate(Tokens $tokens)
  26952. {
  26953. return $tokens->isAnyTokenKindsFound(Token::getClassyTokenKinds());
  26954. }
  26955. protected function applyFix(SplFileInfo $file, Tokens $tokens)
  26956. {
  26957. $tokensAnalyzer = new TokensAnalyzer($tokens);
  26958. $class = $classStart = $classEnd = false;
  26959. foreach (array_reverse($tokensAnalyzer->getClassyElements(), true) as $index => $element) {
  26960. if (!isset($this->classElementTypes[$element['type']])) {
  26961. continue;
  26962. }
  26963. if ($element['classIndex'] !== $class) {
  26964. $class = $element['classIndex'];
  26965. $classStart = $tokens->getNextTokenOfKind($class, ['{']);
  26966. $classEnd = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $classStart);
  26967. }
  26968. if ('method' === $element['type'] && !$tokens[$class]->isGivenKind(T_INTERFACE)) {
  26969. $attributes = $tokensAnalyzer->getMethodAttributes($index);
  26970. $methodEnd = true === $attributes['abstract']
  26971. ? $tokens->getNextTokenOfKind($index, [';'])
  26972. : $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $tokens->getNextTokenOfKind($index, ['{']))
  26973. ;
  26974. $this->fixSpaceBelowClassMethod($tokens, $classEnd, $methodEnd);
  26975. $this->fixSpaceAboveClassElement($tokens, $classStart, $index);
  26976. continue;
  26977. }
  26978. $this->fixSpaceBelowClassElement($tokens, $classEnd, $tokens->getNextTokenOfKind($index, [';']));
  26979. $this->fixSpaceAboveClassElement($tokens, $classStart, $index);
  26980. }
  26981. }
  26982. protected function createConfigurationDefinition()
  26983. {
  26984. $types = ['const', 'method', 'property'];
  26985. return new FixerConfigurationResolver([
  26986. (new FixerOptionBuilder('elements', sprintf('List of classy elements; \'%s\'.', implode("', '", $types))))
  26987. ->setAllowedTypes(['array'])
  26988. ->setAllowedValues([new AllowedValueSubset($types)])
  26989. ->setDefault(['const', 'method', 'property'])
  26990. ->getOption(),
  26991. ]);
  26992. }
  26993. private function fixSpaceBelowClassElement(Tokens $tokens, $classEndIndex, $elementEndIndex)
  26994. {
  26995. for ($nextNotWhite = $elementEndIndex + 1;; ++$nextNotWhite) {
  26996. if (($tokens[$nextNotWhite]->isComment() || $tokens[$nextNotWhite]->isWhitespace()) && false === strpos($tokens[$nextNotWhite]->getContent(), "\n")) {
  26997. continue;
  26998. }
  26999. break;
  27000. }
  27001. if ($tokens[$nextNotWhite]->isWhitespace()) {
  27002. $nextNotWhite = $tokens->getNextNonWhitespace($nextNotWhite);
  27003. }
  27004. $this->correctLineBreaks($tokens, $elementEndIndex, $nextNotWhite, $nextNotWhite === $classEndIndex ? 1 : 2);
  27005. }
  27006. private function fixSpaceBelowClassMethod(Tokens $tokens, $classEndIndex, $elementEndIndex)
  27007. {
  27008. $nextNotWhite = $tokens->getNextNonWhitespace($elementEndIndex);
  27009. $this->correctLineBreaks($tokens, $elementEndIndex, $nextNotWhite, $nextNotWhite === $classEndIndex ? 1 : 2);
  27010. }
  27011. private function fixSpaceAboveClassElement(Tokens $tokens, $classStartIndex, $elementIndex)
  27012. {
  27013. static $methodAttr = [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];
  27014. $nonWhiteAbove = null;
  27015. $firstElementAttributeIndex = $elementIndex;
  27016. for ($i = $elementIndex; $i > $classStartIndex; --$i) {
  27017. $nonWhiteAbove = $tokens->getNonWhitespaceSibling($i, -1);
  27018. if (null !== $nonWhiteAbove && $tokens[$nonWhiteAbove]->isGivenKind($methodAttr)) {
  27019. $firstElementAttributeIndex = $nonWhiteAbove;
  27020. } else {
  27021. break;
  27022. }
  27023. }
  27024. if ($tokens[$nonWhiteAbove]->isGivenKind(T_COMMENT)) {
  27025. if (1 === $firstElementAttributeIndex - $nonWhiteAbove) {
  27026. $this->correctLineBreaks($tokens, $nonWhiteAbove, $firstElementAttributeIndex, 1);
  27027. return;
  27028. }
  27029. if (substr_count($tokens[$nonWhiteAbove + 1]->getContent(), "\n") > 1) {
  27030. $this->correctLineBreaks($tokens, $nonWhiteAbove, $firstElementAttributeIndex, 2);
  27031. return;
  27032. }
  27033. if ($tokens[$nonWhiteAbove - 1]->isWhitespace() && substr_count($tokens[$nonWhiteAbove - 1]->getContent(), "\n") > 0) {
  27034. $this->correctLineBreaks($tokens, $nonWhiteAbove, $firstElementAttributeIndex, 1);
  27035. $nonWhiteAbove = $this->findCommentBlockStart($tokens, $nonWhiteAbove);
  27036. $nonWhiteAboveComment = $tokens->getNonWhitespaceSibling($nonWhiteAbove, -1);
  27037. $this->correctLineBreaks($tokens, $nonWhiteAboveComment, $nonWhiteAbove, $nonWhiteAboveComment === $classStartIndex ? 1 : 2);
  27038. } else {
  27039. $this->correctLineBreaks($tokens, $nonWhiteAbove, $firstElementAttributeIndex, 2);
  27040. }
  27041. return;
  27042. }
  27043. if (false === $tokens[$nonWhiteAbove]->isGivenKind(T_DOC_COMMENT)) {
  27044. $this->correctLineBreaks($tokens, $nonWhiteAbove, $firstElementAttributeIndex, $nonWhiteAbove === $classStartIndex ? 1 : 2);
  27045. return;
  27046. }
  27047. $this->correctLineBreaks($tokens, $nonWhiteAbove, $firstElementAttributeIndex, 1);
  27048. $nonWhiteAbovePHPDoc = $tokens->getNonWhitespaceSibling($nonWhiteAbove, -1);
  27049. $this->correctLineBreaks($tokens, $nonWhiteAbovePHPDoc, $nonWhiteAbove, $nonWhiteAbovePHPDoc === $classStartIndex ? 1 : 2);
  27050. }
  27051. private function correctLineBreaks(Tokens $tokens, $startIndex, $endIndex, $reqLineCount = 2)
  27052. {
  27053. $lineEnding = $this->whitespacesConfig->getLineEnding();
  27054. ++$startIndex;
  27055. $numbOfWhiteTokens = $endIndex - $startIndex;
  27056. if (0 === $numbOfWhiteTokens) {
  27057. $tokens->insertAt($startIndex, new Token([T_WHITESPACE, str_repeat($lineEnding, $reqLineCount)]));
  27058. return;
  27059. }
  27060. $lineBreakCount = $this->getLineBreakCount($tokens, $startIndex, $endIndex);
  27061. if ($reqLineCount === $lineBreakCount) {
  27062. return;
  27063. }
  27064. if ($lineBreakCount < $reqLineCount) {
  27065. $tokens[$startIndex] = new Token([
  27066. T_WHITESPACE,
  27067. str_repeat($lineEnding, $reqLineCount - $lineBreakCount).$tokens[$startIndex]->getContent(),
  27068. ]);
  27069. return;
  27070. }
  27071. if (1 === $numbOfWhiteTokens) {
  27072. $tokens[$startIndex] = new Token([
  27073. T_WHITESPACE,
  27074. Preg::replace('/\r\n|\n/', '', $tokens[$startIndex]->getContent(), $lineBreakCount - $reqLineCount),
  27075. ]);
  27076. return;
  27077. }
  27078. $toReplaceCount = $lineBreakCount - $reqLineCount;
  27079. for ($i = $startIndex; $i < $endIndex && $toReplaceCount > 0; ++$i) {
  27080. $tokenLineCount = substr_count($tokens[$i]->getContent(), "\n");
  27081. if ($tokenLineCount > 0) {
  27082. $tokens[$i] = new Token([
  27083. T_WHITESPACE,
  27084. Preg::replace('/\r\n|\n/', '', $tokens[$i]->getContent(), min($toReplaceCount, $tokenLineCount)),
  27085. ]);
  27086. $toReplaceCount -= $tokenLineCount;
  27087. }
  27088. }
  27089. }
  27090. private function getLineBreakCount(Tokens $tokens, $whiteSpaceStartIndex, $whiteSpaceEndIndex)
  27091. {
  27092. $lineCount = 0;
  27093. for ($i = $whiteSpaceStartIndex; $i < $whiteSpaceEndIndex; ++$i) {
  27094. $lineCount += substr_count($tokens[$i]->getContent(), "\n");
  27095. }
  27096. return $lineCount;
  27097. }
  27098. private function findCommentBlockStart(Tokens $tokens, $commentIndex)
  27099. {
  27100. $start = $commentIndex;
  27101. for ($i = $commentIndex - 1; $i > 0; --$i) {
  27102. if ($tokens[$i]->isComment()) {
  27103. $start = $i;
  27104. continue;
  27105. }
  27106. if (!$tokens[$i]->isWhitespace() || $this->getLineBreakCount($tokens, $i, $i + 1) > 1) {
  27107. break;
  27108. }
  27109. }
  27110. return $start;
  27111. }
  27112. }
  27113. <?php
  27114. namespace PhpCsFixer\Fixer\ClassNotation;
  27115. use PhpCsFixer\AbstractFixer;
  27116. use PhpCsFixer\FixerDefinition\CodeSample;
  27117. use PhpCsFixer\FixerDefinition\FixerDefinition;
  27118. use PhpCsFixer\Tokenizer\Token;
  27119. use PhpCsFixer\Tokenizer\Tokens;
  27120. final class FinalStaticAccessFixer extends AbstractFixer
  27121. {
  27122. public function getDefinition()
  27123. {
  27124. return new FixerDefinition(
  27125. 'Converts `static` access to `self` access in `final` classes.',
  27126. [
  27127. new CodeSample(
  27128. '<?php
  27129. final class Sample
  27130. {
  27131. public function getFoo()
  27132. {
  27133. return static::class;
  27134. }
  27135. }
  27136. '
  27137. ),
  27138. ]
  27139. );
  27140. }
  27141. public function getPriority()
  27142. {
  27143. return -1;
  27144. }
  27145. public function isCandidate(Tokens $tokens)
  27146. {
  27147. return $tokens->isAllTokenKindsFound([T_FINAL, T_CLASS, T_STATIC]);
  27148. }
  27149. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  27150. {
  27151. for ($index = $tokens->count() - 1; 0 <= $index; --$index) {
  27152. if (!$tokens[$index]->isGivenKind(T_FINAL)) {
  27153. continue;
  27154. }
  27155. $classTokenIndex = $tokens->getNextMeaningfulToken($index);
  27156. if (!$tokens[$classTokenIndex]->isGivenKind(T_CLASS)) {
  27157. continue;
  27158. }
  27159. $startClassIndex = $tokens->getNextTokenOfKind(
  27160. $classTokenIndex,
  27161. ['{']
  27162. );
  27163. $endClassIndex = $tokens->findBlockEnd(
  27164. Tokens::BLOCK_TYPE_CURLY_BRACE,
  27165. $startClassIndex
  27166. );
  27167. $this->replaceStaticAccessWithSelfAccessBetween(
  27168. $tokens,
  27169. $startClassIndex,
  27170. $endClassIndex
  27171. );
  27172. }
  27173. }
  27174. private function replaceStaticAccessWithSelfAccessBetween(
  27175. Tokens $tokens,
  27176. $startIndex,
  27177. $endIndex
  27178. ) {
  27179. for ($index = $startIndex; $index <= $endIndex; ++$index) {
  27180. if ($tokens[$index]->isGivenKind(T_CLASS)) {
  27181. $index = $this->getEndOfAnonymousClass($tokens, $index);
  27182. continue;
  27183. }
  27184. if (!$tokens[$index]->isGivenKind(T_STATIC)) {
  27185. continue;
  27186. }
  27187. $doubleColonIndex = $tokens->getNextMeaningfulToken($index);
  27188. if (!$tokens[$doubleColonIndex]->isGivenKind(T_DOUBLE_COLON)) {
  27189. continue;
  27190. }
  27191. $tokens[$index] = new Token([T_STRING, 'self']);
  27192. }
  27193. }
  27194. private function getEndOfAnonymousClass(Tokens $tokens, $index)
  27195. {
  27196. $instantiationBraceStart = $tokens->getNextMeaningfulToken($index);
  27197. if ($tokens[$instantiationBraceStart]->equals('(')) {
  27198. $index = $tokens->findBlockEnd(
  27199. Tokens::BLOCK_TYPE_PARENTHESIS_BRACE,
  27200. $instantiationBraceStart
  27201. );
  27202. }
  27203. $bodyBraceStart = $tokens->getNextTokenOfKind($index, ['{']);
  27204. return $tokens->findBlockEnd(
  27205. Tokens::BLOCK_TYPE_CURLY_BRACE,
  27206. $bodyBraceStart
  27207. );
  27208. }
  27209. }
  27210. <?php
  27211. namespace PhpCsFixer\Fixer\ClassNotation;
  27212. use PhpCsFixer\AbstractFixer;
  27213. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  27214. use PhpCsFixer\FixerDefinition\CodeSample;
  27215. use PhpCsFixer\FixerDefinition\FixerDefinition;
  27216. use PhpCsFixer\Tokenizer\Token;
  27217. use PhpCsFixer\Tokenizer\Tokens;
  27218. final class NoBlankLinesAfterClassOpeningFixer extends AbstractFixer implements WhitespacesAwareFixerInterface
  27219. {
  27220. public function isCandidate(Tokens $tokens)
  27221. {
  27222. return $tokens->isAnyTokenKindsFound(Token::getClassyTokenKinds());
  27223. }
  27224. public function getDefinition()
  27225. {
  27226. return new FixerDefinition(
  27227. 'There should be no empty lines after class opening brace.',
  27228. [
  27229. new CodeSample(
  27230. '<?php
  27231. final class Sample
  27232. {
  27233. protected function foo()
  27234. {
  27235. }
  27236. }
  27237. '
  27238. ),
  27239. ]
  27240. );
  27241. }
  27242. public function getPriority()
  27243. {
  27244. return 0;
  27245. }
  27246. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  27247. {
  27248. foreach ($tokens as $index => $token) {
  27249. if (!$token->isClassy()) {
  27250. continue;
  27251. }
  27252. $startBraceIndex = $tokens->getNextTokenOfKind($index, ['{']);
  27253. if (!$tokens[$startBraceIndex + 1]->isWhitespace()) {
  27254. continue;
  27255. }
  27256. $this->fixWhitespace($tokens, $startBraceIndex + 1);
  27257. }
  27258. }
  27259. private function fixWhitespace(Tokens $tokens, $index)
  27260. {
  27261. $content = $tokens[$index]->getContent();
  27262. if (substr_count($content, "\n") > 1) {
  27263. $tokens[$index] = new Token([T_WHITESPACE, $this->whitespacesConfig->getLineEnding().substr($content, strrpos($content, "\n") + 1)]);
  27264. }
  27265. }
  27266. }
  27267. <?php
  27268. namespace PhpCsFixer\Fixer\ClassNotation;
  27269. use PhpCsFixer\AbstractFixer;
  27270. use PhpCsFixer\ConfigurationException\InvalidFixerConfigurationException;
  27271. use PhpCsFixer\DocBlock\DocBlock;
  27272. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  27273. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  27274. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  27275. use PhpCsFixer\FixerDefinition\CodeSample;
  27276. use PhpCsFixer\FixerDefinition\FixerDefinition;
  27277. use PhpCsFixer\Preg;
  27278. use PhpCsFixer\Tokenizer\Token;
  27279. use PhpCsFixer\Tokenizer\Tokens;
  27280. use Symfony\Component\OptionsResolver\Options;
  27281. final class FinalInternalClassFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface
  27282. {
  27283. public function configure(array $configuration = null)
  27284. {
  27285. parent::configure($configuration);
  27286. $intersect = array_intersect_assoc(
  27287. $this->configuration['annotation-white-list'],
  27288. $this->configuration['annotation-black-list']
  27289. );
  27290. if (\count($intersect)) {
  27291. throw new InvalidFixerConfigurationException($this->getName(), sprintf('Annotation cannot be used in both the include and exclude list, got duplicates: "%s".', implode('", "', array_keys($intersect))));
  27292. }
  27293. }
  27294. public function getDefinition()
  27295. {
  27296. return new FixerDefinition(
  27297. 'Internal classes should be `final`.',
  27298. [
  27299. new CodeSample("<?php\n/**\n * @internal\n */\nclass Sample\n{\n}\n"),
  27300. new CodeSample(
  27301. "<?php\n/** @CUSTOM */class A{}\n",
  27302. [
  27303. 'annotation-white-list' => ['@Custom'],
  27304. ]
  27305. ),
  27306. ],
  27307. null,
  27308. 'Changing classes to `final` might cause code execution to break.'
  27309. );
  27310. }
  27311. public function getPriority()
  27312. {
  27313. return 67;
  27314. }
  27315. public function isCandidate(Tokens $tokens)
  27316. {
  27317. return $tokens->isTokenKindFound(T_CLASS);
  27318. }
  27319. public function isRisky()
  27320. {
  27321. return true;
  27322. }
  27323. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  27324. {
  27325. for ($index = $tokens->count() - 1; 0 <= $index; --$index) {
  27326. if (!$tokens[$index]->isGivenKind(T_CLASS) || !$this->isClassCandidate($tokens, $index)) {
  27327. continue;
  27328. }
  27329. $tokens->insertAt(
  27330. $index,
  27331. [
  27332. new Token([T_FINAL, 'final']),
  27333. new Token([T_WHITESPACE, ' ']),
  27334. ]
  27335. );
  27336. }
  27337. }
  27338. protected function createConfigurationDefinition()
  27339. {
  27340. $annotationsAsserts = [static function (array $values) {
  27341. foreach ($values as $value) {
  27342. if (!\is_string($value) || '' === $value) {
  27343. return false;
  27344. }
  27345. }
  27346. return true;
  27347. }];
  27348. $annotationsNormalizer = static function (Options $options, array $value) {
  27349. $newValue = [];
  27350. foreach ($value as $key) {
  27351. if ('@' === $key[0]) {
  27352. $key = substr($key, 1);
  27353. }
  27354. $newValue[strtolower($key)] = true;
  27355. }
  27356. return $newValue;
  27357. };
  27358. return new FixerConfigurationResolver([
  27359. (new FixerOptionBuilder('annotation-white-list', 'Class level annotations tags that must be set in order to fix the class. (case insensitive)'))
  27360. ->setAllowedTypes(['array'])
  27361. ->setAllowedValues($annotationsAsserts)
  27362. ->setDefault(['@internal'])
  27363. ->setNormalizer($annotationsNormalizer)
  27364. ->getOption(),
  27365. (new FixerOptionBuilder('annotation-black-list', 'Class level annotations tags that must be omitted to fix the class, even if all of the excluded ones are used as well. (case insensitive)'))
  27366. ->setAllowedTypes(['array'])
  27367. ->setAllowedValues($annotationsAsserts)
  27368. ->setDefault([
  27369. '@final',
  27370. '@Entity',
  27371. '@ORM\Entity',
  27372. '@ORM\Mapping\Entity',
  27373. '@Mapping\Entity',
  27374. ])
  27375. ->setNormalizer($annotationsNormalizer)
  27376. ->getOption(),
  27377. (new FixerOptionBuilder('consider-absent-docblock-as-internal-class', 'Should classes without any DocBlock be fixed to final?'))
  27378. ->setAllowedTypes(['bool'])
  27379. ->setDefault(false)
  27380. ->getOption(),
  27381. ]);
  27382. }
  27383. private function isClassCandidate(Tokens $tokens, $index)
  27384. {
  27385. if ($tokens[$tokens->getPrevMeaningfulToken($index)]->isGivenKind([T_ABSTRACT, T_FINAL, T_NEW])) {
  27386. return false;
  27387. }
  27388. $docToken = $tokens[$tokens->getPrevNonWhitespace($index)];
  27389. if (!$docToken->isGivenKind(T_DOC_COMMENT)) {
  27390. return $this->configuration['consider-absent-docblock-as-internal-class'];
  27391. }
  27392. $doc = new DocBlock($docToken->getContent());
  27393. $tags = [];
  27394. foreach ($doc->getAnnotations() as $annotation) {
  27395. Preg::match('/@\S+(?=\s|$)/', $annotation->getContent(), $matches);
  27396. $tag = strtolower(substr(array_shift($matches), 1));
  27397. foreach ($this->configuration['annotation-black-list'] as $tagStart => $true) {
  27398. if (0 === strpos($tag, $tagStart)) {
  27399. return false;
  27400. }
  27401. }
  27402. $tags[$tag] = true;
  27403. }
  27404. foreach ($this->configuration['annotation-white-list'] as $tag => $true) {
  27405. if (!isset($tags[$tag])) {
  27406. return false;
  27407. }
  27408. }
  27409. return true;
  27410. }
  27411. }
  27412. <?php
  27413. namespace PhpCsFixer\Fixer\ClassNotation;
  27414. use PhpCsFixer\AbstractFixer;
  27415. use PhpCsFixer\FixerDefinition\CodeSample;
  27416. use PhpCsFixer\FixerDefinition\FixerDefinition;
  27417. use PhpCsFixer\Tokenizer\Token;
  27418. use PhpCsFixer\Tokenizer\Tokens;
  27419. final class FinalPublicMethodForAbstractClassFixer extends AbstractFixer
  27420. {
  27421. private $magicMethods = [
  27422. '__construct' => true,
  27423. '__destruct' => true,
  27424. '__call' => true,
  27425. '__callstatic' => true,
  27426. '__get' => true,
  27427. '__set' => true,
  27428. '__isset' => true,
  27429. '__unset' => true,
  27430. '__sleep' => true,
  27431. '__wakeup' => true,
  27432. '__tostring' => true,
  27433. '__invoke' => true,
  27434. '__set_state' => true,
  27435. '__clone' => true,
  27436. '__debuginfo' => true,
  27437. ];
  27438. public function getDefinition()
  27439. {
  27440. return new FixerDefinition(
  27441. 'All `public` methods of `abstract` classes should be `final`.',
  27442. [
  27443. new CodeSample(
  27444. '<?php
  27445. abstract class AbstractMachine
  27446. {
  27447. public function start()
  27448. {}
  27449. }
  27450. '
  27451. ),
  27452. ],
  27453. 'Enforce API encapsulation in an inheritance architecture. '
  27454. .'If you want to override a method, use the Template method pattern.',
  27455. 'Risky when overriding `public` methods of `abstract` classes.'
  27456. );
  27457. }
  27458. public function isCandidate(Tokens $tokens)
  27459. {
  27460. return $tokens->isAllTokenKindsFound([T_CLASS, T_ABSTRACT, T_PUBLIC, T_FUNCTION]);
  27461. }
  27462. public function isRisky()
  27463. {
  27464. return true;
  27465. }
  27466. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  27467. {
  27468. $classes = array_keys($tokens->findGivenKind(T_CLASS));
  27469. while ($classIndex = array_pop($classes)) {
  27470. $prevToken = $tokens[$tokens->getPrevMeaningfulToken($classIndex)];
  27471. if (!$prevToken->isGivenKind([T_ABSTRACT])) {
  27472. continue;
  27473. }
  27474. $classOpen = $tokens->getNextTokenOfKind($classIndex, ['{']);
  27475. $classClose = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $classOpen);
  27476. $this->fixClass($tokens, $classOpen, $classClose);
  27477. }
  27478. }
  27479. private function fixClass(Tokens $tokens, $classOpenIndex, $classCloseIndex)
  27480. {
  27481. for ($index = $classCloseIndex - 1; $index > $classOpenIndex; --$index) {
  27482. if ($tokens[$index]->equals('}')) {
  27483. $index = $tokens->findBlockStart(Tokens::BLOCK_TYPE_CURLY_BRACE, $index);
  27484. continue;
  27485. }
  27486. if (!$tokens[$index]->isGivenKind(T_PUBLIC)) {
  27487. continue;
  27488. }
  27489. $nextIndex = $tokens->getNextMeaningfulToken($index);
  27490. $nextToken = $tokens[$nextIndex];
  27491. if ($nextToken->isGivenKind(T_STATIC)) {
  27492. $nextIndex = $tokens->getNextMeaningfulToken($nextIndex);
  27493. $nextToken = $tokens[$nextIndex];
  27494. }
  27495. if (!$nextToken->isGivenKind(T_FUNCTION)) {
  27496. continue;
  27497. }
  27498. $nextIndex = $tokens->getNextMeaningfulToken($nextIndex);
  27499. $nextToken = $tokens[$nextIndex];
  27500. if (isset($this->magicMethods[strtolower($nextToken->getContent())])) {
  27501. continue;
  27502. }
  27503. $prevIndex = $tokens->getPrevMeaningfulToken($index);
  27504. $prevToken = $tokens[$prevIndex];
  27505. if ($prevToken->isGivenKind(T_STATIC)) {
  27506. $index = $prevIndex;
  27507. $prevIndex = $tokens->getPrevMeaningfulToken($index);
  27508. $prevToken = $tokens[$prevIndex];
  27509. }
  27510. if ($prevToken->isGivenKind([T_ABSTRACT, T_FINAL])) {
  27511. $index = $prevIndex;
  27512. continue;
  27513. }
  27514. $tokens->insertAt(
  27515. $index,
  27516. [
  27517. new Token([T_FINAL, 'final']),
  27518. new Token([T_WHITESPACE, ' ']),
  27519. ]
  27520. );
  27521. }
  27522. }
  27523. }
  27524. <?php
  27525. namespace PhpCsFixer\Fixer\ClassUsage;
  27526. use PhpCsFixer\AbstractFixer;
  27527. use PhpCsFixer\FixerDefinition\CodeSample;
  27528. use PhpCsFixer\FixerDefinition\FixerDefinition;
  27529. use PhpCsFixer\Tokenizer\Token;
  27530. use PhpCsFixer\Tokenizer\Tokens;
  27531. final class DateTimeImmutableFixer extends AbstractFixer
  27532. {
  27533. public function getDefinition()
  27534. {
  27535. return new FixerDefinition(
  27536. 'Class `DateTimeImmutable` should be used instead of `DateTime`.',
  27537. [new CodeSample("<?php\nnew DateTime();\n")],
  27538. null,
  27539. 'Risky when the code relies on modifying `DateTime` objects or if any of the `date_create*` functions are overridden.'
  27540. );
  27541. }
  27542. public function isCandidate(Tokens $tokens)
  27543. {
  27544. return $tokens->isTokenKindFound(T_STRING);
  27545. }
  27546. public function isRisky()
  27547. {
  27548. return true;
  27549. }
  27550. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  27551. {
  27552. $isInNamespace = false;
  27553. $isImported = false;
  27554. for ($index = 0, $limit = $tokens->count(); $index < $limit; ++$index) {
  27555. $token = $tokens[$index];
  27556. if ($token->isGivenKind(T_NAMESPACE)) {
  27557. $isInNamespace = true;
  27558. continue;
  27559. }
  27560. if ($token->isGivenKind(T_USE) && $isInNamespace) {
  27561. $nextIndex = $tokens->getNextMeaningfulToken($index);
  27562. if ('datetime' !== strtolower($tokens[$nextIndex]->getContent())) {
  27563. continue;
  27564. }
  27565. $nextNextIndex = $tokens->getNextMeaningfulToken($nextIndex);
  27566. if ($tokens[$nextNextIndex]->equals(';')) {
  27567. $isImported = true;
  27568. }
  27569. $index = $nextNextIndex;
  27570. continue;
  27571. }
  27572. if (!$token->isGivenKind(T_STRING)) {
  27573. continue;
  27574. }
  27575. $lowercaseContent = strtolower($token->getContent());
  27576. if ('datetime' === $lowercaseContent) {
  27577. $this->fixClassUsage($tokens, $index, $isInNamespace, $isImported);
  27578. $limit = $tokens->count();
  27579. } elseif ('date_create' === $lowercaseContent) {
  27580. $this->fixFunctionUsage($tokens, $index, 'date_create_immutable');
  27581. } elseif ('date_create_from_format' === $lowercaseContent) {
  27582. $this->fixFunctionUsage($tokens, $index, 'date_create_immutable_from_format');
  27583. }
  27584. }
  27585. }
  27586. private function fixClassUsage(Tokens $tokens, $index, $isInNamespace, $isImported)
  27587. {
  27588. $nextIndex = $tokens->getNextMeaningfulToken($index);
  27589. if ($tokens[$nextIndex]->isGivenKind(T_DOUBLE_COLON)) {
  27590. $nextNextIndex = $tokens->getNextMeaningfulToken($nextIndex);
  27591. if ($tokens[$nextNextIndex]->isGivenKind(T_STRING)) {
  27592. $nextNextNextIndex = $tokens->getNextMeaningfulToken($nextNextIndex);
  27593. if (!$tokens[$nextNextNextIndex]->equals('(')) {
  27594. return;
  27595. }
  27596. }
  27597. }
  27598. $isUsedAlone = false;
  27599. $isUsedWithLeadingBackslash = false;
  27600. $prevIndex = $tokens->getPrevMeaningfulToken($index);
  27601. if ($tokens[$prevIndex]->isGivenKind(T_NS_SEPARATOR)) {
  27602. $prevPrevIndex = $tokens->getPrevMeaningfulToken($prevIndex);
  27603. if (!$tokens[$prevPrevIndex]->isGivenKind(T_STRING)) {
  27604. $isUsedWithLeadingBackslash = true;
  27605. }
  27606. } elseif (!$tokens[$prevIndex]->isGivenKind([T_DOUBLE_COLON, T_OBJECT_OPERATOR])) {
  27607. $isUsedAlone = true;
  27608. }
  27609. if ($isUsedWithLeadingBackslash || $isUsedAlone && ($isInNamespace && $isImported || !$isInNamespace)) {
  27610. $tokens[$index] = new Token([T_STRING, \DateTimeImmutable::class]);
  27611. if ($isInNamespace && $isUsedAlone) {
  27612. $tokens->insertAt($index, new Token([T_NS_SEPARATOR, '\\']));
  27613. }
  27614. }
  27615. }
  27616. private function fixFunctionUsage(Tokens $tokens, $index, $replacement)
  27617. {
  27618. $prevIndex = $tokens->getPrevMeaningfulToken($index);
  27619. if ($tokens[$prevIndex]->isGivenKind([T_DOUBLE_COLON, T_NEW, T_OBJECT_OPERATOR])) {
  27620. return;
  27621. }
  27622. if ($tokens[$prevIndex]->isGivenKind(T_NS_SEPARATOR)) {
  27623. $prevPrevIndex = $tokens->getPrevMeaningfulToken($prevIndex);
  27624. if ($tokens[$prevPrevIndex]->isGivenKind([T_NEW, T_STRING])) {
  27625. return;
  27626. }
  27627. }
  27628. $tokens[$index] = new Token([T_STRING, $replacement]);
  27629. }
  27630. }
  27631. <?php
  27632. namespace PhpCsFixer\Fixer\StringNotation;
  27633. use PhpCsFixer\AbstractFixer;
  27634. use PhpCsFixer\FixerDefinition\CodeSample;
  27635. use PhpCsFixer\FixerDefinition\FixerDefinition;
  27636. use PhpCsFixer\Tokenizer\Token;
  27637. use PhpCsFixer\Tokenizer\Tokens;
  27638. final class NoBinaryStringFixer extends AbstractFixer
  27639. {
  27640. public function isCandidate(Tokens $tokens)
  27641. {
  27642. return $tokens->isAnyTokenKindsFound([T_CONSTANT_ENCAPSED_STRING, T_START_HEREDOC]);
  27643. }
  27644. public function getDefinition()
  27645. {
  27646. return new FixerDefinition(
  27647. 'There should not be a binary flag before strings.',
  27648. [
  27649. new CodeSample("<?php \$a = b'foo';\n"),
  27650. new CodeSample("<?php \$a = b<<<EOT\nfoo\nEOT;\n"),
  27651. ]
  27652. );
  27653. }
  27654. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  27655. {
  27656. foreach ($tokens as $index => $token) {
  27657. if (!$token->isGivenKind([T_CONSTANT_ENCAPSED_STRING, T_START_HEREDOC])) {
  27658. continue;
  27659. }
  27660. $content = $token->getContent();
  27661. if ('b' === strtolower($content[0])) {
  27662. $tokens[$index] = new Token([$token->getId(), substr($content, 1)]);
  27663. }
  27664. }
  27665. }
  27666. }
  27667. <?php
  27668. namespace PhpCsFixer\Fixer\StringNotation;
  27669. use PhpCsFixer\AbstractFixer;
  27670. use PhpCsFixer\FixerDefinition\CodeSample;
  27671. use PhpCsFixer\FixerDefinition\FixerDefinition;
  27672. use PhpCsFixer\Tokenizer\CT;
  27673. use PhpCsFixer\Tokenizer\Token;
  27674. use PhpCsFixer\Tokenizer\Tokens;
  27675. final class SimpleToComplexStringVariableFixer extends AbstractFixer
  27676. {
  27677. public function getDefinition()
  27678. {
  27679. return new FixerDefinition(
  27680. 'Converts explicit variables in double-quoted strings and heredoc syntax from simple to complex format (`${` to `{$`).',
  27681. [
  27682. new CodeSample(
  27683. <<<'EOT'
  27684. <?php
  27685. $name = 'World';
  27686. echo "Hello ${name}!";
  27687. EOT
  27688. ),
  27689. new CodeSample(
  27690. <<<'EOT'
  27691. <?php
  27692. $name = 'World';
  27693. echo <<<TEST
  27694. Hello ${name}!
  27695. TEST;
  27696. EOT
  27697. ),
  27698. ],
  27699. "Doesn't touch implicit variables. Works together nicely with `explicit_string_variable`."
  27700. );
  27701. }
  27702. public function getPriority()
  27703. {
  27704. return -10;
  27705. }
  27706. public function isCandidate(Tokens $tokens)
  27707. {
  27708. return $tokens->isTokenKindFound(T_DOLLAR_OPEN_CURLY_BRACES);
  27709. }
  27710. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  27711. {
  27712. for ($index = \count($tokens) - 3; $index > 0; --$index) {
  27713. $token = $tokens[$index];
  27714. if (!$token->isGivenKind(T_DOLLAR_OPEN_CURLY_BRACES)) {
  27715. continue;
  27716. }
  27717. $varnameToken = $tokens[$index + 1];
  27718. if (!$varnameToken->isGivenKind(T_STRING_VARNAME)) {
  27719. continue;
  27720. }
  27721. $dollarCloseToken = $tokens[$index + 2];
  27722. if (!$dollarCloseToken->isGivenKind(CT::T_DOLLAR_CLOSE_CURLY_BRACES)) {
  27723. continue;
  27724. }
  27725. $tokenOfStringBeforeToken = $tokens[$index - 1];
  27726. $stringContent = $tokenOfStringBeforeToken->getContent();
  27727. if ('$' === substr($stringContent, -1) && '\\$' !== substr($stringContent, -2)) {
  27728. $newContent = substr($stringContent, 0, -1).'\\$';
  27729. $tokenOfStringBeforeToken = new Token([T_ENCAPSED_AND_WHITESPACE, $newContent]);
  27730. }
  27731. $tokens->overrideRange($index - 1, $index + 2, [
  27732. $tokenOfStringBeforeToken,
  27733. new Token([T_CURLY_OPEN, '{']),
  27734. new Token([T_VARIABLE, '$'.$varnameToken->getContent()]),
  27735. new Token([CT::T_CURLY_CLOSE, '}']),
  27736. ]);
  27737. }
  27738. }
  27739. }
  27740. <?php
  27741. namespace PhpCsFixer\Fixer\StringNotation;
  27742. use PhpCsFixer\AbstractFixer;
  27743. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  27744. use PhpCsFixer\FixerDefinition\CodeSample;
  27745. use PhpCsFixer\FixerDefinition\FixerDefinition;
  27746. use PhpCsFixer\Preg;
  27747. use PhpCsFixer\Tokenizer\Token;
  27748. use PhpCsFixer\Tokenizer\Tokens;
  27749. final class StringLineEndingFixer extends AbstractFixer implements WhitespacesAwareFixerInterface
  27750. {
  27751. public function isCandidate(Tokens $tokens)
  27752. {
  27753. return $tokens->isAnyTokenKindsFound([T_CONSTANT_ENCAPSED_STRING, T_ENCAPSED_AND_WHITESPACE, T_INLINE_HTML]);
  27754. }
  27755. public function isRisky()
  27756. {
  27757. return true;
  27758. }
  27759. public function getDefinition()
  27760. {
  27761. return new FixerDefinition(
  27762. 'All multi-line strings must use correct line ending.',
  27763. [
  27764. new CodeSample(
  27765. "<?php \$a = 'my\r\nmulti\nline\r\nstring';\r\n"
  27766. ),
  27767. ],
  27768. null,
  27769. 'Changing the line endings of multi-line strings might affect string comparisons and outputs.'
  27770. );
  27771. }
  27772. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  27773. {
  27774. $ending = $this->whitespacesConfig->getLineEnding();
  27775. foreach ($tokens as $tokenIndex => $token) {
  27776. if (!$token->isGivenKind([T_CONSTANT_ENCAPSED_STRING, T_ENCAPSED_AND_WHITESPACE, T_INLINE_HTML])) {
  27777. continue;
  27778. }
  27779. $tokens[$tokenIndex] = new Token([
  27780. $token->getId(),
  27781. Preg::replace(
  27782. '#\R#u',
  27783. $ending,
  27784. $token->getContent()
  27785. ),
  27786. ]);
  27787. }
  27788. }
  27789. }
  27790. <?php
  27791. namespace PhpCsFixer\Fixer\StringNotation;
  27792. use PhpCsFixer\AbstractFixer;
  27793. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  27794. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  27795. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  27796. use PhpCsFixer\FixerDefinition\CodeSample;
  27797. use PhpCsFixer\FixerDefinition\FixerDefinition;
  27798. use PhpCsFixer\Preg;
  27799. use PhpCsFixer\Tokenizer\Token;
  27800. use PhpCsFixer\Tokenizer\Tokens;
  27801. final class SingleQuoteFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface
  27802. {
  27803. public function getDefinition()
  27804. {
  27805. $codeSample = <<<'EOF'
  27806. <?php
  27807. $a = "sample";
  27808. $b = "sample with 'single-quotes'";
  27809. EOF;
  27810. return new FixerDefinition(
  27811. 'Convert double quotes to single quotes for simple strings.',
  27812. [
  27813. new CodeSample($codeSample),
  27814. new CodeSample(
  27815. $codeSample,
  27816. ['strings_containing_single_quote_chars' => true]
  27817. ),
  27818. ]
  27819. );
  27820. }
  27821. public function getPriority()
  27822. {
  27823. return 0;
  27824. }
  27825. public function isCandidate(Tokens $tokens)
  27826. {
  27827. return $tokens->isTokenKindFound(T_CONSTANT_ENCAPSED_STRING);
  27828. }
  27829. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  27830. {
  27831. foreach ($tokens as $index => $token) {
  27832. if (!$token->isGivenKind(T_CONSTANT_ENCAPSED_STRING)) {
  27833. continue;
  27834. }
  27835. $content = $token->getContent();
  27836. $prefix = '';
  27837. if ('b' === strtolower($content[0])) {
  27838. $prefix = $content[0];
  27839. $content = substr($content, 1);
  27840. }
  27841. if (
  27842. '"' === $content[0] &&
  27843. (true === $this->configuration['strings_containing_single_quote_chars'] || false === strpos($content, "'")) &&
  27844. !Preg::match('/(?<!\\\\)(?:\\\\{2})*\\\\(?!["$\\\\])/', $content)
  27845. ) {
  27846. $content = substr($content, 1, -1);
  27847. $content = str_replace(['\\"', '\\$', '\''], ['"', '$', '\\\''], $content);
  27848. $tokens[$index] = new Token([T_CONSTANT_ENCAPSED_STRING, $prefix.'\''.$content.'\'']);
  27849. }
  27850. }
  27851. }
  27852. protected function createConfigurationDefinition()
  27853. {
  27854. return new FixerConfigurationResolver([
  27855. (new FixerOptionBuilder('strings_containing_single_quote_chars', 'Whether to fix double-quoted strings that contains single-quotes.'))
  27856. ->setAllowedTypes(['bool'])
  27857. ->setDefault(false)
  27858. ->getOption(),
  27859. ]);
  27860. }
  27861. }
  27862. <?php
  27863. namespace PhpCsFixer\Fixer\StringNotation;
  27864. use PhpCsFixer\AbstractFixer;
  27865. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  27866. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  27867. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  27868. use PhpCsFixer\FixerDefinition\CodeSample;
  27869. use PhpCsFixer\FixerDefinition\FixerDefinition;
  27870. use PhpCsFixer\Preg;
  27871. use PhpCsFixer\Tokenizer\Token;
  27872. use PhpCsFixer\Tokenizer\Tokens;
  27873. final class EscapeImplicitBackslashesFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface
  27874. {
  27875. public function getDefinition()
  27876. {
  27877. $codeSample = <<<'EOF'
  27878. <?php
  27879. $singleQuoted = 'String with \" and My\Prefix\\';
  27880. $doubleQuoted = "Interpret my \n but not my \a";
  27881. $hereDoc = <<<HEREDOC
  27882. Interpret my \100 but not my \999
  27883. HEREDOC;
  27884. EOF;
  27885. return new FixerDefinition(
  27886. 'Escape implicit backslashes in strings and heredocs to ease the understanding of which are special chars interpreted by PHP and which not.',
  27887. [
  27888. new CodeSample($codeSample),
  27889. new CodeSample(
  27890. $codeSample,
  27891. ['single_quoted' => true]
  27892. ),
  27893. new CodeSample(
  27894. $codeSample,
  27895. ['double_quoted' => false]
  27896. ),
  27897. new CodeSample(
  27898. $codeSample,
  27899. ['heredoc_syntax' => false]
  27900. ),
  27901. ],
  27902. 'In PHP double-quoted strings and heredocs some chars like `n`, `$` or `u` have special meanings if preceded by a backslash '
  27903. .'(and some are special only if followed by other special chars), while a backslash preceding other chars are interpreted like a plain '
  27904. .'backslash. The precise list of those special chars is hard to remember and to identify quickly: this fixer escapes backslashes '
  27905. ."that do not start a special interpretation with the char after them.\n"
  27906. .'It is possible to fix also single-quoted strings: in this case there is no special chars apart from single-quote and backslash '
  27907. .'itself, so the fixer simply ensure that all backslashes are escaped. Both single and double backslashes are allowed in single-quoted '
  27908. .'strings, so the purpose in this context is mainly to have a uniformed way to have them written all over the codebase.'
  27909. );
  27910. }
  27911. public function isCandidate(Tokens $tokens)
  27912. {
  27913. return $tokens->isAnyTokenKindsFound([T_ENCAPSED_AND_WHITESPACE, T_CONSTANT_ENCAPSED_STRING]);
  27914. }
  27915. public function getPriority()
  27916. {
  27917. return 1;
  27918. }
  27919. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  27920. {
  27921. static $singleQuotedRegex = '/(?<!\\\\)\\\\((?:\\\\\\\\)*)(?![\\\'\\\\])/';
  27922. static $doubleQuotedRegex = '/(?<!\\\\)\\\\((?:\\\\\\\\)*)(?![efnrtv$"\\\\0-7]|x[0-9A-Fa-f]|u{)/';
  27923. static $heredocSyntaxRegex = '/(?<!\\\\)\\\\((?:\\\\\\\\)*)(?![efnrtv$\\\\0-7]|x[0-9A-Fa-f]|u{)/';
  27924. $doubleQuoteOpened = false;
  27925. foreach ($tokens as $index => $token) {
  27926. $content = $token->getContent();
  27927. if ($token->equalsAny(['"', 'b"', 'B"'])) {
  27928. $doubleQuoteOpened = !$doubleQuoteOpened;
  27929. }
  27930. if (!$token->isGivenKind([T_ENCAPSED_AND_WHITESPACE, T_CONSTANT_ENCAPSED_STRING]) || false === strpos($content, '\\')) {
  27931. continue;
  27932. }
  27933. if ($token->isGivenKind(T_ENCAPSED_AND_WHITESPACE) && '\'' === substr(rtrim($tokens[$index - 1]->getContent()), -1)) {
  27934. continue;
  27935. }
  27936. $firstTwoCharacters = strtolower(substr($content, 0, 2));
  27937. $isSingleQuotedString = $token->isGivenKind(T_CONSTANT_ENCAPSED_STRING) && ('\'' === $content[0] || 'b\'' === $firstTwoCharacters);
  27938. $isDoubleQuotedString =
  27939. ($token->isGivenKind(T_CONSTANT_ENCAPSED_STRING) && ('"' === $content[0] || 'b"' === $firstTwoCharacters))
  27940. || ($token->isGivenKind(T_ENCAPSED_AND_WHITESPACE) && $doubleQuoteOpened)
  27941. ;
  27942. $isHeredocSyntax = !$isSingleQuotedString && !$isDoubleQuotedString;
  27943. if (
  27944. (false === $this->configuration['single_quoted'] && $isSingleQuotedString)
  27945. || (false === $this->configuration['double_quoted'] && $isDoubleQuotedString)
  27946. || (false === $this->configuration['heredoc_syntax'] && $isHeredocSyntax)
  27947. ) {
  27948. continue;
  27949. }
  27950. $regex = $heredocSyntaxRegex;
  27951. if ($isSingleQuotedString) {
  27952. $regex = $singleQuotedRegex;
  27953. } elseif ($isDoubleQuotedString) {
  27954. $regex = $doubleQuotedRegex;
  27955. }
  27956. $newContent = Preg::replace($regex, '\\\\\\\\$1', $content);
  27957. if ($newContent !== $content) {
  27958. $tokens[$index] = new Token([$token->getId(), $newContent]);
  27959. }
  27960. }
  27961. }
  27962. protected function createConfigurationDefinition()
  27963. {
  27964. return new FixerConfigurationResolver([
  27965. (new FixerOptionBuilder('single_quoted', 'Whether to fix single-quoted strings.'))
  27966. ->setAllowedTypes(['bool'])
  27967. ->setDefault(false)
  27968. ->getOption(),
  27969. (new FixerOptionBuilder('double_quoted', 'Whether to fix double-quoted strings.'))
  27970. ->setAllowedTypes(['bool'])
  27971. ->setDefault(true)
  27972. ->getOption(),
  27973. (new FixerOptionBuilder('heredoc_syntax', 'Whether to fix heredoc syntax.'))
  27974. ->setAllowedTypes(['bool'])
  27975. ->setDefault(true)
  27976. ->getOption(),
  27977. ]);
  27978. }
  27979. }
  27980. <?php
  27981. namespace PhpCsFixer\Fixer\StringNotation;
  27982. use PhpCsFixer\AbstractFixer;
  27983. use PhpCsFixer\FixerDefinition\CodeSample;
  27984. use PhpCsFixer\FixerDefinition\FixerDefinition;
  27985. use PhpCsFixer\Preg;
  27986. use PhpCsFixer\Tokenizer\Token;
  27987. use PhpCsFixer\Tokenizer\Tokens;
  27988. final class HeredocToNowdocFixer extends AbstractFixer
  27989. {
  27990. public function getDefinition()
  27991. {
  27992. return new FixerDefinition(
  27993. 'Convert `heredoc` to `nowdoc` where possible.',
  27994. [
  27995. new CodeSample(
  27996. <<<'EOF'
  27997. <?php $a = <<<"TEST"
  27998. Foo
  27999. TEST;
  28000. EOF
  28001. ),
  28002. ]
  28003. );
  28004. }
  28005. public function getPriority()
  28006. {
  28007. return 0;
  28008. }
  28009. public function isCandidate(Tokens $tokens)
  28010. {
  28011. return $tokens->isTokenKindFound(T_START_HEREDOC);
  28012. }
  28013. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  28014. {
  28015. foreach ($tokens as $index => $token) {
  28016. if (!$token->isGivenKind(T_START_HEREDOC) || false !== strpos($token->getContent(), "'")) {
  28017. continue;
  28018. }
  28019. if ($tokens[$index + 1]->isGivenKind(T_END_HEREDOC)) {
  28020. $tokens[$index] = $this->convertToNowdoc($token);
  28021. continue;
  28022. }
  28023. if (
  28024. !$tokens[$index + 1]->isGivenKind(T_ENCAPSED_AND_WHITESPACE) ||
  28025. !$tokens[$index + 2]->isGivenKind(T_END_HEREDOC)
  28026. ) {
  28027. continue;
  28028. }
  28029. $content = $tokens[$index + 1]->getContent();
  28030. if (Preg::match('/(?<!\\\\)(?:\\\\{2})*\\\\(?![$\\\\])/', $content)) {
  28031. continue;
  28032. }
  28033. $tokens[$index] = $this->convertToNowdoc($token);
  28034. $content = str_replace(['\\\\', '\\$'], ['\\', '$'], $content);
  28035. $tokens[$index + 1] = new Token([
  28036. $tokens[$index + 1]->getId(),
  28037. $content,
  28038. ]);
  28039. }
  28040. }
  28041. private function convertToNowdoc(Token $token)
  28042. {
  28043. return new Token([
  28044. $token->getId(),
  28045. Preg::replace('/^([Bb]?<<<)(\h*)"?([^\s"]+)"?/', '$1$2\'$3\'', $token->getContent()),
  28046. ]);
  28047. }
  28048. }
  28049. <?php
  28050. namespace PhpCsFixer\Fixer\StringNotation;
  28051. use PhpCsFixer\AbstractFixer;
  28052. use PhpCsFixer\FixerDefinition\CodeSample;
  28053. use PhpCsFixer\FixerDefinition\FixerDefinition;
  28054. use PhpCsFixer\Tokenizer\CT;
  28055. use PhpCsFixer\Tokenizer\Token;
  28056. use PhpCsFixer\Tokenizer\Tokens;
  28057. final class ExplicitStringVariableFixer extends AbstractFixer
  28058. {
  28059. public function getDefinition()
  28060. {
  28061. return new FixerDefinition(
  28062. 'Converts implicit variables into explicit ones in double-quoted strings or heredoc syntax.',
  28063. [new CodeSample(
  28064. <<<'EOT'
  28065. <?php
  28066. $a = "My name is $name !";
  28067. $b = "I live in $state->country !";
  28068. $c = "I have $farm[0] chickens !";
  28069. EOT
  28070. )],
  28071. 'The reasoning behind this rule is the following:'
  28072. ."\n".'- When there are two valid ways of doing the same thing, using both is confusing, there should be a coding standard to follow'
  28073. ."\n".'- PHP manual marks `"$var"` syntax as implicit and `"${var}"` syntax as explicit: explicit code should always be preferred'
  28074. ."\n".'- Explicit syntax allows word concatenation inside strings, e.g. `"${var}IsAVar"`, implicit doesn\'t'
  28075. ."\n".'- Explicit syntax is easier to detect for IDE/editors and therefore has colors/highlight with higher contrast, which is easier to read'
  28076. ."\n".'Backtick operator is skipped because it is harder to handle; you can use `backtick_to_shell_exec` fixer to normalize backticks to strings'
  28077. );
  28078. }
  28079. public function getPriority()
  28080. {
  28081. return 0;
  28082. }
  28083. public function isCandidate(Tokens $tokens)
  28084. {
  28085. return $tokens->isTokenKindFound(T_VARIABLE);
  28086. }
  28087. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  28088. {
  28089. $backtickStarted = false;
  28090. for ($index = \count($tokens) - 1; $index > 0; --$index) {
  28091. $token = $tokens[$index];
  28092. if ($token->equals('`')) {
  28093. $backtickStarted = !$backtickStarted;
  28094. continue;
  28095. }
  28096. if ($backtickStarted || !$token->isGivenKind(T_VARIABLE)) {
  28097. continue;
  28098. }
  28099. $prevToken = $tokens[$index - 1];
  28100. if (!$this->isStringPartToken($prevToken)) {
  28101. continue;
  28102. }
  28103. $distinctVariableIndex = $index;
  28104. $variableTokens = [
  28105. $distinctVariableIndex => [
  28106. 'tokens' => [$index => $token],
  28107. 'firstVariableTokenIndex' => $index,
  28108. 'lastVariableTokenIndex' => $index,
  28109. ],
  28110. ];
  28111. $nextIndex = $index + 1;
  28112. $squareBracketCount = 0;
  28113. while (!$this->isStringPartToken($tokens[$nextIndex])) {
  28114. if ($tokens[$nextIndex]->isGivenKind(T_CURLY_OPEN)) {
  28115. $nextIndex = $tokens->getNextTokenOfKind($nextIndex, [[CT::T_CURLY_CLOSE]]);
  28116. } elseif ($tokens[$nextIndex]->isGivenKind(T_VARIABLE) && 1 !== $squareBracketCount) {
  28117. $distinctVariableIndex = $nextIndex;
  28118. $variableTokens[$distinctVariableIndex] = [
  28119. 'tokens' => [$nextIndex => $tokens[$nextIndex]],
  28120. 'firstVariableTokenIndex' => $nextIndex,
  28121. 'lastVariableTokenIndex' => $nextIndex,
  28122. ];
  28123. } else {
  28124. $variableTokens[$distinctVariableIndex]['tokens'][$nextIndex] = $tokens[$nextIndex];
  28125. $variableTokens[$distinctVariableIndex]['lastVariableTokenIndex'] = $nextIndex;
  28126. if ($tokens[$nextIndex]->equalsAny(['[', ']'])) {
  28127. ++$squareBracketCount;
  28128. }
  28129. }
  28130. ++$nextIndex;
  28131. }
  28132. krsort($variableTokens, \SORT_NUMERIC);
  28133. foreach ($variableTokens as $distinctVariableSet) {
  28134. if (1 === \count($distinctVariableSet['tokens'])) {
  28135. $singleVariableIndex = key($distinctVariableSet['tokens']);
  28136. $singleVariableToken = current($distinctVariableSet['tokens']);
  28137. $tokens->overrideRange($singleVariableIndex, $singleVariableIndex, [
  28138. new Token([T_DOLLAR_OPEN_CURLY_BRACES, '${']),
  28139. new Token([T_STRING_VARNAME, substr($singleVariableToken->getContent(), 1)]),
  28140. new Token([CT::T_DOLLAR_CLOSE_CURLY_BRACES, '}']),
  28141. ]);
  28142. } else {
  28143. foreach ($distinctVariableSet['tokens'] as $variablePartIndex => $variablePartToken) {
  28144. if ($variablePartToken->isGivenKind(T_NUM_STRING)) {
  28145. $tokens[$variablePartIndex] = new Token([T_LNUMBER, $variablePartToken->getContent()]);
  28146. continue;
  28147. }
  28148. if ($variablePartToken->isGivenKind(T_STRING) && $tokens[$variablePartIndex + 1]->equals(']')) {
  28149. $tokens[$variablePartIndex] = new Token([T_CONSTANT_ENCAPSED_STRING, "'".$variablePartToken->getContent()."'"]);
  28150. }
  28151. }
  28152. $tokens->insertAt($distinctVariableSet['lastVariableTokenIndex'] + 1, new Token([CT::T_CURLY_CLOSE, '}']));
  28153. $tokens->insertAt($distinctVariableSet['firstVariableTokenIndex'], new Token([T_CURLY_OPEN, '{']));
  28154. }
  28155. }
  28156. }
  28157. }
  28158. private function isStringPartToken(Token $token)
  28159. {
  28160. return $token->isGivenKind(T_ENCAPSED_AND_WHITESPACE)
  28161. || $token->isGivenKind(T_START_HEREDOC)
  28162. || '"' === $token->getContent()
  28163. || 'b"' === strtolower($token->getContent())
  28164. ;
  28165. }
  28166. }
  28167. <?php
  28168. namespace PhpCsFixer\Fixer\FunctionNotation;
  28169. use PhpCsFixer\AbstractFixer;
  28170. use PhpCsFixer\FixerDefinition\CodeSample;
  28171. use PhpCsFixer\FixerDefinition\FixerDefinition;
  28172. use PhpCsFixer\Tokenizer\CT;
  28173. use PhpCsFixer\Tokenizer\Token;
  28174. use PhpCsFixer\Tokenizer\Tokens;
  28175. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  28176. final class StaticLambdaFixer extends AbstractFixer
  28177. {
  28178. public function getDefinition()
  28179. {
  28180. return new FixerDefinition(
  28181. 'Lambdas not (indirect) referencing `$this` must be declared `static`.',
  28182. [new CodeSample("<?php\n\$a = function () use (\$b)\n{ echo \$b;\n};\n")],
  28183. null,
  28184. 'Risky when using `->bindTo` on lambdas without referencing to `$this`.'
  28185. );
  28186. }
  28187. public function isCandidate(Tokens $tokens)
  28188. {
  28189. if (\PHP_VERSION_ID >= 70400 && $tokens->isTokenKindFound(T_FN)) {
  28190. return true;
  28191. }
  28192. return $tokens->isTokenKindFound(T_FUNCTION);
  28193. }
  28194. public function isRisky()
  28195. {
  28196. return true;
  28197. }
  28198. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  28199. {
  28200. $analyzer = new TokensAnalyzer($tokens);
  28201. $expectedFunctionKinds = [T_FUNCTION];
  28202. if (\PHP_VERSION_ID >= 70400) {
  28203. $expectedFunctionKinds[] = T_FN;
  28204. }
  28205. for ($index = $tokens->count() - 4; $index > 0; --$index) {
  28206. if (!$tokens[$index]->isGivenKind($expectedFunctionKinds) || !$analyzer->isLambda($index)) {
  28207. continue;
  28208. }
  28209. $prev = $tokens->getPrevMeaningfulToken($index);
  28210. if ($tokens[$prev]->isGivenKind(T_STATIC)) {
  28211. continue;
  28212. }
  28213. $argumentsStartIndex = $tokens->getNextTokenOfKind($index, ['(']);
  28214. $argumentsEndIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $argumentsStartIndex);
  28215. $lambdaOpenIndex = $tokens->getNextTokenOfKind($argumentsEndIndex, ['{', [T_DOUBLE_ARROW]]);
  28216. if ($tokens[$lambdaOpenIndex]->isGivenKind(T_DOUBLE_ARROW)) {
  28217. $lambdaEndIndex = $tokens->getNextTokenOfKind($lambdaOpenIndex, [';']);
  28218. } else {
  28219. $lambdaEndIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $lambdaOpenIndex);
  28220. }
  28221. if ($this->hasPossibleReferenceToThis($tokens, $lambdaOpenIndex, $lambdaEndIndex)) {
  28222. continue;
  28223. }
  28224. $tokens->insertAt(
  28225. $index,
  28226. [
  28227. new Token([T_STATIC, 'static']),
  28228. new Token([T_WHITESPACE, ' ']),
  28229. ]
  28230. );
  28231. $index -= 4;
  28232. }
  28233. }
  28234. private function hasPossibleReferenceToThis(Tokens $tokens, $startIndex, $endIndex)
  28235. {
  28236. for ($i = $startIndex; $i < $endIndex; ++$i) {
  28237. if ($tokens[$i]->isGivenKind(T_VARIABLE) && '$this' === strtolower($tokens[$i]->getContent())) {
  28238. return true;
  28239. }
  28240. if ($tokens[$i]->isGivenKind([
  28241. T_INCLUDE,
  28242. T_INCLUDE_ONCE,
  28243. T_REQUIRE,
  28244. T_REQUIRE_ONCE,
  28245. CT::T_DYNAMIC_VAR_BRACE_OPEN,
  28246. T_EVAL,
  28247. ])) {
  28248. return true;
  28249. }
  28250. if ($tokens[$i]->equals('$')) {
  28251. $nextIndex = $tokens->getNextMeaningfulToken($i);
  28252. if ($tokens[$nextIndex]->isGivenKind(T_VARIABLE)) {
  28253. return true;
  28254. }
  28255. }
  28256. }
  28257. return false;
  28258. }
  28259. }
  28260. <?php
  28261. namespace PhpCsFixer\Fixer\FunctionNotation;
  28262. use PhpCsFixer\AbstractFixer;
  28263. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  28264. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  28265. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  28266. use PhpCsFixer\FixerDefinition\FixerDefinition;
  28267. use PhpCsFixer\FixerDefinition\VersionSpecification;
  28268. use PhpCsFixer\FixerDefinition\VersionSpecificCodeSample;
  28269. use PhpCsFixer\Tokenizer\Analyzer\Analysis\ArgumentAnalysis;
  28270. use PhpCsFixer\Tokenizer\Analyzer\FunctionsAnalyzer;
  28271. use PhpCsFixer\Tokenizer\CT;
  28272. use PhpCsFixer\Tokenizer\Token;
  28273. use PhpCsFixer\Tokenizer\Tokens;
  28274. final class NullableTypeDeclarationForDefaultNullValueFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface
  28275. {
  28276. public function getDefinition()
  28277. {
  28278. return new FixerDefinition(
  28279. 'Adds or removes `?` before type declarations for parameters with a default `null` value.',
  28280. [
  28281. new VersionSpecificCodeSample(
  28282. "<?php\nfunction sample(string \$str = null)\n{}\n",
  28283. new VersionSpecification(70100)
  28284. ),
  28285. new VersionSpecificCodeSample(
  28286. "<?php\nfunction sample(?string \$str = null)\n{}\n",
  28287. new VersionSpecification(70100),
  28288. ['use_nullable_type_declaration' => false]
  28289. ),
  28290. ],
  28291. 'Rule is applied only in a PHP 7.1+ environment.'
  28292. );
  28293. }
  28294. public function isCandidate(Tokens $tokens)
  28295. {
  28296. if (\PHP_VERSION_ID < 70100) {
  28297. return false;
  28298. }
  28299. if (!$tokens->isTokenKindFound(T_VARIABLE)) {
  28300. return false;
  28301. }
  28302. if (\PHP_VERSION_ID >= 70400 && $tokens->isTokenKindFound(T_FN)) {
  28303. return true;
  28304. }
  28305. return $tokens->isTokenKindFound(T_FUNCTION);
  28306. }
  28307. public function getPriority()
  28308. {
  28309. return 1;
  28310. }
  28311. protected function createConfigurationDefinition()
  28312. {
  28313. return new FixerConfigurationResolver([
  28314. (new FixerOptionBuilder('use_nullable_type_declaration', 'Whether to add or remove `?` before type declarations for parameters with a default `null` value.'))
  28315. ->setAllowedTypes(['bool'])
  28316. ->setDefault(true)
  28317. ->getOption(),
  28318. ]);
  28319. }
  28320. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  28321. {
  28322. $functionsAnalyzer = new FunctionsAnalyzer();
  28323. $tokenKinds = [T_FUNCTION];
  28324. if (\PHP_VERSION_ID >= 70400) {
  28325. $tokenKinds[] = T_FN;
  28326. }
  28327. for ($index = $tokens->count() - 1; $index >= 0; --$index) {
  28328. $token = $tokens[$index];
  28329. if (!$token->isGivenKind($tokenKinds)) {
  28330. continue;
  28331. }
  28332. $arguments = $functionsAnalyzer->getFunctionArguments($tokens, $index);
  28333. $this->fixFunctionParameters($tokens, $arguments);
  28334. }
  28335. }
  28336. private function fixFunctionParameters(Tokens $tokens, array $arguments)
  28337. {
  28338. foreach (array_reverse($arguments) as $argumentInfo) {
  28339. if (
  28340. !$argumentInfo->hasTypeAnalysis()
  28341. || !$argumentInfo->hasDefault()
  28342. || 'null' !== strtolower($argumentInfo->getDefault())
  28343. ) {
  28344. continue;
  28345. }
  28346. $argumentTypeInfo = $argumentInfo->getTypeAnalysis();
  28347. if (true === $this->configuration['use_nullable_type_declaration']) {
  28348. if (!$argumentTypeInfo->isNullable()) {
  28349. $tokens->insertAt($argumentTypeInfo->getStartIndex(), new Token([CT::T_NULLABLE_TYPE, '?']));
  28350. }
  28351. } else {
  28352. if ($argumentTypeInfo->isNullable()) {
  28353. $tokens->removeTrailingWhitespace($argumentTypeInfo->getStartIndex());
  28354. $tokens->clearTokenAndMergeSurroundingWhitespace($argumentTypeInfo->getStartIndex());
  28355. }
  28356. }
  28357. }
  28358. }
  28359. }
  28360. <?php
  28361. namespace PhpCsFixer\Fixer\FunctionNotation;
  28362. use PhpCsFixer\AbstractFixer;
  28363. use PhpCsFixer\FixerDefinition\CodeSample;
  28364. use PhpCsFixer\FixerDefinition\FixerDefinition;
  28365. use PhpCsFixer\Tokenizer\Analyzer\ArgumentsAnalyzer;
  28366. use PhpCsFixer\Tokenizer\Analyzer\FunctionsAnalyzer;
  28367. use PhpCsFixer\Tokenizer\Token;
  28368. use PhpCsFixer\Tokenizer\Tokens;
  28369. final class ImplodeCallFixer extends AbstractFixer
  28370. {
  28371. public function getDefinition()
  28372. {
  28373. return new FixerDefinition(
  28374. 'Function `implode` must be called with 2 arguments in the documented order.',
  28375. [
  28376. new CodeSample("<?php\nimplode(\$pieces, '');\n"),
  28377. new CodeSample("<?php\nimplode(\$pieces);\n"),
  28378. ],
  28379. null,
  28380. 'Risky when the function `implode` is overridden.'
  28381. );
  28382. }
  28383. public function isRisky()
  28384. {
  28385. return true;
  28386. }
  28387. public function isCandidate(Tokens $tokens)
  28388. {
  28389. return $tokens->isTokenKindFound(T_STRING);
  28390. }
  28391. public function getPriority()
  28392. {
  28393. return -1;
  28394. }
  28395. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  28396. {
  28397. $functionsAnalyzer = new FunctionsAnalyzer();
  28398. for ($index = \count($tokens) - 1; $index > 0; --$index) {
  28399. if (!$tokens[$index]->equals([T_STRING, 'implode'], false)) {
  28400. continue;
  28401. }
  28402. if (!$functionsAnalyzer->isGlobalFunctionCall($tokens, $index)) {
  28403. continue;
  28404. }
  28405. $argumentsIndices = $this->getArgumentIndices($tokens, $index);
  28406. if (1 === \count($argumentsIndices)) {
  28407. $firstArgumentIndex = key($argumentsIndices);
  28408. $tokens->insertAt($firstArgumentIndex, [
  28409. new Token([T_CONSTANT_ENCAPSED_STRING, "''"]),
  28410. new Token(','),
  28411. new Token([T_WHITESPACE, ' ']),
  28412. ]);
  28413. continue;
  28414. }
  28415. if (2 === \count($argumentsIndices)) {
  28416. list($firstArgumentIndex, $secondArgumentIndex) = array_keys($argumentsIndices);
  28417. if ($tokens[$firstArgumentIndex]->isGivenKind(T_CONSTANT_ENCAPSED_STRING)) {
  28418. continue;
  28419. }
  28420. if (!$tokens[$secondArgumentIndex]->isGivenKind(T_CONSTANT_ENCAPSED_STRING)) {
  28421. continue;
  28422. }
  28423. $firstArgumentEndIndex = $argumentsIndices[key($argumentsIndices)];
  28424. $newSecondArgumentTokens = [];
  28425. for ($i = key($argumentsIndices); $i <= $firstArgumentEndIndex; ++$i) {
  28426. $newSecondArgumentTokens[] = clone $tokens[$i];
  28427. $tokens->clearAt($i);
  28428. }
  28429. $tokens->insertAt($firstArgumentIndex, clone $tokens[$secondArgumentIndex]);
  28430. ++$secondArgumentIndex;
  28431. $tokens->clearAt($secondArgumentIndex);
  28432. $tokens->insertAt($secondArgumentIndex, $newSecondArgumentTokens);
  28433. }
  28434. }
  28435. }
  28436. private function getArgumentIndices(Tokens $tokens, $functionNameIndex)
  28437. {
  28438. $argumentsAnalyzer = new ArgumentsAnalyzer();
  28439. $openParenthesis = $tokens->getNextTokenOfKind($functionNameIndex, ['(']);
  28440. $closeParenthesis = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $openParenthesis);
  28441. $indices = [];
  28442. foreach ($argumentsAnalyzer->getArguments($tokens, $openParenthesis, $closeParenthesis) as $startIndexCandidate => $endIndex) {
  28443. $indices[$tokens->getNextMeaningfulToken($startIndexCandidate - 1)] = $tokens->getPrevMeaningfulToken($endIndex + 1);
  28444. }
  28445. return $indices;
  28446. }
  28447. }
  28448. <?php
  28449. namespace PhpCsFixer\Fixer\FunctionNotation;
  28450. use PhpCsFixer\AbstractFixer;
  28451. use PhpCsFixer\FixerDefinition\CodeSample;
  28452. use PhpCsFixer\FixerDefinition\FixerDefinition;
  28453. use PhpCsFixer\Tokenizer\CT;
  28454. use PhpCsFixer\Tokenizer\Tokens;
  28455. /**
  28456. @gmail
  28457. */
  28458. final class NoSpacesAfterFunctionNameFixer extends AbstractFixer
  28459. {
  28460. public function getDefinition()
  28461. {
  28462. return new FixerDefinition(
  28463. 'When making a method or function call, there MUST NOT be a space between the method or function name and the opening parenthesis.',
  28464. [new CodeSample("<?php\nrequire ('sample.php');\necho (test (3));\nexit (1);\n\$func ();\n")]
  28465. );
  28466. }
  28467. public function getPriority()
  28468. {
  28469. return 2;
  28470. }
  28471. public function isCandidate(Tokens $tokens)
  28472. {
  28473. return $tokens->isAnyTokenKindsFound(array_merge($this->getFunctionyTokenKinds(), [T_STRING]));
  28474. }
  28475. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  28476. {
  28477. $functionyTokens = $this->getFunctionyTokenKinds();
  28478. $languageConstructionTokens = $this->getLanguageConstructionTokenKinds();
  28479. $braceTypes = $this->getBraceAfterVariableKinds();
  28480. foreach ($tokens as $index => $token) {
  28481. if (!$token->equals('(')) {
  28482. continue;
  28483. }
  28484. $lastTokenIndex = $tokens->getPrevNonWhitespace($index);
  28485. $endParenthesisIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $index);
  28486. $nextNonWhiteSpace = $tokens->getNextMeaningfulToken($endParenthesisIndex);
  28487. if (
  28488. null !== $nextNonWhiteSpace
  28489. && $tokens[$nextNonWhiteSpace]->equals('?')
  28490. && $tokens[$lastTokenIndex]->isGivenKind($languageConstructionTokens)
  28491. ) {
  28492. continue;
  28493. }
  28494. if ($tokens[$lastTokenIndex]->isGivenKind($functionyTokens)) {
  28495. $this->fixFunctionCall($tokens, $index);
  28496. } elseif ($tokens[$lastTokenIndex]->isGivenKind(T_STRING)) {
  28497. $possibleDefinitionIndex = $tokens->getPrevMeaningfulToken($lastTokenIndex);
  28498. if (!$tokens[$possibleDefinitionIndex]->isGivenKind(T_FUNCTION)) {
  28499. $this->fixFunctionCall($tokens, $index);
  28500. }
  28501. } elseif ($tokens[$lastTokenIndex]->equalsAny($braceTypes)) {
  28502. $block = Tokens::detectBlockType($tokens[$lastTokenIndex]);
  28503. if (
  28504. Tokens::BLOCK_TYPE_ARRAY_INDEX_CURLY_BRACE === $block['type']
  28505. || Tokens::BLOCK_TYPE_DYNAMIC_VAR_BRACE === $block['type']
  28506. || Tokens::BLOCK_TYPE_INDEX_SQUARE_BRACE === $block['type']
  28507. || Tokens::BLOCK_TYPE_PARENTHESIS_BRACE === $block['type']
  28508. ) {
  28509. $this->fixFunctionCall($tokens, $index);
  28510. }
  28511. }
  28512. }
  28513. }
  28514. private function fixFunctionCall(Tokens $tokens, $index)
  28515. {
  28516. if ($tokens[$index - 1]->isWhitespace()) {
  28517. $tokens->clearAt($index - 1);
  28518. }
  28519. }
  28520. private function getBraceAfterVariableKinds()
  28521. {
  28522. static $tokens = [
  28523. ')',
  28524. ']',
  28525. [CT::T_DYNAMIC_VAR_BRACE_CLOSE],
  28526. [CT::T_ARRAY_INDEX_CURLY_BRACE_CLOSE],
  28527. ];
  28528. return $tokens;
  28529. }
  28530. private function getFunctionyTokenKinds()
  28531. {
  28532. static $tokens = [
  28533. T_ARRAY,
  28534. T_ECHO,
  28535. T_EMPTY,
  28536. T_EVAL,
  28537. T_EXIT,
  28538. T_INCLUDE,
  28539. T_INCLUDE_ONCE,
  28540. T_ISSET,
  28541. T_LIST,
  28542. T_PRINT,
  28543. T_REQUIRE,
  28544. T_REQUIRE_ONCE,
  28545. T_UNSET,
  28546. T_VARIABLE,
  28547. ];
  28548. return $tokens;
  28549. }
  28550. private function getLanguageConstructionTokenKinds()
  28551. {
  28552. static $languageConstructionTokens = [
  28553. T_ECHO,
  28554. T_PRINT,
  28555. T_INCLUDE,
  28556. T_INCLUDE_ONCE,
  28557. T_REQUIRE,
  28558. T_REQUIRE_ONCE,
  28559. ];
  28560. return $languageConstructionTokens;
  28561. }
  28562. }
  28563. <?php
  28564. namespace PhpCsFixer\Fixer\FunctionNotation;
  28565. use PhpCsFixer\AbstractFixer;
  28566. use PhpCsFixer\FixerDefinition\FixerDefinition;
  28567. use PhpCsFixer\FixerDefinition\VersionSpecification;
  28568. use PhpCsFixer\FixerDefinition\VersionSpecificCodeSample;
  28569. use PhpCsFixer\Tokenizer\Analyzer\FunctionsAnalyzer;
  28570. use PhpCsFixer\Tokenizer\Token;
  28571. use PhpCsFixer\Tokenizer\Tokens;
  28572. final class CombineNestedDirnameFixer extends AbstractFixer
  28573. {
  28574. public function getDefinition()
  28575. {
  28576. return new FixerDefinition(
  28577. 'Replace multiple nested calls of `dirname` by only one call with second `$level` parameter. Requires PHP >= 7.0.',
  28578. [
  28579. new VersionSpecificCodeSample(
  28580. "<?php\ndirname(dirname(dirname(\$path)));\n",
  28581. new VersionSpecification(70000)
  28582. ),
  28583. ],
  28584. null,
  28585. 'Risky when the function `dirname` is overridden.'
  28586. );
  28587. }
  28588. public function isCandidate(Tokens $tokens)
  28589. {
  28590. return \PHP_VERSION_ID >= 70000 && $tokens->isTokenKindFound(T_STRING);
  28591. }
  28592. public function isRisky()
  28593. {
  28594. return true;
  28595. }
  28596. public function getPriority()
  28597. {
  28598. return 3;
  28599. }
  28600. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  28601. {
  28602. for ($index = $tokens->count() - 1; 0 <= $index; --$index) {
  28603. $dirnameInfo = $this->getDirnameInfo($tokens, $index);
  28604. if (!$dirnameInfo) {
  28605. continue;
  28606. }
  28607. $prev = $tokens->getPrevMeaningfulToken($dirnameInfo['indexes'][0]);
  28608. if (!$tokens[$prev]->equals('(')) {
  28609. continue;
  28610. }
  28611. $prev = $tokens->getPrevMeaningfulToken($prev);
  28612. $firstArgumentEnd = $dirnameInfo['end'];
  28613. $dirnameInfoArray = [$dirnameInfo];
  28614. while ($dirnameInfo = $this->getDirnameInfo($tokens, $prev, $firstArgumentEnd)) {
  28615. $dirnameInfoArray[] = $dirnameInfo;
  28616. $prev = $tokens->getPrevMeaningfulToken($dirnameInfo['indexes'][0]);
  28617. if (!$tokens[$prev]->equals('(')) {
  28618. break;
  28619. }
  28620. $prev = $tokens->getPrevMeaningfulToken($prev);
  28621. $firstArgumentEnd = $dirnameInfo['end'];
  28622. }
  28623. if (\count($dirnameInfoArray) > 1) {
  28624. $this->combineDirnames($tokens, $dirnameInfoArray);
  28625. }
  28626. $index = $prev;
  28627. }
  28628. }
  28629. private function getDirnameInfo(Tokens $tokens, $index, $firstArgumentEndIndex = null)
  28630. {
  28631. if (!$tokens[$index]->equals([T_STRING, 'dirname'], false)) {
  28632. return false;
  28633. }
  28634. if (!(new FunctionsAnalyzer())->isGlobalFunctionCall($tokens, $index)) {
  28635. return false;
  28636. }
  28637. $info['indexes'] = [];
  28638. $prev = $tokens->getPrevMeaningfulToken($index);
  28639. if ($tokens[$prev]->isGivenKind(T_NS_SEPARATOR)) {
  28640. $info['indexes'][] = $prev;
  28641. }
  28642. $info['indexes'][] = $index;
  28643. $next = $tokens->getNextMeaningfulToken($index);
  28644. $info['indexes'][] = $next;
  28645. if (null !== $firstArgumentEndIndex) {
  28646. $next = $tokens->getNextMeaningfulToken($firstArgumentEndIndex);
  28647. } else {
  28648. $next = $tokens->getNextMeaningfulToken($next);
  28649. if ($tokens[$next]->equals(')')) {
  28650. return false;
  28651. }
  28652. while (!$tokens[$next]->equalsAny([',', ')'])) {
  28653. $blockType = Tokens::detectBlockType($tokens[$next]);
  28654. if ($blockType) {
  28655. $next = $tokens->findBlockEnd($blockType['type'], $next);
  28656. }
  28657. $next = $tokens->getNextMeaningfulToken($next);
  28658. }
  28659. }
  28660. $info['indexes'][] = $next;
  28661. if ($tokens[$next]->equals(',')) {
  28662. $next = $tokens->getNextMeaningfulToken($next);
  28663. $info['indexes'][] = $next;
  28664. }
  28665. if ($tokens[$next]->equals(')')) {
  28666. $info['levels'] = 1;
  28667. $info['end'] = $next;
  28668. return $info;
  28669. }
  28670. if (!$tokens[$next]->isGivenKind(T_LNUMBER)) {
  28671. return false;
  28672. }
  28673. $info['secondArgument'] = $next;
  28674. $info['levels'] = (int) $tokens[$next]->getContent();
  28675. $next = $tokens->getNextMeaningfulToken($next);
  28676. if ($tokens[$next]->equals(',')) {
  28677. $info['indexes'][] = $next;
  28678. $next = $tokens->getNextMeaningfulToken($next);
  28679. }
  28680. if (!$tokens[$next]->equals(')')) {
  28681. return false;
  28682. }
  28683. $info['indexes'][] = $next;
  28684. $info['end'] = $next;
  28685. return $info;
  28686. }
  28687. private function combineDirnames(Tokens $tokens, array $dirnameInfoArray)
  28688. {
  28689. $outerDirnameInfo = array_pop($dirnameInfoArray);
  28690. $levels = $outerDirnameInfo['levels'];
  28691. foreach ($dirnameInfoArray as $dirnameInfo) {
  28692. $levels += $dirnameInfo['levels'];
  28693. foreach ($dirnameInfo['indexes'] as $index) {
  28694. $tokens->removeLeadingWhitespace($index);
  28695. $tokens->clearTokenAndMergeSurroundingWhitespace($index);
  28696. }
  28697. }
  28698. $levelsToken = new Token([T_LNUMBER, (string) $levels]);
  28699. if (isset($outerDirnameInfo['secondArgument'])) {
  28700. $tokens[$outerDirnameInfo['secondArgument']] = $levelsToken;
  28701. } else {
  28702. $prev = $tokens->getPrevMeaningfulToken($outerDirnameInfo['end']);
  28703. $items = [];
  28704. if (!$tokens[$prev]->equals(',')) {
  28705. $items = [new Token(','), new Token([T_WHITESPACE, ' '])];
  28706. }
  28707. $items[] = $levelsToken;
  28708. $tokens->insertAt($outerDirnameInfo['end'], $items);
  28709. }
  28710. }
  28711. }
  28712. <?php
  28713. namespace PhpCsFixer\Fixer\FunctionNotation;
  28714. use PhpCsFixer\AbstractFixer;
  28715. use PhpCsFixer\DocBlock\Annotation;
  28716. use PhpCsFixer\DocBlock\DocBlock;
  28717. use PhpCsFixer\FixerDefinition\FixerDefinition;
  28718. use PhpCsFixer\FixerDefinition\VersionSpecification;
  28719. use PhpCsFixer\FixerDefinition\VersionSpecificCodeSample;
  28720. use PhpCsFixer\Tokenizer\CT;
  28721. use PhpCsFixer\Tokenizer\Token;
  28722. use PhpCsFixer\Tokenizer\Tokens;
  28723. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  28724. final class VoidReturnFixer extends AbstractFixer
  28725. {
  28726. public function getDefinition()
  28727. {
  28728. return new FixerDefinition(
  28729. 'Add `void` return type to functions with missing or empty return statements, but priority is given to `@return` annotations. Requires PHP >= 7.1.',
  28730. [
  28731. new VersionSpecificCodeSample(
  28732. "<?php\nfunction foo(\$a) {};\n",
  28733. new VersionSpecification(70100)
  28734. ),
  28735. ],
  28736. null,
  28737. 'Modifies the signature of functions.'
  28738. );
  28739. }
  28740. public function getPriority()
  28741. {
  28742. return 15;
  28743. }
  28744. public function isCandidate(Tokens $tokens)
  28745. {
  28746. return \PHP_VERSION_ID >= 70100 && $tokens->isTokenKindFound(T_FUNCTION);
  28747. }
  28748. public function isRisky()
  28749. {
  28750. return true;
  28751. }
  28752. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  28753. {
  28754. static $excludeFuncNames = [
  28755. [T_STRING, '__construct'],
  28756. [T_STRING, '__destruct'],
  28757. [T_STRING, '__clone'],
  28758. ];
  28759. for ($index = $tokens->count() - 1; 0 <= $index; --$index) {
  28760. if (!$tokens[$index]->isGivenKind(T_FUNCTION)) {
  28761. continue;
  28762. }
  28763. $funcName = $tokens->getNextMeaningfulToken($index);
  28764. if ($tokens[$funcName]->equalsAny($excludeFuncNames, false)) {
  28765. continue;
  28766. }
  28767. $startIndex = $tokens->getNextTokenOfKind($index, ['{', ';']);
  28768. if ($this->hasReturnTypeHint($tokens, $startIndex)) {
  28769. continue;
  28770. }
  28771. if ($tokens[$startIndex]->equals(';')) {
  28772. if ($this->hasVoidReturnAnnotation($tokens, $index)) {
  28773. $this->fixFunctionDefinition($tokens, $startIndex);
  28774. }
  28775. continue;
  28776. }
  28777. if ($this->hasReturnAnnotation($tokens, $index)) {
  28778. continue;
  28779. }
  28780. $endIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $startIndex);
  28781. if ($this->hasVoidReturn($tokens, $startIndex, $endIndex)) {
  28782. $this->fixFunctionDefinition($tokens, $startIndex);
  28783. }
  28784. }
  28785. }
  28786. private function hasReturnAnnotation(Tokens $tokens, $index)
  28787. {
  28788. foreach ($this->findReturnAnnotations($tokens, $index) as $return) {
  28789. if (['void'] !== $return->getTypes()) {
  28790. return true;
  28791. }
  28792. }
  28793. return false;
  28794. }
  28795. private function hasVoidReturnAnnotation(Tokens $tokens, $index)
  28796. {
  28797. foreach ($this->findReturnAnnotations($tokens, $index) as $return) {
  28798. if (['void'] === $return->getTypes()) {
  28799. return true;
  28800. }
  28801. }
  28802. return false;
  28803. }
  28804. private function hasReturnTypeHint(Tokens $tokens, $index)
  28805. {
  28806. $endFuncIndex = $tokens->getPrevTokenOfKind($index, [')']);
  28807. $nextIndex = $tokens->getNextMeaningfulToken($endFuncIndex);
  28808. return $tokens[$nextIndex]->isGivenKind(CT::T_TYPE_COLON);
  28809. }
  28810. private function hasVoidReturn(Tokens $tokens, $startIndex, $endIndex)
  28811. {
  28812. $tokensAnalyzer = new TokensAnalyzer($tokens);
  28813. for ($i = $startIndex; $i < $endIndex; ++$i) {
  28814. if (
  28815. ($tokens[$i]->isGivenKind(T_CLASS) && $tokensAnalyzer->isAnonymousClass($i)) ||
  28816. ($tokens[$i]->isGivenKind(T_FUNCTION) && $tokensAnalyzer->isLambda($i))
  28817. ) {
  28818. $i = $tokens->getNextTokenOfKind($i, ['{']);
  28819. $i = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $i);
  28820. continue;
  28821. }
  28822. if ($tokens[$i]->isGivenKind([T_YIELD, T_YIELD_FROM])) {
  28823. return false;
  28824. }
  28825. if (!$tokens[$i]->isGivenKind(T_RETURN)) {
  28826. continue;
  28827. }
  28828. $i = $tokens->getNextMeaningfulToken($i);
  28829. if (!$tokens[$i]->equals(';')) {
  28830. return false;
  28831. }
  28832. }
  28833. return true;
  28834. }
  28835. private function fixFunctionDefinition(Tokens $tokens, $index)
  28836. {
  28837. $endFuncIndex = $tokens->getPrevTokenOfKind($index, [')']);
  28838. $tokens->insertAt($endFuncIndex + 1, [
  28839. new Token([CT::T_TYPE_COLON, ':']),
  28840. new Token([T_WHITESPACE, ' ']),
  28841. new Token([T_STRING, 'void']),
  28842. ]);
  28843. }
  28844. private function findReturnAnnotations(Tokens $tokens, $index)
  28845. {
  28846. do {
  28847. $index = $tokens->getPrevNonWhitespace($index);
  28848. } while ($tokens[$index]->isGivenKind([
  28849. T_ABSTRACT,
  28850. T_FINAL,
  28851. T_PRIVATE,
  28852. T_PROTECTED,
  28853. T_PUBLIC,
  28854. T_STATIC,
  28855. ]));
  28856. if (!$tokens[$index]->isGivenKind(T_DOC_COMMENT)) {
  28857. return [];
  28858. }
  28859. $doc = new DocBlock($tokens[$index]->getContent());
  28860. return $doc->getAnnotationsOfType('return');
  28861. }
  28862. }
  28863. <?php
  28864. namespace PhpCsFixer\Fixer\FunctionNotation;
  28865. use PhpCsFixer\AbstractFixer;
  28866. use PhpCsFixer\FixerDefinition\CodeSample;
  28867. use PhpCsFixer\FixerDefinition\FixerDefinition;
  28868. use PhpCsFixer\Preg;
  28869. use PhpCsFixer\Tokenizer\Token;
  28870. use PhpCsFixer\Tokenizer\Tokens;
  28871. final class SingleLineThrowFixer extends AbstractFixer
  28872. {
  28873. const REMOVE_WHITESPACE_AFTER_TOKENS = ['['];
  28874. const REMOVE_WHITESPACE_AROUND_TOKENS = ['(', [T_OBJECT_OPERATOR], [T_DOUBLE_COLON]];
  28875. const REMOVE_WHITESPACE_BEFORE_TOKENS = [')', ']', ',', ';'];
  28876. public function getDefinition()
  28877. {
  28878. return new FixerDefinition(
  28879. 'Throwing exception must be done in single line.',
  28880. [
  28881. new CodeSample("<?php\nthrow new Exception(\n 'Error',\n 500\n);\n"),
  28882. ]
  28883. );
  28884. }
  28885. public function isCandidate(Tokens $tokens)
  28886. {
  28887. return $tokens->isTokenKindFound(T_THROW);
  28888. }
  28889. public function getPriority()
  28890. {
  28891. return 1;
  28892. }
  28893. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  28894. {
  28895. for ($index = 0, $count = $tokens->count(); $index < $count; ++$index) {
  28896. if (!$tokens[$index]->isGivenKind(T_THROW)) {
  28897. continue;
  28898. }
  28899. $openingBraceCandidateIndex = $tokens->getNextTokenOfKind($index, [';', '(']);
  28900. while ($tokens[$openingBraceCandidateIndex]->equals('(')) {
  28901. $closingBraceIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $openingBraceCandidateIndex);
  28902. $openingBraceCandidateIndex = $tokens->getNextTokenOfKind($closingBraceIndex, [';', '(']);
  28903. }
  28904. $this->trimNewLines($tokens, $index, $openingBraceCandidateIndex);
  28905. }
  28906. }
  28907. private function trimNewLines(Tokens $tokens, $startIndex, $endIndex)
  28908. {
  28909. for ($index = $startIndex; $index < $endIndex; ++$index) {
  28910. $content = $tokens[$index]->getContent();
  28911. if ($tokens[$index]->isGivenKind(T_COMMENT)) {
  28912. if (0 === strpos($content, '//')) {
  28913. $content = '/*'.substr($content, 2).' */';
  28914. $tokens->clearAt($index + 1);
  28915. } elseif (0 === strpos($content, '#')) {
  28916. $content = '/*'.substr($content, 1).' */';
  28917. $tokens->clearAt($index + 1);
  28918. } elseif (false !== Preg::match('/\R/', $content)) {
  28919. $content = Preg::replace('/\R/', ' ', $content);
  28920. }
  28921. $tokens[$index] = new Token([T_COMMENT, $content]);
  28922. continue;
  28923. }
  28924. if (!$tokens[$index]->isGivenKind(T_WHITESPACE)) {
  28925. continue;
  28926. }
  28927. if (0 === Preg::match('/\R/', $content)) {
  28928. continue;
  28929. }
  28930. $prevIndex = $tokens->getNonEmptySibling($index, -1);
  28931. if ($tokens[$prevIndex]->equalsAny(array_merge(self::REMOVE_WHITESPACE_AFTER_TOKENS, self::REMOVE_WHITESPACE_AROUND_TOKENS))) {
  28932. $tokens->clearAt($index);
  28933. continue;
  28934. }
  28935. $nextIndex = $tokens->getNonEmptySibling($index, 1);
  28936. if ($tokens[$nextIndex]->equalsAny(array_merge(self::REMOVE_WHITESPACE_AROUND_TOKENS, self::REMOVE_WHITESPACE_BEFORE_TOKENS))) {
  28937. if (!$tokens[$prevIndex]->isGivenKind(T_FUNCTION)) {
  28938. $tokens->clearAt($index);
  28939. continue;
  28940. }
  28941. }
  28942. $tokens[$index] = new Token([T_WHITESPACE, ' ']);
  28943. }
  28944. }
  28945. }
  28946. <?php
  28947. namespace PhpCsFixer\Fixer\FunctionNotation;
  28948. use PhpCsFixer\AbstractFixer;
  28949. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  28950. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  28951. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  28952. use PhpCsFixer\FixerDefinition\FixerDefinition;
  28953. use PhpCsFixer\FixerDefinition\VersionSpecification;
  28954. use PhpCsFixer\FixerDefinition\VersionSpecificCodeSample;
  28955. use PhpCsFixer\Tokenizer\CT;
  28956. use PhpCsFixer\Tokenizer\Token;
  28957. use PhpCsFixer\Tokenizer\Tokens;
  28958. final class ReturnTypeDeclarationFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface
  28959. {
  28960. public function getDefinition()
  28961. {
  28962. $versionSpecification = new VersionSpecification(70000);
  28963. return new FixerDefinition(
  28964. 'There should be one or no space before colon, and one space after it in return type declarations, according to configuration.',
  28965. [
  28966. new VersionSpecificCodeSample(
  28967. "<?php\nfunction foo(int \$a):string {};\n",
  28968. $versionSpecification
  28969. ),
  28970. new VersionSpecificCodeSample(
  28971. "<?php\nfunction foo(int \$a):string {};\n",
  28972. $versionSpecification,
  28973. ['space_before' => 'none']
  28974. ),
  28975. new VersionSpecificCodeSample(
  28976. "<?php\nfunction foo(int \$a):string {};\n",
  28977. $versionSpecification,
  28978. ['space_before' => 'one']
  28979. ),
  28980. ],
  28981. 'Rule is applied only in a PHP 7+ environment.'
  28982. );
  28983. }
  28984. public function getPriority()
  28985. {
  28986. return -17;
  28987. }
  28988. public function isCandidate(Tokens $tokens)
  28989. {
  28990. return \PHP_VERSION_ID >= 70000 && $tokens->isTokenKindFound(CT::T_TYPE_COLON);
  28991. }
  28992. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  28993. {
  28994. $oneSpaceBefore = 'one' === $this->configuration['space_before'];
  28995. for ($index = 0, $limit = $tokens->count(); $index < $limit; ++$index) {
  28996. if (!$tokens[$index]->isGivenKind(CT::T_TYPE_COLON)) {
  28997. continue;
  28998. }
  28999. $previousIndex = $index - 1;
  29000. $previousToken = $tokens[$previousIndex];
  29001. if ($previousToken->isWhitespace()) {
  29002. if (!$tokens[$tokens->getPrevNonWhitespace($index - 1)]->isComment()) {
  29003. if ($oneSpaceBefore) {
  29004. $tokens[$previousIndex] = new Token([T_WHITESPACE, ' ']);
  29005. } else {
  29006. $tokens->clearAt($previousIndex);
  29007. }
  29008. }
  29009. } elseif ($oneSpaceBefore) {
  29010. $tokenWasAdded = $tokens->ensureWhitespaceAtIndex($index, 0, ' ');
  29011. if ($tokenWasAdded) {
  29012. ++$limit;
  29013. }
  29014. ++$index;
  29015. }
  29016. ++$index;
  29017. $tokenWasAdded = $tokens->ensureWhitespaceAtIndex($index, 0, ' ');
  29018. if ($tokenWasAdded) {
  29019. ++$limit;
  29020. }
  29021. }
  29022. }
  29023. protected function createConfigurationDefinition()
  29024. {
  29025. return new FixerConfigurationResolver([
  29026. (new FixerOptionBuilder('space_before', 'Spacing to apply before colon.'))
  29027. ->setAllowedValues(['one', 'none'])
  29028. ->setDefault('none')
  29029. ->getOption(),
  29030. ]);
  29031. }
  29032. }
  29033. <?php
  29034. namespace PhpCsFixer\Fixer\FunctionNotation;
  29035. use PhpCsFixer\AbstractFixer;
  29036. use PhpCsFixer\DocBlock\Annotation;
  29037. use PhpCsFixer\DocBlock\DocBlock;
  29038. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  29039. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  29040. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  29041. use PhpCsFixer\FixerDefinition\FixerDefinition;
  29042. use PhpCsFixer\FixerDefinition\VersionSpecification;
  29043. use PhpCsFixer\FixerDefinition\VersionSpecificCodeSample;
  29044. use PhpCsFixer\Preg;
  29045. use PhpCsFixer\Tokenizer\CT;
  29046. use PhpCsFixer\Tokenizer\Token;
  29047. use PhpCsFixer\Tokenizer\Tokens;
  29048. final class PhpdocToParamTypeFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface
  29049. {
  29050. const CLASS_REGEX = '/^\\\\?[a-zA-Z_\\x7f-\\xff](?:\\\\?[a-zA-Z0-9_\\x7f-\\xff]+)*(?<array>\[\])*$/';
  29051. const MINIMUM_PHP_VERSION = 70000;
  29052. private $blacklistFuncNames = [
  29053. [T_STRING, '__clone'],
  29054. [T_STRING, '__destruct'],
  29055. ];
  29056. private $skippedTypes = [
  29057. 'mixed' => true,
  29058. 'resource' => true,
  29059. 'static' => true,
  29060. 'void' => true,
  29061. ];
  29062. public function getDefinition()
  29063. {
  29064. return new FixerDefinition(
  29065. 'EXPERIMENTAL: Takes `@param` annotations of non-mixed types and adjusts accordingly the function signature. Requires PHP >= 7.0.',
  29066. [
  29067. new VersionSpecificCodeSample(
  29068. '<?php
  29069. /** @param string $bar */
  29070. function my_foo($bar)
  29071. {}
  29072. ',
  29073. new VersionSpecification(70000)
  29074. ),
  29075. new VersionSpecificCodeSample(
  29076. '<?php
  29077. /** @param string|null $bar */
  29078. function my_foo($bar)
  29079. {}
  29080. ',
  29081. new VersionSpecification(70100)
  29082. ),
  29083. ],
  29084. null,
  29085. 'This rule is EXPERIMENTAL and [1] is not covered with backward compatibility promise. [2] `@param` annotation is mandatory for the fixer to make changes, signatures of methods without it (no docblock, inheritdocs) will not be fixed. [3] Manual actions are required if inherited signatures are not properly documented.'
  29086. );
  29087. }
  29088. public function isCandidate(Tokens $tokens)
  29089. {
  29090. return \PHP_VERSION_ID >= self::MINIMUM_PHP_VERSION && $tokens->isTokenKindFound(T_FUNCTION);
  29091. }
  29092. public function getPriority()
  29093. {
  29094. return 8;
  29095. }
  29096. public function isRisky()
  29097. {
  29098. return true;
  29099. }
  29100. protected function createConfigurationDefinition()
  29101. {
  29102. return new FixerConfigurationResolver([
  29103. (new FixerOptionBuilder('scalar_types', 'Fix also scalar types; may have unexpected behaviour due to PHP bad type coercion system.'))
  29104. ->setAllowedTypes(['bool'])
  29105. ->setDefault(true)
  29106. ->getOption(),
  29107. ]);
  29108. }
  29109. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  29110. {
  29111. for ($index = $tokens->count() - 1; 0 < $index; --$index) {
  29112. if (!$tokens[$index]->isGivenKind(T_FUNCTION)) {
  29113. continue;
  29114. }
  29115. $funcName = $tokens->getNextMeaningfulToken($index);
  29116. if ($tokens[$funcName]->equalsAny($this->blacklistFuncNames, false)) {
  29117. continue;
  29118. }
  29119. $paramTypeAnnotations = $this->findParamAnnotations($tokens, $index);
  29120. foreach ($paramTypeAnnotations as $paramTypeAnnotation) {
  29121. if (\PHP_VERSION_ID < self::MINIMUM_PHP_VERSION) {
  29122. continue;
  29123. }
  29124. $types = array_values($paramTypeAnnotation->getTypes());
  29125. $paramType = current($types);
  29126. if (isset($this->skippedTypes[$paramType])) {
  29127. continue;
  29128. }
  29129. $hasIterable = false;
  29130. $hasNull = false;
  29131. $hasArray = false;
  29132. $hasString = false;
  29133. $hasInt = false;
  29134. $hasFloat = false;
  29135. $hasBool = false;
  29136. $hasCallable = false;
  29137. $hasObject = false;
  29138. $minimumTokenPhpVersion = self::MINIMUM_PHP_VERSION;
  29139. foreach ($types as $key => $type) {
  29140. if (1 !== Preg::match(self::CLASS_REGEX, $type, $matches)) {
  29141. continue;
  29142. }
  29143. if (isset($matches['array'])) {
  29144. $hasArray = true;
  29145. unset($types[$key]);
  29146. }
  29147. if ('iterable' === $type) {
  29148. $hasIterable = true;
  29149. unset($types[$key]);
  29150. $minimumTokenPhpVersion = 70100;
  29151. }
  29152. if ('null' === $type) {
  29153. $hasNull = true;
  29154. unset($types[$key]);
  29155. $minimumTokenPhpVersion = 70100;
  29156. }
  29157. if ('string' === $type) {
  29158. $hasString = true;
  29159. unset($types[$key]);
  29160. }
  29161. if ('int' === $type) {
  29162. $hasInt = true;
  29163. unset($types[$key]);
  29164. }
  29165. if ('float' === $type) {
  29166. $hasFloat = true;
  29167. unset($types[$key]);
  29168. }
  29169. if ('bool' === $type) {
  29170. $hasBool = true;
  29171. unset($types[$key]);
  29172. }
  29173. if ('callable' === $type) {
  29174. $hasCallable = true;
  29175. unset($types[$key]);
  29176. }
  29177. if ('array' === $type) {
  29178. $hasArray = true;
  29179. unset($types[$key]);
  29180. }
  29181. if ('object' === $type) {
  29182. $hasObject = true;
  29183. unset($types[$key]);
  29184. $minimumTokenPhpVersion = 70200;
  29185. }
  29186. }
  29187. if (\PHP_VERSION_ID < $minimumTokenPhpVersion) {
  29188. continue;
  29189. }
  29190. $typesCount = \count($types);
  29191. if (1 < $typesCount) {
  29192. continue;
  29193. }
  29194. if (0 === $typesCount) {
  29195. $paramType = '';
  29196. } elseif (1 === $typesCount) {
  29197. $paramType = array_shift($types);
  29198. }
  29199. $startIndex = $tokens->getNextTokenOfKind($index, ['(']) + 1;
  29200. $variableIndex = $this->findCorrectVariable($tokens, $startIndex - 1, $paramTypeAnnotation);
  29201. if (null === $variableIndex) {
  29202. continue;
  29203. }
  29204. $byRefIndex = $tokens->getPrevMeaningfulToken($variableIndex);
  29205. if ($tokens[$byRefIndex]->equals('&')) {
  29206. $variableIndex = $byRefIndex;
  29207. }
  29208. if (!('(' === $tokens[$variableIndex - 1]->getContent()) && $this->hasParamTypeHint($tokens, $variableIndex - 2)) {
  29209. continue;
  29210. }
  29211. $this->fixFunctionDefinition(
  29212. $paramType,
  29213. $tokens,
  29214. $variableIndex,
  29215. $hasNull,
  29216. $hasArray,
  29217. $hasIterable,
  29218. $hasString,
  29219. $hasInt,
  29220. $hasFloat,
  29221. $hasBool,
  29222. $hasCallable,
  29223. $hasObject
  29224. );
  29225. }
  29226. }
  29227. }
  29228. private function findParamAnnotations(Tokens $tokens, $index)
  29229. {
  29230. do {
  29231. $index = $tokens->getPrevNonWhitespace($index);
  29232. } while ($tokens[$index]->isGivenKind([
  29233. T_COMMENT,
  29234. T_ABSTRACT,
  29235. T_FINAL,
  29236. T_PRIVATE,
  29237. T_PROTECTED,
  29238. T_PUBLIC,
  29239. T_STATIC,
  29240. ]));
  29241. if (!$tokens[$index]->isGivenKind(T_DOC_COMMENT)) {
  29242. return [];
  29243. }
  29244. $doc = new DocBlock($tokens[$index]->getContent());
  29245. return $doc->getAnnotationsOfType('param');
  29246. }
  29247. private function findCorrectVariable(Tokens $tokens, $index, $paramTypeAnnotation)
  29248. {
  29249. $nextFunction = $tokens->getNextTokenOfKind($index, [[T_FUNCTION]]);
  29250. $variableIndex = $tokens->getNextTokenOfKind($index, [[T_VARIABLE]]);
  29251. if (\is_int($nextFunction) && $variableIndex > $nextFunction) {
  29252. return null;
  29253. }
  29254. if (!isset($tokens[$variableIndex])) {
  29255. return null;
  29256. }
  29257. $variableToken = $tokens[$variableIndex]->getContent();
  29258. Preg::match('/@param\s*[^\s!<]+\s*([^\s]+)/', $paramTypeAnnotation->getContent(), $paramVariable);
  29259. if (isset($paramVariable[1]) && $paramVariable[1] === $variableToken) {
  29260. return $variableIndex;
  29261. }
  29262. return $this->findCorrectVariable($tokens, $index + 1, $paramTypeAnnotation);
  29263. }
  29264. private function hasParamTypeHint(Tokens $tokens, $index)
  29265. {
  29266. return $tokens[$index]->isGivenKind([T_STRING, T_NS_SEPARATOR, CT::T_ARRAY_TYPEHINT, T_CALLABLE, CT::T_NULLABLE_TYPE]);
  29267. }
  29268. private function fixFunctionDefinition(
  29269. $paramType,
  29270. Tokens $tokens,
  29271. $index,
  29272. $hasNull,
  29273. $hasArray,
  29274. $hasIterable,
  29275. $hasString,
  29276. $hasInt,
  29277. $hasFloat,
  29278. $hasBool,
  29279. $hasCallable,
  29280. $hasObject
  29281. ) {
  29282. $newTokens = [];
  29283. if (true === $hasIterable && true === $hasArray) {
  29284. $newTokens[] = new Token([CT::T_ARRAY_TYPEHINT, 'array']);
  29285. } elseif (true === $hasIterable) {
  29286. $newTokens[] = new Token([T_STRING, 'iterable']);
  29287. } elseif (true === $hasArray) {
  29288. $newTokens[] = new Token([CT::T_ARRAY_TYPEHINT, 'array']);
  29289. } elseif (true === $hasString) {
  29290. $newTokens[] = new Token([T_STRING, 'string']);
  29291. } elseif (true === $hasInt) {
  29292. $newTokens[] = new Token([T_STRING, 'int']);
  29293. } elseif (true === $hasFloat) {
  29294. $newTokens[] = new Token([T_STRING, 'float']);
  29295. } elseif (true === $hasBool) {
  29296. $newTokens[] = new Token([T_STRING, 'bool']);
  29297. } elseif (true === $hasCallable) {
  29298. $newTokens[] = new Token([T_CALLABLE, 'callable']);
  29299. } elseif (true === $hasObject) {
  29300. $newTokens[] = new Token([T_STRING, 'object']);
  29301. }
  29302. if ('' !== $paramType && [] !== $newTokens) {
  29303. return;
  29304. }
  29305. foreach (explode('\\', $paramType) as $nsIndex => $value) {
  29306. if (0 === $nsIndex && '' === $value) {
  29307. continue;
  29308. }
  29309. if (0 < $nsIndex) {
  29310. $newTokens[] = new Token([T_NS_SEPARATOR, '\\']);
  29311. }
  29312. $newTokens[] = new Token([T_STRING, $value]);
  29313. }
  29314. if (true === $hasNull) {
  29315. array_unshift($newTokens, new Token([CT::T_NULLABLE_TYPE, '?']));
  29316. }
  29317. $newTokens[] = new Token([T_WHITESPACE, ' ']);
  29318. $tokens->insertAt($index, $newTokens);
  29319. }
  29320. }
  29321. <?php
  29322. namespace PhpCsFixer\Fixer\FunctionNotation;
  29323. use PhpCsFixer\AbstractFixer;
  29324. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  29325. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  29326. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  29327. use PhpCsFixer\FixerDefinition\CodeSample;
  29328. use PhpCsFixer\FixerDefinition\FixerDefinition;
  29329. use PhpCsFixer\Tokenizer\Analyzer\Analysis\NamespaceAnalysis;
  29330. use PhpCsFixer\Tokenizer\Analyzer\FunctionsAnalyzer;
  29331. use PhpCsFixer\Tokenizer\Analyzer\NamespacesAnalyzer;
  29332. use PhpCsFixer\Tokenizer\Token;
  29333. use PhpCsFixer\Tokenizer\Tokens;
  29334. use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException;
  29335. final class NativeFunctionInvocationFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface
  29336. {
  29337. const SET_ALL = '@all';
  29338. const SET_COMPILER_OPTIMIZED = '@compiler_optimized';
  29339. const SET_INTERNAL = '@internal';
  29340. private $functionFilter;
  29341. public function configure(array $configuration = null)
  29342. {
  29343. parent::configure($configuration);
  29344. $this->functionFilter = $this->getFunctionFilter();
  29345. }
  29346. public function getDefinition()
  29347. {
  29348. return new FixerDefinition(
  29349. 'Add leading `\` before function invocation to speed up resolving.',
  29350. [
  29351. new CodeSample(
  29352. '<?php
  29353. function baz($options)
  29354. {
  29355. if (!array_key_exists("foo", $options)) {
  29356. throw new \InvalidArgumentException();
  29357. }
  29358. return json_encode($options);
  29359. }
  29360. '
  29361. ),
  29362. new CodeSample(
  29363. '<?php
  29364. function baz($options)
  29365. {
  29366. if (!array_key_exists("foo", $options)) {
  29367. throw new \InvalidArgumentException();
  29368. }
  29369. return json_encode($options);
  29370. }
  29371. ',
  29372. [
  29373. 'exclude' => [
  29374. 'json_encode',
  29375. ],
  29376. ]
  29377. ),
  29378. new CodeSample(
  29379. '<?php
  29380. namespace space1 {
  29381. echo count([1]);
  29382. }
  29383. namespace {
  29384. echo count([1]);
  29385. }
  29386. ',
  29387. ['scope' => 'all']
  29388. ),
  29389. new CodeSample(
  29390. '<?php
  29391. namespace space1 {
  29392. echo count([1]);
  29393. }
  29394. namespace {
  29395. echo count([1]);
  29396. }
  29397. ',
  29398. ['scope' => 'namespaced']
  29399. ),
  29400. new CodeSample(
  29401. '<?php
  29402. myGlobalFunction();
  29403. count();
  29404. ',
  29405. ['include' => ['myGlobalFunction']]
  29406. ),
  29407. new CodeSample(
  29408. '<?php
  29409. myGlobalFunction();
  29410. count();
  29411. ',
  29412. ['include' => ['@all']]
  29413. ),
  29414. new CodeSample(
  29415. '<?php
  29416. myGlobalFunction();
  29417. count();
  29418. ',
  29419. ['include' => ['@internal']]
  29420. ),
  29421. new CodeSample(
  29422. '<?php
  29423. $a .= str_repeat($a, 4);
  29424. $c = get_class($d);
  29425. ',
  29426. ['include' => ['@compiler_optimized']]
  29427. ),
  29428. ],
  29429. null,
  29430. 'Risky when any of the functions are overridden.'
  29431. );
  29432. }
  29433. public function getPriority()
  29434. {
  29435. return 10;
  29436. }
  29437. public function isCandidate(Tokens $tokens)
  29438. {
  29439. return $tokens->isTokenKindFound(T_STRING);
  29440. }
  29441. public function isRisky()
  29442. {
  29443. return true;
  29444. }
  29445. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  29446. {
  29447. if ('all' === $this->configuration['scope']) {
  29448. $this->fixFunctionCalls($tokens, $this->functionFilter, 0, \count($tokens) - 1, false);
  29449. return;
  29450. }
  29451. $namespaces = (new NamespacesAnalyzer())->getDeclarations($tokens);
  29452. foreach (array_reverse($namespaces) as $namespace) {
  29453. $this->fixFunctionCalls($tokens, $this->functionFilter, $namespace->getScopeStartIndex(), $namespace->getScopeEndIndex(), '' === $namespace->getFullName());
  29454. }
  29455. }
  29456. protected function createConfigurationDefinition()
  29457. {
  29458. return new FixerConfigurationResolver([
  29459. (new FixerOptionBuilder('exclude', 'List of functions to ignore.'))
  29460. ->setAllowedTypes(['array'])
  29461. ->setAllowedValues([static function (array $value) {
  29462. foreach ($value as $functionName) {
  29463. if (!\is_string($functionName) || '' === trim($functionName) || trim($functionName) !== $functionName) {
  29464. throw new InvalidOptionsException(sprintf(
  29465. 'Each element must be a non-empty, trimmed string, got "%s" instead.',
  29466. \is_object($functionName) ? \get_class($functionName) : \gettype($functionName)
  29467. ));
  29468. }
  29469. }
  29470. return true;
  29471. }])
  29472. ->setDefault([])
  29473. ->getOption(),
  29474. (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).'))
  29475. ->setAllowedTypes(['array'])
  29476. ->setAllowedValues([static function (array $value) {
  29477. foreach ($value as $functionName) {
  29478. if (!\is_string($functionName) || '' === trim($functionName) || trim($functionName) !== $functionName) {
  29479. throw new InvalidOptionsException(sprintf(
  29480. 'Each element must be a non-empty, trimmed string, got "%s" instead.',
  29481. \is_object($functionName) ? \get_class($functionName) : \gettype($functionName)
  29482. ));
  29483. }
  29484. $sets = [
  29485. self::SET_ALL,
  29486. self::SET_INTERNAL,
  29487. self::SET_COMPILER_OPTIMIZED,
  29488. ];
  29489. if ('@' === $functionName[0] && !\in_array($functionName, $sets, true)) {
  29490. throw new InvalidOptionsException(sprintf('Unknown set "%s", known sets are "%s".', $functionName, implode('", "', $sets)));
  29491. }
  29492. }
  29493. return true;
  29494. }])
  29495. ->setDefault([self::SET_INTERNAL])
  29496. ->getOption(),
  29497. (new FixerOptionBuilder('scope', 'Only fix function calls that are made within a namespace or fix all.'))
  29498. ->setAllowedValues(['all', 'namespaced'])
  29499. ->setDefault('all')
  29500. ->getOption(),
  29501. (new FixerOptionBuilder('strict', 'Whether leading `\` of function call not meant to have it should be removed.'))
  29502. ->setAllowedTypes(['bool'])
  29503. ->setDefault(false)
  29504. ->getOption(),
  29505. ]);
  29506. }
  29507. private function fixFunctionCalls(Tokens $tokens, callable $functionFilter, $start, $end, $tryToRemove)
  29508. {
  29509. $functionsAnalyzer = new FunctionsAnalyzer();
  29510. $insertAtIndexes = [];
  29511. for ($index = $start; $index < $end; ++$index) {
  29512. if (!$functionsAnalyzer->isGlobalFunctionCall($tokens, $index)) {
  29513. continue;
  29514. }
  29515. $prevIndex = $tokens->getPrevMeaningfulToken($index);
  29516. if (!$functionFilter($tokens[$index]->getContent()) || $tryToRemove) {
  29517. if (!$this->configuration['strict']) {
  29518. continue;
  29519. }
  29520. if ($tokens[$prevIndex]->isGivenKind(T_NS_SEPARATOR)) {
  29521. $tokens->clearTokenAndMergeSurroundingWhitespace($prevIndex);
  29522. }
  29523. continue;
  29524. }
  29525. if ($tokens[$prevIndex]->isGivenKind(T_NS_SEPARATOR)) {
  29526. continue;
  29527. }
  29528. $insertAtIndexes[] = $index;
  29529. }
  29530. foreach (array_reverse($insertAtIndexes) as $index) {
  29531. $tokens->insertAt($index, new Token([T_NS_SEPARATOR, '\\']));
  29532. }
  29533. }
  29534. private function getFunctionFilter()
  29535. {
  29536. $exclude = $this->normalizeFunctionNames($this->configuration['exclude']);
  29537. if (\in_array(self::SET_ALL, $this->configuration['include'], true)) {
  29538. if (\count($exclude) > 0) {
  29539. return static function ($functionName) use ($exclude) {
  29540. return !isset($exclude[strtolower($functionName)]);
  29541. };
  29542. }
  29543. return static function () {
  29544. return true;
  29545. };
  29546. }
  29547. $include = [];
  29548. if (\in_array(self::SET_INTERNAL, $this->configuration['include'], true)) {
  29549. $include = $this->getAllInternalFunctionsNormalized();
  29550. } elseif (\in_array(self::SET_COMPILER_OPTIMIZED, $this->configuration['include'], true)) {
  29551. $include = $this->getAllCompilerOptimizedFunctionsNormalized();
  29552. }
  29553. foreach ($this->configuration['include'] as $additional) {
  29554. if ('@' !== $additional[0]) {
  29555. $include[strtolower($additional)] = true;
  29556. }
  29557. }
  29558. if (\count($exclude) > 0) {
  29559. return static function ($functionName) use ($include, $exclude) {
  29560. return isset($include[strtolower($functionName)]) && !isset($exclude[strtolower($functionName)]);
  29561. };
  29562. }
  29563. return static function ($functionName) use ($include) {
  29564. return isset($include[strtolower($functionName)]);
  29565. };
  29566. }
  29567. private function getAllCompilerOptimizedFunctionsNormalized()
  29568. {
  29569. return $this->normalizeFunctionNames([
  29570. 'array_key_exists',
  29571. 'array_slice',
  29572. 'assert',
  29573. 'boolval',
  29574. 'call_user_func',
  29575. 'call_user_func_array',
  29576. 'chr',
  29577. 'count',
  29578. 'defined',
  29579. 'doubleval',
  29580. 'floatval',
  29581. 'func_get_args',
  29582. 'func_num_args',
  29583. 'get_called_class',
  29584. 'get_class',
  29585. 'gettype',
  29586. 'in_array',
  29587. 'intval',
  29588. 'is_array',
  29589. 'is_bool',
  29590. 'is_double',
  29591. 'is_float',
  29592. 'is_int',
  29593. 'is_integer',
  29594. 'is_long',
  29595. 'is_null',
  29596. 'is_object',
  29597. 'is_real',
  29598. 'is_resource',
  29599. 'is_string',
  29600. 'ord',
  29601. 'strlen',
  29602. 'strval',
  29603. 'constant',
  29604. 'define',
  29605. 'dirname',
  29606. 'extension_loaded',
  29607. 'function_exists',
  29608. 'is_callable',
  29609. ]);
  29610. }
  29611. private function getAllInternalFunctionsNormalized()
  29612. {
  29613. return $this->normalizeFunctionNames(get_defined_functions()['internal']);
  29614. }
  29615. private function normalizeFunctionNames(array $functionNames)
  29616. {
  29617. foreach ($functionNames as $index => $functionName) {
  29618. $functionNames[strtolower($functionName)] = true;
  29619. unset($functionNames[$index]);
  29620. }
  29621. return $functionNames;
  29622. }
  29623. }
  29624. <?php
  29625. namespace PhpCsFixer\Fixer\FunctionNotation;
  29626. use PhpCsFixer\AbstractFixer;
  29627. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  29628. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  29629. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  29630. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  29631. use PhpCsFixer\FixerConfiguration\InvalidOptionsForEnvException;
  29632. use PhpCsFixer\FixerDefinition\CodeSample;
  29633. use PhpCsFixer\FixerDefinition\FixerDefinition;
  29634. use PhpCsFixer\FixerDefinition\VersionSpecification;
  29635. use PhpCsFixer\FixerDefinition\VersionSpecificCodeSample;
  29636. use PhpCsFixer\Preg;
  29637. use PhpCsFixer\Tokenizer\CT;
  29638. use PhpCsFixer\Tokenizer\Token;
  29639. use PhpCsFixer\Tokenizer\Tokens;
  29640. use Symfony\Component\OptionsResolver\Options;
  29641. final class MethodArgumentSpaceFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface, WhitespacesAwareFixerInterface
  29642. {
  29643. public function fixSpace(Tokens $tokens, $index)
  29644. {
  29645. @trigger_error(__METHOD__.' is deprecated and will be removed in 3.0.', E_USER_DEPRECATED);
  29646. $this->fixSpace2($tokens, $index);
  29647. }
  29648. public function getDefinition()
  29649. {
  29650. return new FixerDefinition(
  29651. '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.',
  29652. [
  29653. new CodeSample(
  29654. "<?php\nfunction sample(\$a=10,\$b=20,\$c=30) {}\nsample(1, 2);\n",
  29655. null
  29656. ),
  29657. new CodeSample(
  29658. "<?php\nfunction sample(\$a=10,\$b=20,\$c=30) {}\nsample(1, 2);\n",
  29659. ['keep_multiple_spaces_after_comma' => false]
  29660. ),
  29661. new CodeSample(
  29662. "<?php\nfunction sample(\$a=10,\$b=20,\$c=30) {}\nsample(1, 2);\n",
  29663. ['keep_multiple_spaces_after_comma' => true]
  29664. ),
  29665. new CodeSample(
  29666. "<?php\nfunction sample(\$a=10,\n \$b=20,\$c=30) {}\nsample(1,\n 2);\n",
  29667. ['on_multiline' => 'ensure_fully_multiline']
  29668. ),
  29669. new CodeSample(
  29670. "<?php\nfunction sample(\n \$a=10,\n \$b=20,\n \$c=30\n) {}\nsample(\n 1,\n 2\n);\n",
  29671. ['on_multiline' => 'ensure_single_line']
  29672. ),
  29673. new CodeSample(
  29674. "<?php\nfunction sample(\$a=10,\n \$b=20,\$c=30) {}\nsample(1, \n 2);\nsample('foo', 'foobarbaz', 'baz');\nsample('foobar', 'bar', 'baz');\n",
  29675. [
  29676. 'on_multiline' => 'ensure_fully_multiline',
  29677. 'keep_multiple_spaces_after_comma' => true,
  29678. ]
  29679. ),
  29680. new CodeSample(
  29681. "<?php\nfunction sample(\$a=10,\n \$b=20,\$c=30) {}\nsample(1, \n 2);\nsample('foo', 'foobarbaz', 'baz');\nsample('foobar', 'bar', 'baz');\n",
  29682. [
  29683. 'on_multiline' => 'ensure_fully_multiline',
  29684. 'keep_multiple_spaces_after_comma' => false,
  29685. ]
  29686. ),
  29687. new VersionSpecificCodeSample(
  29688. <<<'SAMPLE'
  29689. <?php
  29690. sample(
  29691. <<<EOD
  29692. foo
  29693. EOD
  29694. ,
  29695. 'bar'
  29696. );
  29697. SAMPLE
  29698. ,
  29699. new VersionSpecification(70300),
  29700. ['after_heredoc' => true]
  29701. ),
  29702. ]
  29703. );
  29704. }
  29705. public function isCandidate(Tokens $tokens)
  29706. {
  29707. return $tokens->isTokenKindFound('(');
  29708. }
  29709. public function configure(array $configuration = null)
  29710. {
  29711. parent::configure($configuration);
  29712. if ($this->configuration['ensure_fully_multiline'] && 'ignore' === $this->configuration['on_multiline']) {
  29713. $this->configuration['on_multiline'] = 'ensure_fully_multiline';
  29714. }
  29715. }
  29716. public function getPriority()
  29717. {
  29718. return -30;
  29719. }
  29720. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  29721. {
  29722. $expectedTokens = [T_LIST, T_FUNCTION];
  29723. if (\PHP_VERSION_ID >= 70400) {
  29724. $expectedTokens[] = T_FN;
  29725. }
  29726. for ($index = $tokens->count() - 1; $index > 0; --$index) {
  29727. $token = $tokens[$index];
  29728. if (!$token->equals('(')) {
  29729. continue;
  29730. }
  29731. $meaningfulTokenBeforeParenthesis = $tokens[$tokens->getPrevMeaningfulToken($index)];
  29732. if (
  29733. $meaningfulTokenBeforeParenthesis->isKeyword()
  29734. && !$meaningfulTokenBeforeParenthesis->isGivenKind($expectedTokens)
  29735. ) {
  29736. continue;
  29737. }
  29738. $isMultiline = $this->fixFunction($tokens, $index);
  29739. if (
  29740. $isMultiline
  29741. && 'ensure_fully_multiline' === $this->configuration['on_multiline']
  29742. && !$meaningfulTokenBeforeParenthesis->isGivenKind(T_LIST)
  29743. ) {
  29744. $this->ensureFunctionFullyMultiline($tokens, $index);
  29745. }
  29746. }
  29747. }
  29748. protected function createConfigurationDefinition()
  29749. {
  29750. return new FixerConfigurationResolver([
  29751. (new FixerOptionBuilder('keep_multiple_spaces_after_comma', 'Whether keep multiple spaces after comma.'))
  29752. ->setAllowedTypes(['bool'])
  29753. ->setDefault(false)
  29754. ->getOption(),
  29755. (new FixerOptionBuilder(
  29756. 'ensure_fully_multiline',
  29757. 'ensure every argument of a multiline argument list is on its own line'
  29758. ))
  29759. ->setAllowedTypes(['bool'])
  29760. ->setDefault(false)
  29761. ->setDeprecationMessage('Use option `on_multiline` instead.')
  29762. ->getOption(),
  29763. (new FixerOptionBuilder(
  29764. 'on_multiline',
  29765. 'Defines how to handle function arguments lists that contain newlines.'
  29766. ))
  29767. ->setAllowedValues(['ignore', 'ensure_single_line', 'ensure_fully_multiline'])
  29768. ->setDefault('ignore')
  29769. ->getOption(),
  29770. (new FixerOptionBuilder('after_heredoc', 'Whether the whitespace between heredoc end and comma should be removed.'))
  29771. ->setAllowedTypes(['bool'])
  29772. ->setDefault(false)
  29773. ->setNormalizer(static function (Options $options, $value) {
  29774. if (\PHP_VERSION_ID < 70300 && $value) {
  29775. throw new InvalidOptionsForEnvException('"after_heredoc" option can only be enabled with PHP 7.3+.');
  29776. }
  29777. return $value;
  29778. })
  29779. ->getOption(),
  29780. ]);
  29781. }
  29782. private function fixFunction(Tokens $tokens, $startFunctionIndex)
  29783. {
  29784. $endFunctionIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $startFunctionIndex);
  29785. $isMultiline = false;
  29786. $firstWhitespaceIndex = $this->findWhitespaceIndexAfterParenthesis($tokens, $startFunctionIndex, $endFunctionIndex);
  29787. $lastWhitespaceIndex = $this->findWhitespaceIndexAfterParenthesis($tokens, $endFunctionIndex, $startFunctionIndex);
  29788. foreach ([$firstWhitespaceIndex, $lastWhitespaceIndex] as $index) {
  29789. if (null === $index || !Preg::match('/\R/', $tokens[$index]->getContent())) {
  29790. continue;
  29791. }
  29792. if ('ensure_single_line' !== $this->configuration['on_multiline']) {
  29793. $isMultiline = true;
  29794. continue;
  29795. }
  29796. $newLinesRemoved = $this->ensureSingleLine($tokens, $index);
  29797. if (!$newLinesRemoved) {
  29798. $isMultiline = true;
  29799. }
  29800. }
  29801. for ($index = $endFunctionIndex - 1; $index > $startFunctionIndex; --$index) {
  29802. $token = $tokens[$index];
  29803. if ($token->equals(')')) {
  29804. $index = $tokens->findBlockStart(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $index);
  29805. continue;
  29806. }
  29807. if ($token->isGivenKind(CT::T_ARRAY_SQUARE_BRACE_CLOSE)) {
  29808. $index = $tokens->findBlockStart(Tokens::BLOCK_TYPE_ARRAY_SQUARE_BRACE, $index);
  29809. continue;
  29810. }
  29811. if ($token->equals('}')) {
  29812. $index = $tokens->findBlockStart(Tokens::BLOCK_TYPE_CURLY_BRACE, $index);
  29813. continue;
  29814. }
  29815. if ($token->equals(',')) {
  29816. $this->fixSpace2($tokens, $index);
  29817. if (!$isMultiline && $this->isNewline($tokens[$index + 1])) {
  29818. $isMultiline = true;
  29819. break;
  29820. }
  29821. }
  29822. }
  29823. return $isMultiline;
  29824. }
  29825. private function findWhitespaceIndexAfterParenthesis(Tokens $tokens, $startParenthesisIndex, $endParenthesisIndex)
  29826. {
  29827. $direction = $endParenthesisIndex > $startParenthesisIndex ? 1 : -1;
  29828. $startIndex = $startParenthesisIndex + $direction;
  29829. $endIndex = $endParenthesisIndex - $direction;
  29830. for ($index = $startIndex; $index !== $endIndex; $index += $direction) {
  29831. $token = $tokens[$index];
  29832. if ($token->isWhitespace()) {
  29833. return $index;
  29834. }
  29835. if (!$token->isComment()) {
  29836. break;
  29837. }
  29838. }
  29839. return null;
  29840. }
  29841. private function ensureSingleLine(Tokens $tokens, $index)
  29842. {
  29843. $previousToken = $tokens[$index - 1];
  29844. if ($previousToken->isComment() && 0 !== strpos($previousToken->getContent(), '/*')) {
  29845. return false;
  29846. }
  29847. $content = Preg::replace('/\R\h*/', '', $tokens[$index]->getContent());
  29848. if ('' !== $content) {
  29849. $tokens[$index] = new Token([T_WHITESPACE, $content]);
  29850. } else {
  29851. $tokens->clearAt($index);
  29852. }
  29853. return true;
  29854. }
  29855. private function ensureFunctionFullyMultiline(Tokens $tokens, $startFunctionIndex)
  29856. {
  29857. $searchIndex = $startFunctionIndex;
  29858. do {
  29859. $prevWhitespaceTokenIndex = $tokens->getPrevTokenOfKind(
  29860. $searchIndex,
  29861. [[T_WHITESPACE]]
  29862. );
  29863. $searchIndex = $prevWhitespaceTokenIndex;
  29864. } while (null !== $prevWhitespaceTokenIndex
  29865. && false === strpos($tokens[$prevWhitespaceTokenIndex]->getContent(), "\n")
  29866. );
  29867. if (null === $prevWhitespaceTokenIndex) {
  29868. $existingIndentation = '';
  29869. } else {
  29870. $existingIndentation = $tokens[$prevWhitespaceTokenIndex]->getContent();
  29871. $lastLineIndex = strrpos($existingIndentation, "\n");
  29872. $existingIndentation = false === $lastLineIndex
  29873. ? $existingIndentation
  29874. : substr($existingIndentation, $lastLineIndex + 1)
  29875. ;
  29876. }
  29877. $indentation = $existingIndentation.$this->whitespacesConfig->getIndent();
  29878. $endFunctionIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $startFunctionIndex);
  29879. $wasWhitespaceBeforeEndFunctionAddedAsNewToken = $tokens->ensureWhitespaceAtIndex(
  29880. $tokens[$endFunctionIndex - 1]->isWhitespace() ? $endFunctionIndex - 1 : $endFunctionIndex,
  29881. 0,
  29882. $this->whitespacesConfig->getLineEnding().$existingIndentation
  29883. );
  29884. if ($wasWhitespaceBeforeEndFunctionAddedAsNewToken) {
  29885. ++$endFunctionIndex;
  29886. }
  29887. for ($index = $endFunctionIndex - 1; $index > $startFunctionIndex; --$index) {
  29888. $token = $tokens[$index];
  29889. if ($token->equals(')')) {
  29890. $index = $tokens->findBlockStart(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $index);
  29891. continue;
  29892. }
  29893. if ($token->isGivenKind(CT::T_ARRAY_SQUARE_BRACE_CLOSE)) {
  29894. $index = $tokens->findBlockStart(Tokens::BLOCK_TYPE_ARRAY_SQUARE_BRACE, $index);
  29895. continue;
  29896. }
  29897. if ($token->equals('}')) {
  29898. $index = $tokens->findBlockStart(Tokens::BLOCK_TYPE_CURLY_BRACE, $index);
  29899. continue;
  29900. }
  29901. if ($token->equals(',') && !$tokens[$tokens->getNextMeaningfulToken($index)]->equals(')')) {
  29902. $this->fixNewline($tokens, $index, $indentation);
  29903. }
  29904. }
  29905. $this->fixNewline($tokens, $startFunctionIndex, $indentation, false);
  29906. }
  29907. private function fixNewline(Tokens $tokens, $index, $indentation, $override = true)
  29908. {
  29909. if ($tokens[$index + 1]->isComment()) {
  29910. return;
  29911. }
  29912. if ($tokens[$index + 2]->isComment()) {
  29913. $nextMeaningfulTokenIndex = $tokens->getNextMeaningfulToken($index + 2);
  29914. if (!$this->isNewline($tokens[$nextMeaningfulTokenIndex - 1])) {
  29915. $tokens->ensureWhitespaceAtIndex($nextMeaningfulTokenIndex, 0, $this->whitespacesConfig->getLineEnding().$indentation);
  29916. }
  29917. return;
  29918. }
  29919. $nextMeaningfulTokenIndex = $tokens->getNextMeaningfulToken($index);
  29920. if ($tokens[$nextMeaningfulTokenIndex]->equals(')')) {
  29921. return;
  29922. }
  29923. $tokens->ensureWhitespaceAtIndex($index + 1, 0, $this->whitespacesConfig->getLineEnding().$indentation);
  29924. }
  29925. private function fixSpace2(Tokens $tokens, $index)
  29926. {
  29927. if ($tokens[$index - 1]->isWhitespace()) {
  29928. $prevIndex = $tokens->getPrevNonWhitespace($index - 1);
  29929. if (
  29930. !$tokens[$prevIndex]->equals(',') && !$tokens[$prevIndex]->isComment() &&
  29931. ($this->configuration['after_heredoc'] || !$tokens[$prevIndex]->isGivenKind(T_END_HEREDOC))
  29932. ) {
  29933. $tokens->clearAt($index - 1);
  29934. }
  29935. }
  29936. $nextIndex = $index + 1;
  29937. $nextToken = $tokens[$nextIndex];
  29938. if ($nextToken->isWhitespace()) {
  29939. $newContent = $nextToken->getContent();
  29940. if ('ensure_single_line' === $this->configuration['on_multiline']) {
  29941. $newContent = Preg::replace('/\R/', '', $newContent);
  29942. }
  29943. if (
  29944. (!$this->configuration['keep_multiple_spaces_after_comma'] || Preg::match('/\R/', $newContent))
  29945. && !$this->isCommentLastLineToken($tokens, $index + 2)
  29946. ) {
  29947. $newContent = ltrim($newContent, " \t");
  29948. }
  29949. $tokens[$nextIndex] = new Token([T_WHITESPACE, '' === $newContent ? ' ' : $newContent]);
  29950. return;
  29951. }
  29952. if (!$this->isCommentLastLineToken($tokens, $index + 1)) {
  29953. $tokens->insertAt($index + 1, new Token([T_WHITESPACE, ' ']));
  29954. }
  29955. }
  29956. private function isCommentLastLineToken(Tokens $tokens, $index)
  29957. {
  29958. if (!$tokens[$index]->isComment() || !$tokens[$index + 1]->isWhitespace()) {
  29959. return false;
  29960. }
  29961. $content = $tokens[$index + 1]->getContent();
  29962. return $content !== ltrim($content, "\r\n");
  29963. }
  29964. private function isNewline(Token $token)
  29965. {
  29966. return $token->isWhitespace() && false !== strpos($token->getContent(), "\n");
  29967. }
  29968. }
  29969. <?php
  29970. namespace PhpCsFixer\Fixer\FunctionNotation;
  29971. use PhpCsFixer\AbstractFixer;
  29972. use PhpCsFixer\DocBlock\Annotation;
  29973. use PhpCsFixer\DocBlock\DocBlock;
  29974. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  29975. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  29976. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  29977. use PhpCsFixer\FixerDefinition\FixerDefinition;
  29978. use PhpCsFixer\FixerDefinition\VersionSpecification;
  29979. use PhpCsFixer\FixerDefinition\VersionSpecificCodeSample;
  29980. use PhpCsFixer\Preg;
  29981. use PhpCsFixer\Tokenizer\CT;
  29982. use PhpCsFixer\Tokenizer\Token;
  29983. use PhpCsFixer\Tokenizer\Tokens;
  29984. final class PhpdocToReturnTypeFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface
  29985. {
  29986. private $excludeFuncNames = [
  29987. [T_STRING, '__construct'],
  29988. [T_STRING, '__destruct'],
  29989. [T_STRING, '__clone'],
  29990. ];
  29991. private $versionSpecificTypes = [
  29992. 'void' => 70100,
  29993. 'iterable' => 70100,
  29994. 'object' => 70200,
  29995. ];
  29996. private $scalarTypes = [
  29997. 'bool' => 'bool',
  29998. 'true' => 'bool',
  29999. 'false' => 'bool',
  30000. 'float' => 'float',
  30001. 'int' => 'int',
  30002. 'string' => 'string',
  30003. ];
  30004. private $skippedTypes = [
  30005. 'mixed' => true,
  30006. 'resource' => true,
  30007. 'null' => true,
  30008. ];
  30009. private $classRegex = '/^\\\\?[a-zA-Z_\\x7f-\\xff](?:\\\\?[a-zA-Z0-9_\\x7f-\\xff]+)*(?<array>\[\])*$/';
  30010. private $returnTypeCache = [];
  30011. public function getDefinition()
  30012. {
  30013. return new FixerDefinition(
  30014. 'EXPERIMENTAL: Takes `@return` annotation of non-mixed types and adjusts accordingly the function signature. Requires PHP >= 7.0.',
  30015. [
  30016. new VersionSpecificCodeSample(
  30017. '<?php
  30018. /** @return \My\Bar */
  30019. function my_foo()
  30020. {}
  30021. ',
  30022. new VersionSpecification(70000)
  30023. ),
  30024. new VersionSpecificCodeSample(
  30025. '<?php
  30026. /** @return void */
  30027. function my_foo()
  30028. {}
  30029. ',
  30030. new VersionSpecification(70100)
  30031. ),
  30032. new VersionSpecificCodeSample(
  30033. '<?php
  30034. /** @return object */
  30035. function my_foo()
  30036. {}
  30037. ',
  30038. new VersionSpecification(70200)
  30039. ),
  30040. new VersionSpecificCodeSample(
  30041. '<?php
  30042. /** @return Foo */
  30043. function foo() {}
  30044. /** @return string */
  30045. function bar() {}
  30046. ',
  30047. new VersionSpecification(70100),
  30048. ['scalar_types' => false]
  30049. ),
  30050. ],
  30051. null,
  30052. 'This rule is EXPERIMENTAL and [1] is not covered with backward compatibility promise. [2] `@return` annotation is mandatory for the fixer to make changes, signatures of methods without it (no docblock, inheritdocs) will not be fixed. [3] Manual actions are required if inherited signatures are not properly documented. [4] `@inheritdocs` support is under construction.'
  30053. );
  30054. }
  30055. public function isCandidate(Tokens $tokens)
  30056. {
  30057. if (\PHP_VERSION_ID >= 70400 && $tokens->isTokenKindFound(T_FN)) {
  30058. return true;
  30059. }
  30060. return \PHP_VERSION_ID >= 70000 && $tokens->isTokenKindFound(T_FUNCTION);
  30061. }
  30062. public function getPriority()
  30063. {
  30064. return 13;
  30065. }
  30066. public function isRisky()
  30067. {
  30068. return true;
  30069. }
  30070. protected function createConfigurationDefinition()
  30071. {
  30072. return new FixerConfigurationResolver([
  30073. (new FixerOptionBuilder('scalar_types', 'Fix also scalar types; may have unexpected behaviour due to PHP bad type coercion system.'))
  30074. ->setAllowedTypes(['bool'])
  30075. ->setDefault(true)
  30076. ->getOption(),
  30077. ]);
  30078. }
  30079. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  30080. {
  30081. for ($index = $tokens->count() - 1; 0 < $index; --$index) {
  30082. if (
  30083. !$tokens[$index]->isGivenKind(T_FUNCTION)
  30084. && (\PHP_VERSION_ID < 70400 || !$tokens[$index]->isGivenKind(T_FN))
  30085. ) {
  30086. continue;
  30087. }
  30088. $funcName = $tokens->getNextMeaningfulToken($index);
  30089. if ($tokens[$funcName]->equalsAny($this->excludeFuncNames, false)) {
  30090. continue;
  30091. }
  30092. $returnTypeAnnotation = $this->findReturnAnnotations($tokens, $index);
  30093. if (1 !== \count($returnTypeAnnotation)) {
  30094. continue;
  30095. }
  30096. $returnTypeAnnotation = current($returnTypeAnnotation);
  30097. $types = array_values($returnTypeAnnotation->getTypes());
  30098. $typesCount = \count($types);
  30099. if (1 > $typesCount || 2 < $typesCount) {
  30100. continue;
  30101. }
  30102. $isNullable = false;
  30103. $returnType = current($types);
  30104. if (2 === $typesCount) {
  30105. $null = $types[0];
  30106. $returnType = $types[1];
  30107. if ('null' !== $null) {
  30108. $null = $types[1];
  30109. $returnType = $types[0];
  30110. }
  30111. if ('null' !== $null) {
  30112. continue;
  30113. }
  30114. $isNullable = true;
  30115. if (\PHP_VERSION_ID < 70100) {
  30116. continue;
  30117. }
  30118. if ('void' === $returnType) {
  30119. continue;
  30120. }
  30121. }
  30122. if ('static' === $returnType) {
  30123. $returnType = 'self';
  30124. }
  30125. if (isset($this->skippedTypes[$returnType])) {
  30126. continue;
  30127. }
  30128. if (isset($this->versionSpecificTypes[$returnType]) && \PHP_VERSION_ID < $this->versionSpecificTypes[$returnType]) {
  30129. continue;
  30130. }
  30131. if (isset($this->scalarTypes[$returnType])) {
  30132. if (false === $this->configuration['scalar_types']) {
  30133. continue;
  30134. }
  30135. $returnType = $this->scalarTypes[$returnType];
  30136. } else {
  30137. if (1 !== Preg::match($this->classRegex, $returnType, $matches)) {
  30138. continue;
  30139. }
  30140. if (isset($matches['array'])) {
  30141. $returnType = 'array';
  30142. }
  30143. }
  30144. $startIndex = $tokens->getNextTokenOfKind($index, ['{', ';']);
  30145. if ($this->hasReturnTypeHint($tokens, $startIndex)) {
  30146. continue;
  30147. }
  30148. if (!$this->isValidType($returnType)) {
  30149. continue;
  30150. }
  30151. $this->fixFunctionDefinition($tokens, $startIndex, $isNullable, $returnType);
  30152. }
  30153. }
  30154. private function hasReturnTypeHint(Tokens $tokens, $index)
  30155. {
  30156. $endFuncIndex = $tokens->getPrevTokenOfKind($index, [')']);
  30157. $nextIndex = $tokens->getNextMeaningfulToken($endFuncIndex);
  30158. return $tokens[$nextIndex]->isGivenKind(CT::T_TYPE_COLON);
  30159. }
  30160. private function fixFunctionDefinition(Tokens $tokens, $index, $isNullable, $returnType)
  30161. {
  30162. static $specialTypes = [
  30163. 'array' => [CT::T_ARRAY_TYPEHINT, 'array'],
  30164. 'callable' => [T_CALLABLE, 'callable'],
  30165. ];
  30166. $newTokens = [
  30167. new Token([CT::T_TYPE_COLON, ':']),
  30168. new Token([T_WHITESPACE, ' ']),
  30169. ];
  30170. if (true === $isNullable) {
  30171. $newTokens[] = new Token([CT::T_NULLABLE_TYPE, '?']);
  30172. }
  30173. if (isset($specialTypes[$returnType])) {
  30174. $newTokens[] = new Token($specialTypes[$returnType]);
  30175. } else {
  30176. foreach (explode('\\', $returnType) as $nsIndex => $value) {
  30177. if (0 === $nsIndex && '' === $value) {
  30178. continue;
  30179. }
  30180. if (0 < $nsIndex) {
  30181. $newTokens[] = new Token([T_NS_SEPARATOR, '\\']);
  30182. }
  30183. $newTokens[] = new Token([T_STRING, $value]);
  30184. }
  30185. }
  30186. $endFuncIndex = $tokens->getPrevTokenOfKind($index, [')']);
  30187. $tokens->insertAt($endFuncIndex + 1, $newTokens);
  30188. }
  30189. private function findReturnAnnotations(Tokens $tokens, $index)
  30190. {
  30191. do {
  30192. $index = $tokens->getPrevNonWhitespace($index);
  30193. } while ($tokens[$index]->isGivenKind([
  30194. T_COMMENT,
  30195. T_ABSTRACT,
  30196. T_FINAL,
  30197. T_PRIVATE,
  30198. T_PROTECTED,
  30199. T_PUBLIC,
  30200. T_STATIC,
  30201. ]));
  30202. if (!$tokens[$index]->isGivenKind(T_DOC_COMMENT)) {
  30203. return [];
  30204. }
  30205. $doc = new DocBlock($tokens[$index]->getContent());
  30206. return $doc->getAnnotationsOfType('return');
  30207. }
  30208. private function isValidType($returnType)
  30209. {
  30210. if (!\array_key_exists($returnType, $this->returnTypeCache)) {
  30211. try {
  30212. Tokens::fromCode(sprintf('<?php function f():%s {}', $returnType));
  30213. $this->returnTypeCache[$returnType] = true;
  30214. } catch (\ParseError $e) {
  30215. $this->returnTypeCache[$returnType] = false;
  30216. }
  30217. }
  30218. return $this->returnTypeCache[$returnType];
  30219. }
  30220. }
  30221. <?php
  30222. namespace PhpCsFixer\Fixer\FunctionNotation;
  30223. use PhpCsFixer\AbstractFopenFlagFixer;
  30224. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  30225. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  30226. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  30227. use PhpCsFixer\FixerDefinition\CodeSample;
  30228. use PhpCsFixer\FixerDefinition\FixerDefinition;
  30229. use PhpCsFixer\Tokenizer\Token;
  30230. use PhpCsFixer\Tokenizer\Tokens;
  30231. final class FopenFlagsFixer extends AbstractFopenFlagFixer implements ConfigurationDefinitionFixerInterface
  30232. {
  30233. public function getDefinition()
  30234. {
  30235. return new FixerDefinition(
  30236. 'The flags in `fopen` calls must omit `t`, and `b` must be omitted or included consistently.',
  30237. [
  30238. new CodeSample("<?php\n\$a = fopen(\$foo, 'rwt');\n"),
  30239. new CodeSample("<?php\n\$a = fopen(\$foo, 'rwt');\n", ['b_mode' => false]),
  30240. ],
  30241. null,
  30242. 'Risky when the function `fopen` is overridden.'
  30243. );
  30244. }
  30245. protected function createConfigurationDefinition()
  30246. {
  30247. return new FixerConfigurationResolver([
  30248. (new FixerOptionBuilder('b_mode', 'The `b` flag must be used (`true`) or omitted (`false`).'))
  30249. ->setAllowedTypes(['bool'])
  30250. ->setDefault(true)
  30251. ->getOption(),
  30252. ]);
  30253. }
  30254. protected function fixFopenFlagToken(Tokens $tokens, $argumentStartIndex, $argumentEndIndex)
  30255. {
  30256. $argumentFlagIndex = null;
  30257. for ($i = $argumentStartIndex; $i <= $argumentEndIndex; ++$i) {
  30258. if ($tokens[$i]->isGivenKind([T_WHITESPACE, T_COMMENT, T_DOC_COMMENT])) {
  30259. continue;
  30260. }
  30261. if (null !== $argumentFlagIndex) {
  30262. return;
  30263. }
  30264. $argumentFlagIndex = $i;
  30265. }
  30266. if (null === $argumentFlagIndex || !$tokens[$argumentFlagIndex]->isGivenKind(T_CONSTANT_ENCAPSED_STRING)) {
  30267. return;
  30268. }
  30269. $content = $tokens[$argumentFlagIndex]->getContent();
  30270. $contentQuote = $content[0];
  30271. if ('b' === $contentQuote || 'B' === $contentQuote) {
  30272. $binPrefix = $contentQuote;
  30273. $contentQuote = $content[1];
  30274. $mode = substr($content, 2, -1);
  30275. } else {
  30276. $binPrefix = '';
  30277. $mode = substr($content, 1, -1);
  30278. }
  30279. if (false === $this->isValidModeString($mode)) {
  30280. return;
  30281. }
  30282. $mode = str_replace('t', '', $mode);
  30283. if ($this->configuration['b_mode']) {
  30284. if (false === strpos($mode, 'b')) {
  30285. $mode .= 'b';
  30286. }
  30287. } else {
  30288. $mode = str_replace('b', '', $mode);
  30289. }
  30290. $newContent = $binPrefix.$contentQuote.$mode.$contentQuote;
  30291. if ($content !== $newContent) {
  30292. $tokens[$argumentFlagIndex] = new Token([T_CONSTANT_ENCAPSED_STRING, $newContent]);
  30293. }
  30294. }
  30295. }
  30296. <?php
  30297. namespace PhpCsFixer\Fixer\FunctionNotation;
  30298. use PhpCsFixer\AbstractFixer;
  30299. use PhpCsFixer\FixerDefinition\CodeSample;
  30300. use PhpCsFixer\FixerDefinition\FixerDefinition;
  30301. use PhpCsFixer\Tokenizer\Analyzer\Analysis\TypeAnalysis;
  30302. use PhpCsFixer\Tokenizer\Analyzer\FunctionsAnalyzer;
  30303. use PhpCsFixer\Tokenizer\Token;
  30304. use PhpCsFixer\Tokenizer\Tokens;
  30305. final class FunctionTypehintSpaceFixer extends AbstractFixer
  30306. {
  30307. public function getDefinition()
  30308. {
  30309. return new FixerDefinition(
  30310. 'Ensure single space between function\'s argument and its typehint.',
  30311. [
  30312. new CodeSample("<?php\nfunction sample(array\$a)\n{}\n"),
  30313. new CodeSample("<?php\nfunction sample(array \$a)\n{}\n"),
  30314. ]
  30315. );
  30316. }
  30317. public function isCandidate(Tokens $tokens)
  30318. {
  30319. if (\PHP_VERSION_ID >= 70400 && $tokens->isTokenKindFound(T_FN)) {
  30320. return true;
  30321. }
  30322. return $tokens->isTokenKindFound(T_FUNCTION);
  30323. }
  30324. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  30325. {
  30326. $functionsAnalyzer = new FunctionsAnalyzer();
  30327. for ($index = $tokens->count() - 1; $index >= 0; --$index) {
  30328. $token = $tokens[$index];
  30329. if (
  30330. !$token->isGivenKind(T_FUNCTION)
  30331. && (\PHP_VERSION_ID < 70400 || !$token->isGivenKind(T_FN))
  30332. ) {
  30333. continue;
  30334. }
  30335. $arguments = $functionsAnalyzer->getFunctionArguments($tokens, $index);
  30336. foreach (array_reverse($arguments) as $argument) {
  30337. $type = $argument->getTypeAnalysis();
  30338. if (!$type instanceof TypeAnalysis) {
  30339. continue;
  30340. }
  30341. $whitespaceTokenIndex = $type->getEndIndex() + 1;
  30342. if ($tokens[$whitespaceTokenIndex]->equals([T_WHITESPACE])) {
  30343. if (' ' === $tokens[$whitespaceTokenIndex]->getContent()) {
  30344. continue;
  30345. }
  30346. $tokens->clearAt($whitespaceTokenIndex);
  30347. }
  30348. $tokens->insertAt($whitespaceTokenIndex, new Token([T_WHITESPACE, ' ']));
  30349. }
  30350. }
  30351. }
  30352. }
  30353. <?php
  30354. namespace PhpCsFixer\Fixer\FunctionNotation;
  30355. use PhpCsFixer\AbstractFixer;
  30356. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  30357. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  30358. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  30359. use PhpCsFixer\FixerDefinition\CodeSample;
  30360. use PhpCsFixer\FixerDefinition\FixerDefinition;
  30361. use PhpCsFixer\FixerDefinition\VersionSpecification;
  30362. use PhpCsFixer\FixerDefinition\VersionSpecificCodeSample;
  30363. use PhpCsFixer\Tokenizer\CT;
  30364. use PhpCsFixer\Tokenizer\Tokens;
  30365. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  30366. final class FunctionDeclarationFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface
  30367. {
  30368. const SPACING_NONE = 'none';
  30369. const SPACING_ONE = 'one';
  30370. private $supportedSpacings = [self::SPACING_NONE, self::SPACING_ONE];
  30371. private $singleLineWhitespaceOptions = " \t";
  30372. public function isCandidate(Tokens $tokens)
  30373. {
  30374. if (\PHP_VERSION_ID >= 70400 && $tokens->isTokenKindFound(T_FN)) {
  30375. return true;
  30376. }
  30377. return $tokens->isTokenKindFound(T_FUNCTION);
  30378. }
  30379. public function getDefinition()
  30380. {
  30381. return new FixerDefinition(
  30382. 'Spaces should be properly placed in a function declaration.',
  30383. [
  30384. new CodeSample(
  30385. '<?php
  30386. class Foo
  30387. {
  30388. public static function bar ( $baz , $foo )
  30389. {
  30390. return false;
  30391. }
  30392. }
  30393. function foo ($bar, $baz)
  30394. {
  30395. return false;
  30396. }
  30397. '
  30398. ),
  30399. new CodeSample(
  30400. '<?php
  30401. $f = function () {};
  30402. ',
  30403. ['closure_function_spacing' => self::SPACING_NONE]
  30404. ),
  30405. new VersionSpecificCodeSample(
  30406. '<?php
  30407. $f = fn () => null;
  30408. ',
  30409. new VersionSpecification(70400),
  30410. ['closure_function_spacing' => self::SPACING_NONE]
  30411. ),
  30412. ]
  30413. );
  30414. }
  30415. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  30416. {
  30417. $tokensAnalyzer = new TokensAnalyzer($tokens);
  30418. for ($index = $tokens->count() - 1; $index >= 0; --$index) {
  30419. $token = $tokens[$index];
  30420. if (
  30421. !$token->isGivenKind(T_FUNCTION)
  30422. && (\PHP_VERSION_ID < 70400 || !$token->isGivenKind(T_FN))
  30423. ) {
  30424. continue;
  30425. }
  30426. $startParenthesisIndex = $tokens->getNextTokenOfKind($index, ['(', ';', [T_CLOSE_TAG]]);
  30427. if (!$tokens[$startParenthesisIndex]->equals('(')) {
  30428. continue;
  30429. }
  30430. $endParenthesisIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $startParenthesisIndex);
  30431. $startBraceIndex = $tokens->getNextTokenOfKind($endParenthesisIndex, [';', '{', [T_DOUBLE_ARROW]]);
  30432. if (
  30433. $tokens[$startBraceIndex]->equalsAny(['{', [T_DOUBLE_ARROW]]) &&
  30434. (
  30435. !$tokens[$startBraceIndex - 1]->isWhitespace() ||
  30436. $tokens[$startBraceIndex - 1]->isWhitespace($this->singleLineWhitespaceOptions)
  30437. )
  30438. ) {
  30439. $tokens->ensureWhitespaceAtIndex($startBraceIndex - 1, 1, ' ');
  30440. }
  30441. $afterParenthesisIndex = $tokens->getNextNonWhitespace($endParenthesisIndex);
  30442. $afterParenthesisToken = $tokens[$afterParenthesisIndex];
  30443. if ($afterParenthesisToken->isGivenKind(CT::T_USE_LAMBDA)) {
  30444. $tokens->ensureWhitespaceAtIndex($afterParenthesisIndex + 1, 0, ' ');
  30445. $useStartParenthesisIndex = $tokens->getNextTokenOfKind($afterParenthesisIndex, ['(']);
  30446. $useEndParenthesisIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $useStartParenthesisIndex);
  30447. $this->fixParenthesisInnerEdge($tokens, $useStartParenthesisIndex, $useEndParenthesisIndex);
  30448. $tokens->ensureWhitespaceAtIndex($afterParenthesisIndex - 1, 1, ' ');
  30449. }
  30450. $this->fixParenthesisInnerEdge($tokens, $startParenthesisIndex, $endParenthesisIndex);
  30451. $isLambda = $tokensAnalyzer->isLambda($index);
  30452. if (!$isLambda && $tokens[$startParenthesisIndex - 1]->isWhitespace() && !$tokens[$tokens->getPrevNonWhitespace($startParenthesisIndex - 1)]->isComment()) {
  30453. $tokens->clearAt($startParenthesisIndex - 1);
  30454. }
  30455. if ($isLambda && self::SPACING_NONE === $this->configuration['closure_function_spacing']) {
  30456. if ($tokens[$index + 1]->isWhitespace()) {
  30457. $tokens->clearAt($index + 1);
  30458. }
  30459. } else {
  30460. $tokens->ensureWhitespaceAtIndex($index + 1, 0, ' ');
  30461. }
  30462. if ($isLambda) {
  30463. $prev = $tokens->getPrevMeaningfulToken($index);
  30464. if ($tokens[$prev]->isGivenKind(T_STATIC)) {
  30465. $tokens->ensureWhitespaceAtIndex($prev + 1, 0, ' ');
  30466. }
  30467. }
  30468. }
  30469. }
  30470. protected function createConfigurationDefinition()
  30471. {
  30472. return new FixerConfigurationResolver([
  30473. (new FixerOptionBuilder('closure_function_spacing', 'Spacing to use before open parenthesis for closures.'))
  30474. ->setDefault(self::SPACING_ONE)
  30475. ->setAllowedValues($this->supportedSpacings)
  30476. ->getOption(),
  30477. ]);
  30478. }
  30479. private function fixParenthesisInnerEdge(Tokens $tokens, $start, $end)
  30480. {
  30481. if ($tokens[$end - 1]->isWhitespace($this->singleLineWhitespaceOptions)) {
  30482. $tokens->clearAt($end - 1);
  30483. }
  30484. if ($tokens[$start + 1]->isWhitespace($this->singleLineWhitespaceOptions)) {
  30485. $tokens->clearAt($start + 1);
  30486. }
  30487. }
  30488. }
  30489. <?php
  30490. namespace PhpCsFixer\Fixer\FunctionNotation;
  30491. use PhpCsFixer\AbstractFopenFlagFixer;
  30492. use PhpCsFixer\FixerDefinition\CodeSample;
  30493. use PhpCsFixer\FixerDefinition\FixerDefinition;
  30494. use PhpCsFixer\Preg;
  30495. use PhpCsFixer\Tokenizer\Token;
  30496. use PhpCsFixer\Tokenizer\Tokens;
  30497. final class FopenFlagOrderFixer extends AbstractFopenFlagFixer
  30498. {
  30499. public function getDefinition()
  30500. {
  30501. return new FixerDefinition(
  30502. 'Order the flags in `fopen` calls, `b` and `t` must be last.',
  30503. [new CodeSample("<?php\n\$a = fopen(\$foo, 'br+');\n")],
  30504. null,
  30505. 'Risky when the function `fopen` is overridden.'
  30506. );
  30507. }
  30508. protected function fixFopenFlagToken(Tokens $tokens, $argumentStartIndex, $argumentEndIndex)
  30509. {
  30510. $argumentFlagIndex = null;
  30511. for ($i = $argumentStartIndex; $i <= $argumentEndIndex; ++$i) {
  30512. if ($tokens[$i]->isGivenKind([T_WHITESPACE, T_COMMENT, T_DOC_COMMENT])) {
  30513. continue;
  30514. }
  30515. if (null !== $argumentFlagIndex) {
  30516. return;
  30517. }
  30518. $argumentFlagIndex = $i;
  30519. }
  30520. if (null === $argumentFlagIndex || !$tokens[$argumentFlagIndex]->isGivenKind(T_CONSTANT_ENCAPSED_STRING)) {
  30521. return;
  30522. }
  30523. $content = $tokens[$argumentFlagIndex]->getContent();
  30524. $contentQuote = $content[0];
  30525. if ('b' === $contentQuote || 'B' === $contentQuote) {
  30526. $binPrefix = $contentQuote;
  30527. $contentQuote = $content[1];
  30528. $mode = substr($content, 2, -1);
  30529. } else {
  30530. $binPrefix = '';
  30531. $mode = substr($content, 1, -1);
  30532. }
  30533. $modeLength = \strlen($mode);
  30534. if ($modeLength < 2) {
  30535. return;
  30536. }
  30537. if (false === $this->isValidModeString($mode)) {
  30538. return;
  30539. }
  30540. $split = $this->sortFlags(Preg::split('#([^\+]\+?)#', $mode, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE));
  30541. $newContent = $binPrefix.$contentQuote.implode('', $split).$contentQuote;
  30542. if ($content !== $newContent) {
  30543. $tokens[$argumentFlagIndex] = new Token([T_CONSTANT_ENCAPSED_STRING, $newContent]);
  30544. }
  30545. }
  30546. private function sortFlags(array $flags)
  30547. {
  30548. usort(
  30549. $flags,
  30550. static function ($flag1, $flag2) {
  30551. if ($flag1 === $flag2) {
  30552. return 0;
  30553. }
  30554. if ('b' === $flag1) {
  30555. return 1;
  30556. }
  30557. if ('b' === $flag2) {
  30558. return -1;
  30559. }
  30560. if ('t' === $flag1) {
  30561. return 1;
  30562. }
  30563. if ('t' === $flag2) {
  30564. return -1;
  30565. }
  30566. return $flag1 < $flag2 ? -1 : 1;
  30567. }
  30568. );
  30569. return $flags;
  30570. }
  30571. }
  30572. <?php
  30573. namespace PhpCsFixer\Fixer\FunctionNotation;
  30574. use PhpCsFixer\AbstractFixer;
  30575. use PhpCsFixer\FixerDefinition\CodeSample;
  30576. use PhpCsFixer\FixerDefinition\FixerDefinition;
  30577. use PhpCsFixer\Tokenizer\CT;
  30578. use PhpCsFixer\Tokenizer\Tokens;
  30579. /**
  30580. @web
  30581. */
  30582. final class NoUnreachableDefaultArgumentValueFixer extends AbstractFixer
  30583. {
  30584. public function getDefinition()
  30585. {
  30586. return new FixerDefinition(
  30587. 'In function arguments there must not be arguments with default values before non-default ones.',
  30588. [
  30589. new CodeSample(
  30590. '<?php
  30591. function example($foo = "two words", $bar) {}
  30592. '
  30593. ),
  30594. ],
  30595. null,
  30596. 'Modifies the signature of functions; therefore risky when using systems (such as some Symfony components) that rely on those (for example through reflection).'
  30597. );
  30598. }
  30599. public function getPriority()
  30600. {
  30601. return 0;
  30602. }
  30603. public function isCandidate(Tokens $tokens)
  30604. {
  30605. if (\PHP_VERSION_ID >= 70400 && $tokens->isTokenKindFound(T_FN)) {
  30606. return true;
  30607. }
  30608. return $tokens->isTokenKindFound(T_FUNCTION);
  30609. }
  30610. public function isRisky()
  30611. {
  30612. return true;
  30613. }
  30614. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  30615. {
  30616. for ($i = 0, $l = $tokens->count(); $i < $l; ++$i) {
  30617. if (
  30618. !$tokens[$i]->isGivenKind(T_FUNCTION)
  30619. && (\PHP_VERSION_ID < 70400 || !$tokens[$i]->isGivenKind(T_FN))
  30620. ) {
  30621. continue;
  30622. }
  30623. $startIndex = $tokens->getNextTokenOfKind($i, ['(']);
  30624. $i = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $startIndex);
  30625. $this->fixFunctionDefinition($tokens, $startIndex, $i);
  30626. }
  30627. }
  30628. private function fixFunctionDefinition(Tokens $tokens, $startIndex, $endIndex)
  30629. {
  30630. $lastArgumentIndex = $this->getLastNonDefaultArgumentIndex($tokens, $startIndex, $endIndex);
  30631. if (!$lastArgumentIndex) {
  30632. return;
  30633. }
  30634. for ($i = $lastArgumentIndex; $i > $startIndex; --$i) {
  30635. $token = $tokens[$i];
  30636. if ($token->isGivenKind(T_VARIABLE)) {
  30637. $lastArgumentIndex = $i;
  30638. continue;
  30639. }
  30640. if (!$token->equals('=') || $this->isNonNullableTypehintedNullableVariable($tokens, $i)) {
  30641. continue;
  30642. }
  30643. $endIndex = $tokens->getPrevTokenOfKind($lastArgumentIndex, [',']);
  30644. $endIndex = $tokens->getPrevMeaningfulToken($endIndex);
  30645. $this->removeDefaultArgument($tokens, $i, $endIndex);
  30646. }
  30647. }
  30648. private function getLastNonDefaultArgumentIndex(Tokens $tokens, $startIndex, $endIndex)
  30649. {
  30650. for ($i = $endIndex - 1; $i > $startIndex; --$i) {
  30651. $token = $tokens[$i];
  30652. if ($token->equals('=')) {
  30653. $i = $tokens->getPrevMeaningfulToken($i);
  30654. continue;
  30655. }
  30656. if ($token->isGivenKind(T_VARIABLE) && !$this->isEllipsis($tokens, $i)) {
  30657. return $i;
  30658. }
  30659. }
  30660. return null;
  30661. }
  30662. private function isEllipsis(Tokens $tokens, $variableIndex)
  30663. {
  30664. return $tokens[$tokens->getPrevMeaningfulToken($variableIndex)]->isGivenKind(T_ELLIPSIS);
  30665. }
  30666. private function removeDefaultArgument(Tokens $tokens, $startIndex, $endIndex)
  30667. {
  30668. for ($i = $startIndex; $i <= $endIndex;) {
  30669. $tokens->clearTokenAndMergeSurroundingWhitespace($i);
  30670. $this->clearWhitespacesBeforeIndex($tokens, $i);
  30671. $i = $tokens->getNextMeaningfulToken($i);
  30672. }
  30673. }
  30674. private function isNonNullableTypehintedNullableVariable(Tokens $tokens, $index)
  30675. {
  30676. $nextToken = $tokens[$tokens->getNextMeaningfulToken($index)];
  30677. if (!$nextToken->equals([T_STRING, 'null'], false)) {
  30678. return false;
  30679. }
  30680. $variableIndex = $tokens->getPrevMeaningfulToken($index);
  30681. $searchTokens = [',', '(', [T_STRING], [CT::T_ARRAY_TYPEHINT], [T_CALLABLE]];
  30682. $typehintKinds = [T_STRING, CT::T_ARRAY_TYPEHINT, T_CALLABLE];
  30683. $prevIndex = $tokens->getPrevTokenOfKind($variableIndex, $searchTokens);
  30684. if (!$tokens[$prevIndex]->isGivenKind($typehintKinds)) {
  30685. return false;
  30686. }
  30687. return !$tokens[$tokens->getPrevMeaningfulToken($prevIndex)]->isGivenKind(CT::T_NULLABLE_TYPE);
  30688. }
  30689. private function clearWhitespacesBeforeIndex(Tokens $tokens, $index)
  30690. {
  30691. $prevIndex = $tokens->getNonEmptySibling($index, -1);
  30692. if (!$tokens[$prevIndex]->isWhitespace()) {
  30693. return;
  30694. }
  30695. $prevNonWhiteIndex = $tokens->getPrevNonWhitespace($prevIndex);
  30696. if (null === $prevNonWhiteIndex || !$tokens[$prevNonWhiteIndex]->isComment()) {
  30697. $tokens->clearTokenAndMergeSurroundingWhitespace($prevIndex);
  30698. }
  30699. }
  30700. }
  30701. <?php
  30702. namespace PhpCsFixer\Fixer\Naming;
  30703. use PhpCsFixer\AbstractFixer;
  30704. use PhpCsFixer\FixerDefinition\CodeSample;
  30705. use PhpCsFixer\FixerDefinition\FixerDefinition;
  30706. use PhpCsFixer\Preg;
  30707. use PhpCsFixer\Tokenizer\Token;
  30708. use PhpCsFixer\Tokenizer\Tokens;
  30709. /**
  30710. @gmail
  30711. */
  30712. final class NoHomoglyphNamesFixer extends AbstractFixer
  30713. {
  30714. private static $replacements = [
  30715. 'O' => '0',
  30716. '�' => '0',
  30717. 'I' => '1',
  30718. '1' => '1',
  30719. 'ï¼’' => '2',
  30720. '3' => '3',
  30721. 'ï¼”' => '4',
  30722. '5' => '5',
  30723. 'ï¼–' => '6',
  30724. 'ï¼—' => '7',
  30725. '8' => '8',
  30726. 'ï¼™' => '9',
  30727. 'Α' => 'A',
  30728. '�' => 'A',
  30729. 'A' => 'A',
  30730. 'Ê™' => 'B',
  30731. 'Î’' => 'B',
  30732. 'Ð’' => 'B',
  30733. 'ï¼¢' => 'B',
  30734. 'Ϲ' => 'C',
  30735. 'С' => 'C',
  30736. 'â…­' => 'C',
  30737. 'ï¼£' => 'C',
  30738. 'â…®' => 'D',
  30739. 'D' => 'D',
  30740. 'Ε' => 'E',
  30741. 'Е' => 'E',
  30742. 'ï¼¥' => 'E',
  30743. 'Ϝ' => 'F',
  30744. 'F' => 'F',
  30745. 'É¢' => 'G',
  30746. 'Ԍ' => 'G',
  30747. 'ï¼§' => 'G',
  30748. 'ʜ' => 'H',
  30749. 'Η' => 'H',
  30750. '�' => 'H',
  30751. 'H' => 'H',
  30752. 'l' => 'I',
  30753. 'Ι' => 'I',
  30754. 'І' => 'I',
  30755. 'â… ' => 'I',
  30756. 'I' => 'I',
  30757. 'Ј' => 'J',
  30758. 'J' => 'J',
  30759. 'Κ' => 'K',
  30760. 'К' => 'K',
  30761. 'K' => 'K',
  30762. 'K' => 'K',
  30763. 'ÊŸ' => 'L',
  30764. 'â…¬' => 'L',
  30765. 'L' => 'L',
  30766. 'Μ' => 'M',
  30767. 'М' => 'M',
  30768. 'â…¯' => 'M',
  30769. 'ï¼­' => 'M',
  30770. 'É´' => 'N',
  30771. '�' => 'N',
  30772. 'ï¼®' => 'N',
  30773. 'Ο' => 'O',
  30774. 'О' => 'O',
  30775. 'O' => 'O',
  30776. 'Ρ' => 'P',
  30777. 'Р' => 'P',
  30778. 'ï¼°' => 'P',
  30779. 'ï¼±' => 'Q',
  30780. 'Ê€' => 'R',
  30781. 'ï¼²' => 'R',
  30782. 'Ð…' => 'S',
  30783. 'ï¼³' => 'S',
  30784. 'Τ' => 'T',
  30785. 'Т' => 'T',
  30786. 'ï¼´' => 'T',
  30787. 'ï¼µ' => 'U',
  30788. 'Ñ´' => 'V',
  30789. 'â…¤' => 'V',
  30790. 'ï¼¶' => 'V',
  30791. 'ï¼·' => 'W',
  30792. 'Χ' => 'X',
  30793. 'Ð¥' => 'X',
  30794. 'â…©' => 'X',
  30795. 'X' => 'X',
  30796. '�' => 'Y',
  30797. 'Î¥' => 'Y',
  30798. 'Ò®' => 'Y',
  30799. 'ï¼¹' => 'Y',
  30800. 'Ζ' => 'Z',
  30801. 'Z' => 'Z',
  30802. '_' => '_',
  30803. 'É‘' => 'a',
  30804. 'а' => 'a',
  30805. '�' => 'a',
  30806. 'Ь' => 'b',
  30807. 'b' => 'b',
  30808. 'ϲ' => 'c',
  30809. '�' => 'c',
  30810. 'â…½' => 'c',
  30811. 'c' => 'c',
  30812. 'Ô�' => 'd',
  30813. 'â…¾' => 'd',
  30814. 'd' => 'd',
  30815. 'е' => 'e',
  30816. 'ï½…' => 'e',
  30817. 'f' => 'f',
  30818. 'É¡' => 'g',
  30819. 'g' => 'g',
  30820. 'Ò»' => 'h',
  30821. 'h' => 'h',
  30822. 'É©' => 'i',
  30823. 'Ñ–' => 'i',
  30824. 'â…°' => 'i',
  30825. 'i' => 'i',
  30826. 'ј' => 'j',
  30827. 'j' => 'j',
  30828. 'k' => 'k',
  30829. 'â…¼' => 'l',
  30830. 'l' => 'l',
  30831. 'â…¿' => 'm',
  30832. '�' => 'm',
  30833. 'n' => 'n',
  30834. 'ο' => 'o',
  30835. 'о' => 'o',
  30836. '�' => 'o',
  30837. 'Ñ€' => 'p',
  30838. '�' => 'p',
  30839. 'q' => 'q',
  30840. 'ï½’' => 'r',
  30841. 'Ñ•' => 's',
  30842. 's' => 's',
  30843. 'ï½”' => 't',
  30844. 'u' => 'u',
  30845. 'ν' => 'v',
  30846. 'ѵ' => 'v',
  30847. 'â…´' => 'v',
  30848. 'ï½–' => 'v',
  30849. 'Ñ¡' => 'w',
  30850. 'ï½—' => 'w',
  30851. 'Ñ…' => 'x',
  30852. 'â…¹' => 'x',
  30853. 'x' => 'x',
  30854. 'у' => 'y',
  30855. 'ï½™' => 'y',
  30856. 'z' => 'z',
  30857. ];
  30858. public function getDefinition()
  30859. {
  30860. return new FixerDefinition(
  30861. 'Replace accidental usage of homoglyphs (non ascii characters) in names.',
  30862. [new CodeSample("<?php \$nаmе = 'wrong \"a\" character';\n")],
  30863. null,
  30864. 'Renames classes and cannot rename the files. You might have string references to renamed code (`$$name`).'
  30865. );
  30866. }
  30867. public function isRisky()
  30868. {
  30869. return true;
  30870. }
  30871. public function isCandidate(Tokens $tokens)
  30872. {
  30873. return $tokens->isAnyTokenKindsFound([T_VARIABLE, T_STRING]);
  30874. }
  30875. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  30876. {
  30877. foreach ($tokens as $index => $token) {
  30878. if (!$token->isGivenKind([T_VARIABLE, T_STRING])) {
  30879. continue;
  30880. }
  30881. $replaced = Preg::replaceCallback('/[^[:ascii:]]/u', static function ($matches) {
  30882. return isset(self::$replacements[$matches[0]])
  30883. ? self::$replacements[$matches[0]]
  30884. : $matches[0]
  30885. ;
  30886. }, $token->getContent(), -1, $count);
  30887. if ($count) {
  30888. $tokens->offsetSet($index, new Token([$token->getId(), $replaced]));
  30889. }
  30890. }
  30891. }
  30892. }
  30893. <?php
  30894. namespace PhpCsFixer\Fixer\Casing;
  30895. use PhpCsFixer\AbstractFixer;
  30896. use PhpCsFixer\FixerDefinition\CodeSample;
  30897. use PhpCsFixer\FixerDefinition\FixerDefinition;
  30898. use PhpCsFixer\Tokenizer\CT;
  30899. use PhpCsFixer\Tokenizer\Token;
  30900. use PhpCsFixer\Tokenizer\Tokens;
  30901. final class MagicConstantCasingFixer extends AbstractFixer
  30902. {
  30903. public function getDefinition()
  30904. {
  30905. return new FixerDefinition(
  30906. 'Magic constants should be referred to using the correct casing.',
  30907. [new CodeSample("<?php\necho __dir__;\n")]
  30908. );
  30909. }
  30910. public function isCandidate(Tokens $tokens)
  30911. {
  30912. return $tokens->isAnyTokenKindsFound($this->getMagicConstantTokens());
  30913. }
  30914. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  30915. {
  30916. $magicConstants = $this->getMagicConstants();
  30917. $magicConstantTokens = $this->getMagicConstantTokens();
  30918. foreach ($tokens as $index => $token) {
  30919. if ($token->isGivenKind($magicConstantTokens)) {
  30920. $tokens[$index] = new Token([$token->getId(), $magicConstants[$token->getId()]]);
  30921. }
  30922. }
  30923. }
  30924. private function getMagicConstants()
  30925. {
  30926. static $magicConstants = null;
  30927. if (null === $magicConstants) {
  30928. $magicConstants = [
  30929. T_LINE => '__LINE__',
  30930. T_FILE => '__FILE__',
  30931. T_DIR => '__DIR__',
  30932. T_FUNC_C => '__FUNCTION__',
  30933. T_CLASS_C => '__CLASS__',
  30934. T_METHOD_C => '__METHOD__',
  30935. T_NS_C => '__NAMESPACE__',
  30936. CT::T_CLASS_CONSTANT => 'class',
  30937. T_TRAIT_C => '__TRAIT__',
  30938. ];
  30939. }
  30940. return $magicConstants;
  30941. }
  30942. private function getMagicConstantTokens()
  30943. {
  30944. static $magicConstantTokens = null;
  30945. if (null === $magicConstantTokens) {
  30946. $magicConstantTokens = array_keys($this->getMagicConstants());
  30947. }
  30948. return $magicConstantTokens;
  30949. }
  30950. }
  30951. <?php
  30952. namespace PhpCsFixer\Fixer\Casing;
  30953. use PhpCsFixer\AbstractFixer;
  30954. use PhpCsFixer\FixerDefinition\CodeSample;
  30955. use PhpCsFixer\FixerDefinition\FixerDefinition;
  30956. use PhpCsFixer\Tokenizer\CT;
  30957. use PhpCsFixer\Tokenizer\Token;
  30958. use PhpCsFixer\Tokenizer\Tokens;
  30959. final class NativeFunctionCasingFixer extends AbstractFixer
  30960. {
  30961. public function getDefinition()
  30962. {
  30963. return new FixerDefinition(
  30964. 'Function defined by PHP should be called using the correct casing.',
  30965. [new CodeSample("<?php\nSTRLEN(\$str);\n")]
  30966. );
  30967. }
  30968. public function getPriority()
  30969. {
  30970. return 0;
  30971. }
  30972. public function isCandidate(Tokens $tokens)
  30973. {
  30974. return $tokens->isTokenKindFound(T_STRING);
  30975. }
  30976. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  30977. {
  30978. static $nativeFunctionNames = null;
  30979. if (null === $nativeFunctionNames) {
  30980. $nativeFunctionNames = $this->getNativeFunctionNames();
  30981. }
  30982. for ($index = 0, $count = $tokens->count(); $index < $count; ++$index) {
  30983. if (!$tokens[$index]->isGivenKind(T_STRING)) {
  30984. continue;
  30985. }
  30986. $next = $tokens->getNextMeaningfulToken($index);
  30987. if (!$tokens[$next]->equals('(')) {
  30988. $index = $next;
  30989. continue;
  30990. }
  30991. $functionNamePrefix = $tokens->getPrevMeaningfulToken($index);
  30992. if ($tokens[$functionNamePrefix]->isGivenKind([T_DOUBLE_COLON, T_NEW, T_OBJECT_OPERATOR, T_FUNCTION, CT::T_RETURN_REF])) {
  30993. continue;
  30994. }
  30995. if ($tokens[$functionNamePrefix]->isGivenKind(T_NS_SEPARATOR)) {
  30996. $prev = $tokens->getPrevMeaningfulToken($functionNamePrefix);
  30997. if ($tokens[$prev]->isGivenKind([T_STRING, T_NEW])) {
  30998. continue;
  30999. }
  31000. }
  31001. $lower = strtolower($tokens[$index]->getContent());
  31002. if (!\array_key_exists($lower, $nativeFunctionNames)) {
  31003. continue;
  31004. }
  31005. $tokens[$index] = new Token([T_STRING, $nativeFunctionNames[$lower]]);
  31006. $index = $next;
  31007. }
  31008. }
  31009. private function getNativeFunctionNames()
  31010. {
  31011. $allFunctions = get_defined_functions();
  31012. $functions = [];
  31013. foreach ($allFunctions['internal'] as $function) {
  31014. $functions[strtolower($function)] = $function;
  31015. }
  31016. return $functions;
  31017. }
  31018. }
  31019. <?php
  31020. namespace PhpCsFixer\Fixer\Casing;
  31021. use PhpCsFixer\AbstractFixer;
  31022. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  31023. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  31024. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  31025. use PhpCsFixer\FixerDefinition\CodeSample;
  31026. use PhpCsFixer\FixerDefinition\FixerDefinition;
  31027. use PhpCsFixer\Tokenizer\CT;
  31028. use PhpCsFixer\Tokenizer\Token;
  31029. use PhpCsFixer\Tokenizer\Tokens;
  31030. final class ConstantCaseFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface
  31031. {
  31032. private $fixFunction;
  31033. public function configure(array $configuration = null)
  31034. {
  31035. parent::configure($configuration);
  31036. if ('lower' === $this->configuration['case']) {
  31037. $this->fixFunction = static function ($token) {
  31038. return strtolower($token);
  31039. };
  31040. }
  31041. if ('upper' === $this->configuration['case']) {
  31042. $this->fixFunction = static function ($token) {
  31043. return strtoupper($token);
  31044. };
  31045. }
  31046. }
  31047. public function getDefinition()
  31048. {
  31049. return new FixerDefinition(
  31050. 'The PHP constants `true`, `false`, and `null` MUST be written using the correct casing.',
  31051. [new CodeSample("<?php\n\$a = FALSE;\n\$b = True;\n\$c = nuLL;\n")]
  31052. );
  31053. }
  31054. public function isCandidate(Tokens $tokens)
  31055. {
  31056. return $tokens->isTokenKindFound(T_STRING);
  31057. }
  31058. protected function createConfigurationDefinition()
  31059. {
  31060. return new FixerConfigurationResolver([
  31061. (new FixerOptionBuilder('case', 'Whether to use the `upper` or `lower` case syntax.'))
  31062. ->setAllowedValues(['upper', 'lower'])
  31063. ->setDefault('lower')
  31064. ->getOption(),
  31065. ]);
  31066. }
  31067. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  31068. {
  31069. $fixFunction = $this->fixFunction;
  31070. foreach ($tokens as $index => $token) {
  31071. if (!$token->isNativeConstant()) {
  31072. continue;
  31073. }
  31074. if (
  31075. $this->isNeighbourAccepted($tokens, $tokens->getPrevMeaningfulToken($index)) &&
  31076. $this->isNeighbourAccepted($tokens, $tokens->getNextMeaningfulToken($index))
  31077. ) {
  31078. $tokens[$index] = new Token([$token->getId(), $fixFunction($token->getContent())]);
  31079. }
  31080. }
  31081. }
  31082. private function isNeighbourAccepted(Tokens $tokens, $index)
  31083. {
  31084. static $forbiddenTokens = [
  31085. T_AS,
  31086. T_CLASS,
  31087. T_CONST,
  31088. T_EXTENDS,
  31089. T_IMPLEMENTS,
  31090. T_INSTANCEOF,
  31091. T_INSTEADOF,
  31092. T_INTERFACE,
  31093. T_NEW,
  31094. T_NS_SEPARATOR,
  31095. T_OBJECT_OPERATOR,
  31096. T_PAAMAYIM_NEKUDOTAYIM,
  31097. T_TRAIT,
  31098. T_USE,
  31099. CT::T_USE_TRAIT,
  31100. CT::T_USE_LAMBDA,
  31101. ];
  31102. $token = $tokens[$index];
  31103. if ($token->equalsAny(['{', '}'])) {
  31104. return false;
  31105. }
  31106. return !$token->isGivenKind($forbiddenTokens);
  31107. }
  31108. }
  31109. <?php
  31110. namespace PhpCsFixer\Fixer\Casing;
  31111. use PhpCsFixer\AbstractProxyFixer;
  31112. use PhpCsFixer\Fixer\DeprecatedFixerInterface;
  31113. use PhpCsFixer\FixerDefinition\CodeSample;
  31114. use PhpCsFixer\FixerDefinition\FixerDefinition;
  31115. final class LowercaseConstantsFixer extends AbstractProxyFixer implements DeprecatedFixerInterface
  31116. {
  31117. public function getDefinition()
  31118. {
  31119. return new FixerDefinition(
  31120. 'The PHP constants `true`, `false`, and `null` MUST be in lower case.',
  31121. [new CodeSample("<?php\n\$a = FALSE;\n\$b = True;\n\$c = nuLL;\n")]
  31122. );
  31123. }
  31124. public function getSuccessorsNames()
  31125. {
  31126. return array_keys($this->proxyFixers);
  31127. }
  31128. protected function createProxyFixers()
  31129. {
  31130. $fixer = new ConstantCaseFixer();
  31131. $fixer->configure(['case' => 'lower']);
  31132. return [$fixer];
  31133. }
  31134. }
  31135. <?php
  31136. namespace PhpCsFixer\Fixer\Casing;
  31137. use PhpCsFixer\AbstractFixer;
  31138. use PhpCsFixer\FixerDefinition\CodeSample;
  31139. use PhpCsFixer\FixerDefinition\FixerDefinition;
  31140. use PhpCsFixer\Tokenizer\Token;
  31141. use PhpCsFixer\Tokenizer\Tokens;
  31142. final class LowercaseKeywordsFixer extends AbstractFixer
  31143. {
  31144. private static $excludedTokens = [T_HALT_COMPILER];
  31145. public function getDefinition()
  31146. {
  31147. return new FixerDefinition(
  31148. 'PHP keywords MUST be in lower case.',
  31149. [
  31150. new CodeSample(
  31151. '<?php
  31152. FOREACH($a AS $B) {
  31153. TRY {
  31154. NEW $C($a, ISSET($B));
  31155. WHILE($B) {
  31156. INCLUDE "test.php";
  31157. }
  31158. } CATCH(\Exception $e) {
  31159. EXIT(1);
  31160. }
  31161. }
  31162. '
  31163. ),
  31164. ]
  31165. );
  31166. }
  31167. public function isCandidate(Tokens $tokens)
  31168. {
  31169. return $tokens->isAnyTokenKindsFound(Token::getKeywords());
  31170. }
  31171. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  31172. {
  31173. foreach ($tokens as $index => $token) {
  31174. if ($token->isKeyword() && !$token->isGivenKind(self::$excludedTokens)) {
  31175. $tokens[$index] = new Token([$token->getId(), strtolower($token->getContent())]);
  31176. }
  31177. }
  31178. }
  31179. }
  31180. <?php
  31181. namespace PhpCsFixer\Fixer\Casing;
  31182. use PhpCsFixer\AbstractFixer;
  31183. use PhpCsFixer\FixerDefinition\CodeSample;
  31184. use PhpCsFixer\FixerDefinition\FixerDefinition;
  31185. use PhpCsFixer\Tokenizer\Token;
  31186. use PhpCsFixer\Tokenizer\Tokens;
  31187. final class MagicMethodCasingFixer extends AbstractFixer
  31188. {
  31189. private static $magicNames = [
  31190. '__call' => '__call',
  31191. '__callstatic' => '__callStatic',
  31192. '__clone' => '__clone',
  31193. '__construct' => '__construct',
  31194. '__debuginfo' => '__debugInfo',
  31195. '__destruct' => '__destruct',
  31196. '__get' => '__get',
  31197. '__invoke' => '__invoke',
  31198. '__isset' => '__isset',
  31199. '__serialize' => '__serialize',
  31200. '__set' => '__set',
  31201. '__set_state' => '__set_state',
  31202. '__sleep' => '__sleep',
  31203. '__tostring' => '__toString',
  31204. '__unserialize' => '__unserialize',
  31205. '__unset' => '__unset',
  31206. '__wakeup' => '__wakeup',
  31207. ];
  31208. public function getDefinition()
  31209. {
  31210. return new FixerDefinition(
  31211. 'Magic method definitions and calls must be using the correct casing.',
  31212. [
  31213. new CodeSample(
  31214. '<?php
  31215. class Foo
  31216. {
  31217. public function __Sleep()
  31218. {
  31219. }
  31220. }
  31221. '
  31222. ),
  31223. new CodeSample(
  31224. '<?php
  31225. $foo->__INVOKE(1);
  31226. '
  31227. ),
  31228. ]
  31229. );
  31230. }
  31231. public function isCandidate(Tokens $tokens)
  31232. {
  31233. return $tokens->isTokenKindFound(T_STRING) && $tokens->isAnyTokenKindsFound([T_FUNCTION, T_OBJECT_OPERATOR, T_DOUBLE_COLON]);
  31234. }
  31235. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  31236. {
  31237. $inClass = 0;
  31238. $tokenCount = \count($tokens);
  31239. for ($index = 1; $index < $tokenCount - 2; ++$index) {
  31240. if (0 === $inClass && $tokens[$index]->isClassy()) {
  31241. $inClass = 1;
  31242. $index = $tokens->getNextTokenOfKind($index, ['{']);
  31243. continue;
  31244. }
  31245. if (0 !== $inClass) {
  31246. if ($tokens[$index]->equals('{')) {
  31247. ++$inClass;
  31248. continue;
  31249. }
  31250. if ($tokens[$index]->equals('}')) {
  31251. --$inClass;
  31252. continue;
  31253. }
  31254. }
  31255. if (!$tokens[$index]->isGivenKind(T_STRING)) {
  31256. continue;
  31257. }
  31258. $content = $tokens[$index]->getContent();
  31259. if ('__' !== substr($content, 0, 2)) {
  31260. continue;
  31261. }
  31262. $name = strtolower($content);
  31263. if (!$this->isMagicMethodName($name)) {
  31264. continue;
  31265. }
  31266. $nameInCorrectCasing = $this->getMagicMethodNameInCorrectCasing($name);
  31267. if ($nameInCorrectCasing === $content) {
  31268. continue;
  31269. }
  31270. if ($this->isFunctionSignature($tokens, $index)) {
  31271. if (0 !== $inClass) {
  31272. $this->setTokenToCorrectCasing($tokens, $index, $nameInCorrectCasing);
  31273. }
  31274. continue;
  31275. }
  31276. if ($this->isMethodCall($tokens, $index)) {
  31277. $this->setTokenToCorrectCasing($tokens, $index, $nameInCorrectCasing);
  31278. continue;
  31279. }
  31280. if (
  31281. ('__callstatic' === $name || '__set_state' === $name)
  31282. && $this->isStaticMethodCall($tokens, $index)
  31283. ) {
  31284. $this->setTokenToCorrectCasing($tokens, $index, $nameInCorrectCasing);
  31285. }
  31286. }
  31287. }
  31288. private function isFunctionSignature(Tokens $tokens, $index)
  31289. {
  31290. $prevIndex = $tokens->getPrevMeaningfulToken($index);
  31291. if (!$tokens[$prevIndex]->isGivenKind(T_FUNCTION)) {
  31292. return false;
  31293. }
  31294. return $tokens[$tokens->getNextMeaningfulToken($index)]->equals('(');
  31295. }
  31296. private function isMethodCall(Tokens $tokens, $index)
  31297. {
  31298. $prevIndex = $tokens->getPrevMeaningfulToken($index);
  31299. if (!$tokens[$prevIndex]->equals([T_OBJECT_OPERATOR, '->'])) {
  31300. return false;
  31301. }
  31302. return $tokens[$tokens->getNextMeaningfulToken($index)]->equals('(');
  31303. }
  31304. private function isStaticMethodCall(Tokens $tokens, $index)
  31305. {
  31306. $prevIndex = $tokens->getPrevMeaningfulToken($index);
  31307. if (!$tokens[$prevIndex]->isGivenKind(T_DOUBLE_COLON)) {
  31308. return false;
  31309. }
  31310. return $tokens[$tokens->getNextMeaningfulToken($index)]->equals('(');
  31311. }
  31312. private function isMagicMethodName($name)
  31313. {
  31314. return isset(self::$magicNames[$name]);
  31315. }
  31316. private function getMagicMethodNameInCorrectCasing($name)
  31317. {
  31318. return self::$magicNames[$name];
  31319. }
  31320. private function setTokenToCorrectCasing(Tokens $tokens, $index, $nameInCorrectCasing)
  31321. {
  31322. $tokens[$index] = new Token([T_STRING, $nameInCorrectCasing]);
  31323. }
  31324. }
  31325. <?php
  31326. namespace PhpCsFixer\Fixer\Casing;
  31327. use PhpCsFixer\AbstractFixer;
  31328. use PhpCsFixer\FixerDefinition\CodeSample;
  31329. use PhpCsFixer\FixerDefinition\FixerDefinition;
  31330. use PhpCsFixer\FixerDefinition\VersionSpecification;
  31331. use PhpCsFixer\FixerDefinition\VersionSpecificCodeSample;
  31332. use PhpCsFixer\Tokenizer\Token;
  31333. use PhpCsFixer\Tokenizer\Tokens;
  31334. final class LowercaseStaticReferenceFixer extends AbstractFixer
  31335. {
  31336. public function getDefinition()
  31337. {
  31338. return new FixerDefinition(
  31339. 'Class static references `self`, `static` and `parent` MUST be in lower case.',
  31340. [
  31341. new CodeSample('<?php
  31342. class Foo extends Bar
  31343. {
  31344. public function baz1()
  31345. {
  31346. return STATIC::baz2();
  31347. }
  31348. public function baz2($x)
  31349. {
  31350. return $x instanceof Self;
  31351. }
  31352. public function baz3(PaRent $x)
  31353. {
  31354. return true;
  31355. }
  31356. }
  31357. '),
  31358. new VersionSpecificCodeSample(
  31359. '<?php
  31360. class Foo extends Bar
  31361. {
  31362. public function baz(?self $x) : SELF
  31363. {
  31364. return false;
  31365. }
  31366. }
  31367. ',
  31368. new VersionSpecification(70100)
  31369. ),
  31370. ]
  31371. );
  31372. }
  31373. public function isCandidate(Tokens $tokens)
  31374. {
  31375. return $tokens->isAnyTokenKindsFound([T_STATIC, T_STRING]);
  31376. }
  31377. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  31378. {
  31379. foreach ($tokens as $index => $token) {
  31380. if (!$token->equalsAny([[T_STRING, 'self'], [T_STATIC, 'static'], [T_STRING, 'parent']], false)) {
  31381. continue;
  31382. }
  31383. $newContent = strtolower($token->getContent());
  31384. if ($token->getContent() === $newContent) {
  31385. continue;
  31386. }
  31387. $prevIndex = $tokens->getPrevMeaningfulToken($index);
  31388. if ($tokens[$prevIndex]->isGivenKind([T_CONST, T_DOUBLE_COLON, T_FUNCTION, T_NAMESPACE, T_NS_SEPARATOR, T_OBJECT_OPERATOR, T_PRIVATE, T_PROTECTED, T_PUBLIC])) {
  31389. continue;
  31390. }
  31391. $nextIndex = $tokens->getNextMeaningfulToken($index);
  31392. if ($tokens[$nextIndex]->isGivenKind([T_FUNCTION, T_NS_SEPARATOR, T_PRIVATE, T_PROTECTED, T_PUBLIC])) {
  31393. continue;
  31394. }
  31395. if ('static' === $newContent && $tokens[$nextIndex]->isGivenKind(T_VARIABLE)) {
  31396. continue;
  31397. }
  31398. $tokens[$index] = new Token([$token->getId(), $newContent]);
  31399. }
  31400. }
  31401. }
  31402. <?php
  31403. namespace PhpCsFixer\Fixer\Casing;
  31404. use PhpCsFixer\AbstractFixer;
  31405. use PhpCsFixer\FixerDefinition\CodeSample;
  31406. use PhpCsFixer\FixerDefinition\FixerDefinition;
  31407. use PhpCsFixer\FixerDefinition\VersionSpecification;
  31408. use PhpCsFixer\FixerDefinition\VersionSpecificCodeSample;
  31409. use PhpCsFixer\Tokenizer\Analyzer\Analysis\TypeAnalysis;
  31410. use PhpCsFixer\Tokenizer\Analyzer\FunctionsAnalyzer;
  31411. use PhpCsFixer\Tokenizer\Token;
  31412. use PhpCsFixer\Tokenizer\Tokens;
  31413. final class NativeFunctionTypeDeclarationCasingFixer extends AbstractFixer
  31414. {
  31415. private $hints;
  31416. private $functionsAnalyzer;
  31417. public function __construct()
  31418. {
  31419. parent::__construct();
  31420. $this->hints = [
  31421. 'array' => true,
  31422. 'callable' => true,
  31423. 'self' => true,
  31424. ];
  31425. if (\PHP_VERSION_ID >= 70000) {
  31426. $this->hints = array_merge(
  31427. $this->hints,
  31428. [
  31429. 'bool' => true,
  31430. 'float' => true,
  31431. 'int' => true,
  31432. 'string' => true,
  31433. ]
  31434. );
  31435. }
  31436. if (\PHP_VERSION_ID >= 70100) {
  31437. $this->hints = array_merge(
  31438. $this->hints,
  31439. [
  31440. 'iterable' => true,
  31441. 'void' => true,
  31442. ]
  31443. );
  31444. }
  31445. if (\PHP_VERSION_ID >= 70200) {
  31446. $this->hints = array_merge($this->hints, ['object' => true]);
  31447. }
  31448. $this->functionsAnalyzer = new FunctionsAnalyzer();
  31449. }
  31450. public function getDefinition()
  31451. {
  31452. return new FixerDefinition(
  31453. 'Native type hints for functions should use the correct case.',
  31454. [
  31455. new CodeSample("<?php\nclass Bar {\n public function Foo(CALLABLE \$bar)\n {\n return 1;\n }\n}\n"),
  31456. new VersionSpecificCodeSample(
  31457. "<?php\nfunction Foo(INT \$a): Bool\n{\n return true;\n}\n",
  31458. new VersionSpecification(70000)
  31459. ),
  31460. new VersionSpecificCodeSample(
  31461. "<?php\nfunction Foo(Iterable \$a): VOID\n{\n echo 'Hello world';\n}\n",
  31462. new VersionSpecification(70100)
  31463. ),
  31464. new VersionSpecificCodeSample(
  31465. "<?php\nfunction Foo(Object \$a)\n{\n return 'hi!';\n}\n",
  31466. new VersionSpecification(70200)
  31467. ),
  31468. ]
  31469. );
  31470. }
  31471. public function isCandidate(Tokens $tokens)
  31472. {
  31473. return $tokens->isAllTokenKindsFound([T_FUNCTION, T_STRING]);
  31474. }
  31475. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  31476. {
  31477. for ($index = $tokens->count() - 1; $index >= 0; --$index) {
  31478. if ($tokens[$index]->isGivenKind(T_FUNCTION)) {
  31479. if (\PHP_VERSION_ID >= 70000) {
  31480. $this->fixFunctionReturnType($tokens, $index);
  31481. }
  31482. $this->fixFunctionArgumentTypes($tokens, $index);
  31483. }
  31484. }
  31485. }
  31486. private function fixFunctionArgumentTypes(Tokens $tokens, $index)
  31487. {
  31488. foreach ($this->functionsAnalyzer->getFunctionArguments($tokens, $index) as $argument) {
  31489. $this->fixArgumentType($tokens, $argument->getTypeAnalysis());
  31490. }
  31491. }
  31492. private function fixFunctionReturnType(Tokens $tokens, $index)
  31493. {
  31494. $this->fixArgumentType($tokens, $this->functionsAnalyzer->getFunctionReturnType($tokens, $index));
  31495. }
  31496. private function fixArgumentType(Tokens $tokens, TypeAnalysis $type = null)
  31497. {
  31498. if (null === $type) {
  31499. return;
  31500. }
  31501. $argumentIndex = $type->getStartIndex();
  31502. if ($argumentIndex !== $type->getEndIndex()) {
  31503. return;
  31504. }
  31505. $lowerCasedName = strtolower($type->getName());
  31506. if (!isset($this->hints[$lowerCasedName])) {
  31507. return;
  31508. }
  31509. $tokens[$argumentIndex] = new Token([$tokens[$argumentIndex]->getId(), $lowerCasedName]);
  31510. }
  31511. }
  31512. <?php
  31513. namespace PhpCsFixer\Fixer\NamespaceNotation;
  31514. use PhpCsFixer\AbstractFixer;
  31515. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  31516. use PhpCsFixer\FixerDefinition\CodeSample;
  31517. use PhpCsFixer\FixerDefinition\FixerDefinition;
  31518. use PhpCsFixer\Preg;
  31519. use PhpCsFixer\Tokenizer\Token;
  31520. use PhpCsFixer\Tokenizer\Tokens;
  31521. final class BlankLineAfterNamespaceFixer extends AbstractFixer implements WhitespacesAwareFixerInterface
  31522. {
  31523. public function getDefinition()
  31524. {
  31525. return new FixerDefinition(
  31526. 'There MUST be one blank line after the namespace declaration.',
  31527. [
  31528. new CodeSample("<?php\nnamespace Sample\\Sample;\n\n\n\$a;\n"),
  31529. new CodeSample("<?php\nnamespace Sample\\Sample;\nClass Test{}\n"),
  31530. ]
  31531. );
  31532. }
  31533. public function getPriority()
  31534. {
  31535. return -20;
  31536. }
  31537. public function isCandidate(Tokens $tokens)
  31538. {
  31539. return $tokens->isTokenKindFound(T_NAMESPACE);
  31540. }
  31541. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  31542. {
  31543. $lastIndex = $tokens->count() - 1;
  31544. for ($index = $lastIndex; $index >= 0; --$index) {
  31545. $token = $tokens[$index];
  31546. if (!$token->isGivenKind(T_NAMESPACE)) {
  31547. continue;
  31548. }
  31549. $semicolonIndex = $tokens->getNextTokenOfKind($index, [';', '{', [T_CLOSE_TAG]]);
  31550. $semicolonToken = $tokens[$semicolonIndex];
  31551. if (!$semicolonToken->equals(';')) {
  31552. continue;
  31553. }
  31554. $indexToEnsureBlankLineAfter = $this->getIndexToEnsureBlankLineAfter($tokens, $semicolonIndex);
  31555. $indexToEnsureBlankLine = $tokens->getNonEmptySibling($indexToEnsureBlankLineAfter, 1);
  31556. if (null !== $indexToEnsureBlankLine && $tokens[$indexToEnsureBlankLine]->isWhitespace()) {
  31557. $tokens[$indexToEnsureBlankLine] = $this->getTokenToInsert($tokens[$indexToEnsureBlankLine]->getContent(), $indexToEnsureBlankLine === $lastIndex);
  31558. } else {
  31559. $tokens->insertAt($indexToEnsureBlankLineAfter + 1, $this->getTokenToInsert('', $indexToEnsureBlankLineAfter === $lastIndex));
  31560. }
  31561. }
  31562. }
  31563. private function getIndexToEnsureBlankLineAfter(Tokens $tokens, $index)
  31564. {
  31565. $indexToEnsureBlankLine = $index;
  31566. $nextIndex = $tokens->getNonEmptySibling($indexToEnsureBlankLine, 1);
  31567. while (null !== $nextIndex) {
  31568. $token = $tokens[$nextIndex];
  31569. if ($token->isWhitespace()) {
  31570. if (1 === Preg::match('/\R/', $token->getContent())) {
  31571. break;
  31572. }
  31573. $nextNextIndex = $tokens->getNonEmptySibling($nextIndex, 1);
  31574. if (!$tokens[$nextNextIndex]->isComment()) {
  31575. break;
  31576. }
  31577. }
  31578. if (!$token->isWhitespace() && !$token->isComment()) {
  31579. break;
  31580. }
  31581. $indexToEnsureBlankLine = $nextIndex;
  31582. $nextIndex = $tokens->getNonEmptySibling($indexToEnsureBlankLine, 1);
  31583. }
  31584. return $indexToEnsureBlankLine;
  31585. }
  31586. private function getTokenToInsert($currentContent, $isLastIndex)
  31587. {
  31588. $ending = $this->whitespacesConfig->getLineEnding();
  31589. $emptyLines = $isLastIndex ? $ending : $ending.$ending;
  31590. $indent = 1 === Preg::match('/^.*\R( *)$/s', $currentContent, $matches) ? $matches[1] : '';
  31591. return new Token([T_WHITESPACE, $emptyLines.$indent]);
  31592. }
  31593. }
  31594. <?php
  31595. namespace PhpCsFixer\Fixer\NamespaceNotation;
  31596. use PhpCsFixer\AbstractFixer;
  31597. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  31598. use PhpCsFixer\FixerDefinition\CodeSample;
  31599. use PhpCsFixer\FixerDefinition\FixerDefinition;
  31600. use PhpCsFixer\Tokenizer\Token;
  31601. use PhpCsFixer\Tokenizer\Tokens;
  31602. /**
  31603. @gmail
  31604. */
  31605. final class NoLeadingNamespaceWhitespaceFixer extends AbstractFixer implements WhitespacesAwareFixerInterface
  31606. {
  31607. public function isCandidate(Tokens $tokens)
  31608. {
  31609. return $tokens->isTokenKindFound(T_NAMESPACE);
  31610. }
  31611. public function getDefinition()
  31612. {
  31613. return new FixerDefinition(
  31614. 'The namespace declaration line shouldn\'t contain leading whitespace.',
  31615. [
  31616. new CodeSample(
  31617. '<?php
  31618. namespace Test8a;
  31619. namespace Test8b;
  31620. '
  31621. ),
  31622. ]
  31623. );
  31624. }
  31625. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  31626. {
  31627. for ($index = \count($tokens) - 1; 0 <= $index; --$index) {
  31628. $token = $tokens[$index];
  31629. if (!$token->isGivenKind(T_NAMESPACE)) {
  31630. continue;
  31631. }
  31632. $beforeNamespaceIndex = $index - 1;
  31633. $beforeNamespace = $tokens[$beforeNamespaceIndex];
  31634. if (!$beforeNamespace->isWhitespace()) {
  31635. if (!self::endsWithWhitespace($beforeNamespace->getContent())) {
  31636. $tokens->insertAt($index, new Token([T_WHITESPACE, $this->whitespacesConfig->getLineEnding()]));
  31637. }
  31638. continue;
  31639. }
  31640. $lastNewline = strrpos($beforeNamespace->getContent(), "\n");
  31641. if (false === $lastNewline) {
  31642. $beforeBeforeNamespace = $tokens[$index - 2];
  31643. if (self::endsWithWhitespace($beforeBeforeNamespace->getContent())) {
  31644. $tokens->clearAt($beforeNamespaceIndex);
  31645. } else {
  31646. $tokens[$beforeNamespaceIndex] = new Token([T_WHITESPACE, ' ']);
  31647. }
  31648. } else {
  31649. $tokens[$beforeNamespaceIndex] = new Token([T_WHITESPACE, substr($beforeNamespace->getContent(), 0, $lastNewline + 1)]);
  31650. }
  31651. }
  31652. }
  31653. private static function endsWithWhitespace($str)
  31654. {
  31655. if ('' === $str) {
  31656. return false;
  31657. }
  31658. return '' === trim(substr($str, -1));
  31659. }
  31660. }
  31661. <?php
  31662. namespace PhpCsFixer\Fixer\NamespaceNotation;
  31663. use PhpCsFixer\AbstractLinesBeforeNamespaceFixer;
  31664. use PhpCsFixer\FixerDefinition\CodeSample;
  31665. use PhpCsFixer\FixerDefinition\FixerDefinition;
  31666. use PhpCsFixer\Tokenizer\Tokens;
  31667. final class SingleBlankLineBeforeNamespaceFixer extends AbstractLinesBeforeNamespaceFixer
  31668. {
  31669. public function getDefinition()
  31670. {
  31671. return new FixerDefinition(
  31672. 'There should be exactly one blank line before a namespace declaration.',
  31673. [
  31674. new CodeSample("<?php namespace A {}\n"),
  31675. new CodeSample("<?php\n\n\nnamespace A{}\n"),
  31676. ]
  31677. );
  31678. }
  31679. public function isCandidate(Tokens $tokens)
  31680. {
  31681. return $tokens->isTokenKindFound(T_NAMESPACE);
  31682. }
  31683. public function getPriority()
  31684. {
  31685. return -21;
  31686. }
  31687. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  31688. {
  31689. for ($index = $tokens->count() - 1; $index >= 0; --$index) {
  31690. $token = $tokens[$index];
  31691. if ($token->isGivenKind(T_NAMESPACE)) {
  31692. $this->fixLinesBeforeNamespace($tokens, $index, 2, 2);
  31693. }
  31694. }
  31695. }
  31696. }
  31697. <?php
  31698. namespace PhpCsFixer\Fixer\NamespaceNotation;
  31699. use PhpCsFixer\AbstractLinesBeforeNamespaceFixer;
  31700. use PhpCsFixer\FixerDefinition\CodeSample;
  31701. use PhpCsFixer\FixerDefinition\FixerDefinition;
  31702. use PhpCsFixer\Tokenizer\Tokens;
  31703. final class NoBlankLinesBeforeNamespaceFixer extends AbstractLinesBeforeNamespaceFixer
  31704. {
  31705. public function isCandidate(Tokens $tokens)
  31706. {
  31707. return $tokens->isTokenKindFound(T_NAMESPACE);
  31708. }
  31709. public function getDefinition()
  31710. {
  31711. return new FixerDefinition(
  31712. 'There should be no blank lines before a namespace declaration.',
  31713. [
  31714. new CodeSample(
  31715. "<?php\n\n\n\nnamespace Example;\n"
  31716. ),
  31717. ]
  31718. );
  31719. }
  31720. public function getPriority()
  31721. {
  31722. return 0;
  31723. }
  31724. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  31725. {
  31726. for ($index = 0, $limit = $tokens->count(); $index < $limit; ++$index) {
  31727. $token = $tokens[$index];
  31728. if (!$token->isGivenKind(T_NAMESPACE)) {
  31729. continue;
  31730. }
  31731. $this->fixLinesBeforeNamespace($tokens, $index, 0, 1);
  31732. }
  31733. }
  31734. }
  31735. <?php
  31736. namespace PhpCsFixer\Fixer\CastNotation;
  31737. use PhpCsFixer\AbstractFixer;
  31738. use PhpCsFixer\FixerDefinition\FixerDefinition;
  31739. use PhpCsFixer\FixerDefinition\VersionSpecification;
  31740. use PhpCsFixer\FixerDefinition\VersionSpecificCodeSample;
  31741. use PhpCsFixer\Tokenizer\Token;
  31742. use PhpCsFixer\Tokenizer\Tokens;
  31743. final class LowercaseCastFixer extends AbstractFixer
  31744. {
  31745. public function getDefinition()
  31746. {
  31747. return new FixerDefinition(
  31748. 'Cast should be written in lower case.',
  31749. [
  31750. new VersionSpecificCodeSample(
  31751. '<?php
  31752. $a = (BOOLEAN) $b;
  31753. $a = (BOOL) $b;
  31754. $a = (INTEGER) $b;
  31755. $a = (INT) $b;
  31756. $a = (DOUBLE) $b;
  31757. $a = (FLoaT) $b;
  31758. $a = (reaL) $b;
  31759. $a = (flOAT) $b;
  31760. $a = (sTRING) $b;
  31761. $a = (ARRAy) $b;
  31762. $a = (OBJect) $b;
  31763. $a = (UNset) $b;
  31764. $a = (Binary) $b;
  31765. ',
  31766. new VersionSpecification(null, 70399)
  31767. ),
  31768. new VersionSpecificCodeSample(
  31769. '<?php
  31770. $a = (BOOLEAN) $b;
  31771. $a = (BOOL) $b;
  31772. $a = (INTEGER) $b;
  31773. $a = (INT) $b;
  31774. $a = (DOUBLE) $b;
  31775. $a = (FLoaT) $b;
  31776. $a = (flOAT) $b;
  31777. $a = (sTRING) $b;
  31778. $a = (ARRAy) $b;
  31779. $a = (OBJect) $b;
  31780. $a = (UNset) $b;
  31781. $a = (Binary) $b;
  31782. ',
  31783. new VersionSpecification(70400)
  31784. ),
  31785. ]
  31786. );
  31787. }
  31788. public function isCandidate(Tokens $tokens)
  31789. {
  31790. return $tokens->isAnyTokenKindsFound(Token::getCastTokenKinds());
  31791. }
  31792. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  31793. {
  31794. for ($index = 0, $count = $tokens->count(); $index < $count; ++$index) {
  31795. if (!$tokens[$index]->isCast()) {
  31796. continue;
  31797. }
  31798. $tokens[$index] = new Token([$tokens[$index]->getId(), strtolower($tokens[$index]->getContent())]);
  31799. }
  31800. }
  31801. }
  31802. <?php
  31803. namespace PhpCsFixer\Fixer\CastNotation;
  31804. use PhpCsFixer\AbstractFixer;
  31805. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  31806. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  31807. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  31808. use PhpCsFixer\FixerDefinition\CodeSample;
  31809. use PhpCsFixer\FixerDefinition\FixerDefinition;
  31810. use PhpCsFixer\Tokenizer\Token;
  31811. use PhpCsFixer\Tokenizer\Tokens;
  31812. final class CastSpacesFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface
  31813. {
  31814. const INSIDE_CAST_SPACE_REPLACE_MAP = [
  31815. ' ' => '',
  31816. "\t" => '',
  31817. "\n" => '',
  31818. "\r" => '',
  31819. "\0" => '',
  31820. "\x0B" => '',
  31821. ];
  31822. public function getDefinition()
  31823. {
  31824. return new FixerDefinition(
  31825. 'A single space or none should be between cast and variable.',
  31826. [
  31827. new CodeSample(
  31828. "<?php\n\$bar = ( string ) \$a;\n\$foo = (int)\$b;\n"
  31829. ),
  31830. new CodeSample(
  31831. "<?php\n\$bar = ( string ) \$a;\n\$foo = (int)\$b;\n",
  31832. ['space' => 'single']
  31833. ),
  31834. new CodeSample(
  31835. "<?php\n\$bar = ( string ) \$a;\n\$foo = (int) \$b;\n",
  31836. ['space' => 'none']
  31837. ),
  31838. ]
  31839. );
  31840. }
  31841. public function getPriority()
  31842. {
  31843. return -10;
  31844. }
  31845. public function isCandidate(Tokens $tokens)
  31846. {
  31847. return $tokens->isAnyTokenKindsFound(Token::getCastTokenKinds());
  31848. }
  31849. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  31850. {
  31851. foreach ($tokens as $index => $token) {
  31852. if (!$token->isCast()) {
  31853. continue;
  31854. }
  31855. $tokens[$index] = new Token([
  31856. $token->getId(),
  31857. strtr($token->getContent(), self::INSIDE_CAST_SPACE_REPLACE_MAP),
  31858. ]);
  31859. if ('single' === $this->configuration['space']) {
  31860. if ($tokens[$index + 1]->isWhitespace(" \t")) {
  31861. $tokens[$index + 1] = new Token([T_WHITESPACE, ' ']);
  31862. } elseif (!$tokens[$index + 1]->isWhitespace()) {
  31863. $tokens->insertAt($index + 1, new Token([T_WHITESPACE, ' ']));
  31864. }
  31865. continue;
  31866. }
  31867. if ($tokens[$index + 1]->isWhitespace()) {
  31868. $tokens->clearAt($index + 1);
  31869. }
  31870. }
  31871. }
  31872. protected function createConfigurationDefinition()
  31873. {
  31874. return new FixerConfigurationResolver([
  31875. (new FixerOptionBuilder('space', 'spacing to apply between cast and variable.'))
  31876. ->setAllowedValues(['none', 'single'])
  31877. ->setDefault('single')
  31878. ->getOption(),
  31879. ]);
  31880. }
  31881. }
  31882. <?php
  31883. namespace PhpCsFixer\Fixer\CastNotation;
  31884. use PhpCsFixer\AbstractFixer;
  31885. use PhpCsFixer\FixerDefinition\CodeSample;
  31886. use PhpCsFixer\FixerDefinition\FixerDefinition;
  31887. use PhpCsFixer\Tokenizer\Token;
  31888. use PhpCsFixer\Tokenizer\Tokens;
  31889. final class NoUnsetCastFixer extends AbstractFixer
  31890. {
  31891. public function getDefinition()
  31892. {
  31893. return new FixerDefinition(
  31894. 'Variables must be set `null` instead of using `(unset)` casting.',
  31895. [new CodeSample("<?php\n\$a = (unset) \$b;\n")]
  31896. );
  31897. }
  31898. public function isCandidate(Tokens $tokens)
  31899. {
  31900. return $tokens->isTokenKindFound(T_UNSET_CAST);
  31901. }
  31902. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  31903. {
  31904. for ($index = \count($tokens) - 1; $index > 0; --$index) {
  31905. if ($tokens[$index]->isGivenKind(T_UNSET_CAST)) {
  31906. $this->fixUnsetCast($tokens, $index);
  31907. }
  31908. }
  31909. }
  31910. private function fixUnsetCast(Tokens $tokens, $index)
  31911. {
  31912. $assignmentIndex = $tokens->getPrevMeaningfulToken($index);
  31913. if (null === $assignmentIndex || !$tokens[$assignmentIndex]->equals('=')) {
  31914. return;
  31915. }
  31916. $varIndex = $tokens->getNextMeaningfulToken($index);
  31917. if (null === $varIndex || !$tokens[$varIndex]->isGivenKind(T_VARIABLE)) {
  31918. return;
  31919. }
  31920. $afterVar = $tokens->getNextMeaningfulToken($varIndex);
  31921. if (null === $afterVar || !$tokens[$afterVar]->equalsAny([';', [T_CLOSE_TAG]])) {
  31922. return;
  31923. }
  31924. $nextIsWhiteSpace = $tokens[$assignmentIndex + 1]->isWhitespace();
  31925. $tokens->clearTokenAndMergeSurroundingWhitespace($index);
  31926. $tokens->clearTokenAndMergeSurroundingWhitespace($varIndex);
  31927. ++$assignmentIndex;
  31928. if (!$nextIsWhiteSpace) {
  31929. $tokens->insertAt($assignmentIndex, new Token([T_WHITESPACE, ' ']));
  31930. }
  31931. ++$assignmentIndex;
  31932. $tokens->insertAt($assignmentIndex, new Token([T_STRING, 'null']));
  31933. }
  31934. }
  31935. <?php
  31936. namespace PhpCsFixer\Fixer\CastNotation;
  31937. use PhpCsFixer\AbstractFixer;
  31938. use PhpCsFixer\FixerDefinition\CodeSample;
  31939. use PhpCsFixer\FixerDefinition\FixerDefinition;
  31940. use PhpCsFixer\Tokenizer\Token;
  31941. use PhpCsFixer\Tokenizer\Tokens;
  31942. final class NoShortBoolCastFixer extends AbstractFixer
  31943. {
  31944. public function getPriority()
  31945. {
  31946. return -9;
  31947. }
  31948. public function getDefinition()
  31949. {
  31950. return new FixerDefinition(
  31951. 'Short cast `bool` using double exclamation mark should not be used.',
  31952. [new CodeSample("<?php\n\$a = !!\$b;\n")]
  31953. );
  31954. }
  31955. public function isCandidate(Tokens $tokens)
  31956. {
  31957. return $tokens->isTokenKindFound('!');
  31958. }
  31959. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  31960. {
  31961. for ($index = \count($tokens) - 1; $index > 1; --$index) {
  31962. if ($tokens[$index]->equals('!')) {
  31963. $index = $this->fixShortCast($tokens, $index);
  31964. }
  31965. }
  31966. }
  31967. private function fixShortCast(Tokens $tokens, $index)
  31968. {
  31969. for ($i = $index - 1; $i > 1; --$i) {
  31970. if ($tokens[$i]->equals('!')) {
  31971. $this->fixShortCastToBoolCast($tokens, $i, $index);
  31972. break;
  31973. }
  31974. if (!$tokens[$i]->isComment() && !$tokens[$i]->isWhitespace()) {
  31975. break;
  31976. }
  31977. }
  31978. return $i;
  31979. }
  31980. private function fixShortCastToBoolCast(Tokens $tokens, $start, $end)
  31981. {
  31982. for (; $start <= $end; ++$start) {
  31983. if (
  31984. !$tokens[$start]->isComment()
  31985. && !($tokens[$start]->isWhitespace() && $tokens[$start - 1]->isComment())
  31986. ) {
  31987. $tokens->clearAt($start);
  31988. }
  31989. }
  31990. $tokens->insertAt($start, new Token([T_BOOL_CAST, '(bool)']));
  31991. }
  31992. }
  31993. <?php
  31994. namespace PhpCsFixer\Fixer\CastNotation;
  31995. use PhpCsFixer\AbstractFixer;
  31996. use PhpCsFixer\FixerDefinition\FixerDefinition;
  31997. use PhpCsFixer\FixerDefinition\VersionSpecification;
  31998. use PhpCsFixer\FixerDefinition\VersionSpecificCodeSample;
  31999. use PhpCsFixer\Tokenizer\Token;
  32000. use PhpCsFixer\Tokenizer\Tokens;
  32001. final class ShortScalarCastFixer extends AbstractFixer
  32002. {
  32003. public function getDefinition()
  32004. {
  32005. return new FixerDefinition(
  32006. 'Cast `(boolean)` and `(integer)` should be written as `(bool)` and `(int)`, `(double)` and `(real)` as `(float)`, `(binary)` as `(string)`.',
  32007. [
  32008. new VersionSpecificCodeSample(
  32009. "<?php\n\$a = (boolean) \$b;\n\$a = (integer) \$b;\n\$a = (double) \$b;\n\$a = (real) \$b;\n\n\$a = (binary) \$b;\n",
  32010. new VersionSpecification(null, 70399)
  32011. ),
  32012. new VersionSpecificCodeSample(
  32013. "<?php\n\$a = (boolean) \$b;\n\$a = (integer) \$b;\n\$a = (double) \$b;\n\n\$a = (binary) \$b;\n",
  32014. new VersionSpecification(70400)
  32015. ),
  32016. ]
  32017. );
  32018. }
  32019. public function isCandidate(Tokens $tokens)
  32020. {
  32021. return $tokens->isAnyTokenKindsFound(Token::getCastTokenKinds());
  32022. }
  32023. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  32024. {
  32025. static $castMap = [
  32026. 'boolean' => 'bool',
  32027. 'integer' => 'int',
  32028. 'double' => 'float',
  32029. 'real' => 'float',
  32030. 'binary' => 'string',
  32031. ];
  32032. for ($index = 0, $count = $tokens->count(); $index < $count; ++$index) {
  32033. if (!$tokens[$index]->isCast()) {
  32034. continue;
  32035. }
  32036. $castFrom = trim(substr($tokens[$index]->getContent(), 1, -1));
  32037. $castFromLowered = strtolower($castFrom);
  32038. if (!\array_key_exists($castFromLowered, $castMap)) {
  32039. continue;
  32040. }
  32041. $tokens[$index] = new Token([
  32042. $tokens[$index]->getId(),
  32043. str_replace($castFrom, $castMap[$castFromLowered], $tokens[$index]->getContent()),
  32044. ]);
  32045. }
  32046. }
  32047. }
  32048. <?php
  32049. namespace PhpCsFixer\Fixer\CastNotation;
  32050. use PhpCsFixer\AbstractFunctionReferenceFixer;
  32051. use PhpCsFixer\FixerDefinition\CodeSample;
  32052. use PhpCsFixer\FixerDefinition\FixerDefinition;
  32053. use PhpCsFixer\Tokenizer\Analyzer\ArgumentsAnalyzer;
  32054. use PhpCsFixer\Tokenizer\Token;
  32055. use PhpCsFixer\Tokenizer\Tokens;
  32056. final class ModernizeTypesCastingFixer extends AbstractFunctionReferenceFixer
  32057. {
  32058. public function getDefinition()
  32059. {
  32060. return new FixerDefinition(
  32061. 'Replaces `intval`, `floatval`, `doubleval`, `strval` and `boolval` function calls with according type casting operator.',
  32062. [
  32063. new CodeSample(
  32064. '<?php
  32065. $a = intval($b);
  32066. $a = floatval($b);
  32067. $a = doubleval($b);
  32068. $a = strval ($b);
  32069. $a = boolval($b);
  32070. '
  32071. ),
  32072. ],
  32073. null,
  32074. 'Risky if any of the functions `intval`, `floatval`, `doubleval`, `strval` or `boolval` are overridden.'
  32075. );
  32076. }
  32077. public function isCandidate(Tokens $tokens)
  32078. {
  32079. return $tokens->isTokenKindFound(T_STRING);
  32080. }
  32081. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  32082. {
  32083. static $replacement = [
  32084. 'intval' => [T_INT_CAST, '(int)'],
  32085. 'floatval' => [T_DOUBLE_CAST, '(float)'],
  32086. 'doubleval' => [T_DOUBLE_CAST, '(float)'],
  32087. 'strval' => [T_STRING_CAST, '(string)'],
  32088. 'boolval' => [T_BOOL_CAST, '(bool)'],
  32089. ];
  32090. $argumentsAnalyzer = new ArgumentsAnalyzer();
  32091. foreach ($replacement as $functionIdentity => $newToken) {
  32092. $currIndex = 0;
  32093. while (null !== $currIndex) {
  32094. $boundaries = $this->find($functionIdentity, $tokens, $currIndex, $tokens->count() - 1);
  32095. if (null === $boundaries) {
  32096. continue 2;
  32097. }
  32098. list($functionName, $openParenthesis, $closeParenthesis) = $boundaries;
  32099. $currIndex = $openParenthesis;
  32100. if (1 !== $argumentsAnalyzer->countArguments($tokens, $openParenthesis, $closeParenthesis)) {
  32101. continue;
  32102. }
  32103. $paramContentEnd = $closeParenthesis;
  32104. $commaCandidate = $tokens->getPrevMeaningfulToken($paramContentEnd);
  32105. if ($tokens[$commaCandidate]->equals(',')) {
  32106. $tokens->removeTrailingWhitespace($commaCandidate);
  32107. $tokens->clearAt($commaCandidate);
  32108. $paramContentEnd = $commaCandidate;
  32109. }
  32110. $countParamTokens = 0;
  32111. for ($paramContentIndex = $openParenthesis + 1; $paramContentIndex < $paramContentEnd; ++$paramContentIndex) {
  32112. if (!$tokens[$paramContentIndex]->isGivenKind(T_WHITESPACE)) {
  32113. ++$countParamTokens;
  32114. }
  32115. }
  32116. $preserveParenthesises = $countParamTokens > 1;
  32117. $afterCloseParenthesisIndex = $tokens->getNextMeaningfulToken($closeParenthesis);
  32118. $afterCloseParenthesisToken = $tokens[$afterCloseParenthesisIndex];
  32119. $wrapInParenthesises = $afterCloseParenthesisToken->equalsAny(['[', '{']) || $afterCloseParenthesisToken->isGivenKind(T_POW);
  32120. $prevTokenIndex = $tokens->getPrevMeaningfulToken($functionName);
  32121. if ($tokens[$prevTokenIndex]->isGivenKind(T_NS_SEPARATOR)) {
  32122. $tokens->removeTrailingWhitespace($prevTokenIndex);
  32123. $tokens->clearAt($prevTokenIndex);
  32124. }
  32125. $replacementSequence = [
  32126. new Token($newToken),
  32127. new Token([T_WHITESPACE, ' ']),
  32128. ];
  32129. if ($wrapInParenthesises) {
  32130. array_unshift($replacementSequence, new Token('('));
  32131. }
  32132. if (!$preserveParenthesises) {
  32133. $tokens->removeLeadingWhitespace($closeParenthesis);
  32134. $tokens->clearAt($closeParenthesis);
  32135. $tokens->removeLeadingWhitespace($openParenthesis);
  32136. $tokens->removeTrailingWhitespace($openParenthesis);
  32137. $tokens->clearAt($openParenthesis);
  32138. } else {
  32139. $tokens->removeTrailingWhitespace($functionName);
  32140. }
  32141. if ($wrapInParenthesises) {
  32142. $tokens->insertAt($closeParenthesis, new Token(')'));
  32143. }
  32144. $tokens->overrideRange($functionName, $functionName, $replacementSequence);
  32145. $currIndex = $functionName;
  32146. }
  32147. }
  32148. }
  32149. }
  32150. <?php
  32151. namespace PhpCsFixer\Fixer\ControlStructure;
  32152. use PhpCsFixer\AbstractFixer;
  32153. use PhpCsFixer\FixerDefinition\CodeSample;
  32154. use PhpCsFixer\FixerDefinition\FixerDefinition;
  32155. use PhpCsFixer\Tokenizer\Analyzer\BlocksAnalyzer;
  32156. use PhpCsFixer\Tokenizer\Token;
  32157. use PhpCsFixer\Tokenizer\Tokens;
  32158. /**
  32159. @gmail
  32160. @gmail
  32161. */
  32162. final class IncludeFixer extends AbstractFixer
  32163. {
  32164. public function getDefinition()
  32165. {
  32166. return new FixerDefinition(
  32167. 'Include/Require and file path should be divided with a single space. File path should not be placed under brackets.',
  32168. [
  32169. new CodeSample(
  32170. '<?php
  32171. require ("sample1.php");
  32172. require_once "sample2.php";
  32173. include "sample3.php";
  32174. include_once("sample4.php");
  32175. '
  32176. ),
  32177. ]
  32178. );
  32179. }
  32180. public function isCandidate(Tokens $tokens)
  32181. {
  32182. return $tokens->isAnyTokenKindsFound([T_REQUIRE, T_REQUIRE_ONCE, T_INCLUDE, T_INCLUDE_ONCE]);
  32183. }
  32184. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  32185. {
  32186. $this->clearIncludies($tokens, $this->findIncludies($tokens));
  32187. }
  32188. private function clearIncludies(Tokens $tokens, array $includies)
  32189. {
  32190. $blocksAnalyzer = new BlocksAnalyzer();
  32191. foreach ($includies as $includy) {
  32192. if ($includy['end'] && !$tokens[$includy['end']]->isGivenKind(T_CLOSE_TAG)) {
  32193. $afterEndIndex = $tokens->getNextNonWhitespace($includy['end']);
  32194. if (null === $afterEndIndex || !$tokens[$afterEndIndex]->isComment()) {
  32195. $tokens->removeLeadingWhitespace($includy['end']);
  32196. }
  32197. }
  32198. $braces = $includy['braces'];
  32199. if (null !== $braces) {
  32200. $prevIndex = $tokens->getPrevMeaningfulToken($includy['begin']);
  32201. $nextIndex = $tokens->getNextMeaningfulToken($braces['close']);
  32202. if (!$tokens[$nextIndex]->equalsAny([';', [T_CLOSE_TAG]]) && !$blocksAnalyzer->isBlock($tokens, $prevIndex, $nextIndex)) {
  32203. continue;
  32204. }
  32205. $this->removeWhitespaceAroundIfPossible($tokens, $braces['open']);
  32206. $this->removeWhitespaceAroundIfPossible($tokens, $braces['close']);
  32207. $tokens->clearTokenAndMergeSurroundingWhitespace($braces['open']);
  32208. $tokens->clearTokenAndMergeSurroundingWhitespace($braces['close']);
  32209. }
  32210. $nextIndex = $tokens->getNonEmptySibling($includy['begin'], 1);
  32211. if ($tokens[$nextIndex]->isWhitespace()) {
  32212. $tokens[$nextIndex] = new Token([T_WHITESPACE, ' ']);
  32213. } elseif (null !== $braces || $tokens[$nextIndex]->isGivenKind([T_VARIABLE, T_CONSTANT_ENCAPSED_STRING, T_COMMENT])) {
  32214. $tokens->insertAt($includy['begin'] + 1, new Token([T_WHITESPACE, ' ']));
  32215. }
  32216. }
  32217. }
  32218. private function findIncludies(Tokens $tokens)
  32219. {
  32220. static $includyTokenKinds = [T_REQUIRE, T_REQUIRE_ONCE, T_INCLUDE, T_INCLUDE_ONCE];
  32221. $includies = [];
  32222. foreach ($tokens->findGivenKind($includyTokenKinds) as $includyTokens) {
  32223. foreach ($includyTokens as $index => $token) {
  32224. $includy = [
  32225. 'begin' => $index,
  32226. 'braces' => null,
  32227. 'end' => $tokens->getNextTokenOfKind($index, [';', [T_CLOSE_TAG]]),
  32228. ];
  32229. $braceOpenIndex = $tokens->getNextMeaningfulToken($index);
  32230. if ($tokens[$braceOpenIndex]->equals('(')) {
  32231. $braceCloseIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $braceOpenIndex);
  32232. $includy['braces'] = [
  32233. 'open' => $braceOpenIndex,
  32234. 'close' => $braceCloseIndex,
  32235. ];
  32236. }
  32237. $includies[$index] = $includy;
  32238. }
  32239. }
  32240. krsort($includies);
  32241. return $includies;
  32242. }
  32243. private function removeWhitespaceAroundIfPossible(Tokens $tokens, $index)
  32244. {
  32245. $nextIndex = $tokens->getNextNonWhitespace($index);
  32246. if (null === $nextIndex || !$tokens[$nextIndex]->isComment()) {
  32247. $tokens->removeLeadingWhitespace($index);
  32248. }
  32249. $prevIndex = $tokens->getPrevNonWhitespace($index);
  32250. if (null === $prevIndex || !$tokens[$prevIndex]->isComment()) {
  32251. $tokens->removeTrailingWhitespace($index);
  32252. }
  32253. }
  32254. }
  32255. <?php
  32256. namespace PhpCsFixer\Fixer\ControlStructure;
  32257. use PhpCsFixer\AbstractFixer;
  32258. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  32259. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  32260. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  32261. use PhpCsFixer\FixerDefinition\CodeSample;
  32262. use PhpCsFixer\FixerDefinition\FixerDefinition;
  32263. use PhpCsFixer\Tokenizer\Token;
  32264. use PhpCsFixer\Tokenizer\Tokens;
  32265. final class NoUnneededCurlyBracesFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface
  32266. {
  32267. public function getDefinition()
  32268. {
  32269. return new FixerDefinition(
  32270. 'Removes unneeded curly braces that are superfluous and aren\'t part of a control structure\'s body.',
  32271. [
  32272. new CodeSample(
  32273. '<?php {
  32274. echo 1;
  32275. }
  32276. switch ($b) {
  32277. case 1: {
  32278. break;
  32279. }
  32280. }
  32281. '
  32282. ),
  32283. new CodeSample(
  32284. '<?php
  32285. namespace Foo {
  32286. function Bar(){}
  32287. }
  32288. ',
  32289. ['namespaces' => true]
  32290. ),
  32291. ]
  32292. );
  32293. }
  32294. public function getPriority()
  32295. {
  32296. return 26;
  32297. }
  32298. public function isCandidate(Tokens $tokens)
  32299. {
  32300. return $tokens->isTokenKindFound('}');
  32301. }
  32302. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  32303. {
  32304. foreach ($this->findCurlyBraceOpen($tokens) as $index) {
  32305. if ($this->isOverComplete($tokens, $index)) {
  32306. $this->clearOverCompleteBraces($tokens, $index, $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $index));
  32307. }
  32308. }
  32309. if ($this->configuration['namespaces']) {
  32310. $this->clearIfIsOverCompleteNamespaceBlock($tokens);
  32311. }
  32312. }
  32313. protected function createConfigurationDefinition()
  32314. {
  32315. return new FixerConfigurationResolver([
  32316. (new FixerOptionBuilder('namespaces', 'Remove unneeded curly braces from bracketed namespaces.'))
  32317. ->setAllowedTypes(['bool'])
  32318. ->setDefault(false)
  32319. ->getOption(),
  32320. ]);
  32321. }
  32322. private function clearOverCompleteBraces(Tokens $tokens, $openIndex, $closeIndex)
  32323. {
  32324. $tokens->clearTokenAndMergeSurroundingWhitespace($closeIndex);
  32325. $tokens->clearTokenAndMergeSurroundingWhitespace($openIndex);
  32326. }
  32327. private function findCurlyBraceOpen(Tokens $tokens)
  32328. {
  32329. for ($i = \count($tokens) - 1; $i > 0; --$i) {
  32330. if ($tokens[$i]->equals('{')) {
  32331. yield $i;
  32332. }
  32333. }
  32334. }
  32335. private function isOverComplete(Tokens $tokens, $index)
  32336. {
  32337. static $include = ['{', '}', [T_OPEN_TAG], ':', ';'];
  32338. return $tokens[$tokens->getPrevMeaningfulToken($index)]->equalsAny($include);
  32339. }
  32340. private function clearIfIsOverCompleteNamespaceBlock(Tokens $tokens)
  32341. {
  32342. if (Tokens::isLegacyMode()) {
  32343. $index = $tokens->getNextTokenOfKind(0, [[T_NAMESPACE]]);
  32344. $secondNamespaceIndex = $tokens->getNextTokenOfKind($index, [[T_NAMESPACE]]);
  32345. if (null !== $secondNamespaceIndex) {
  32346. return;
  32347. }
  32348. } elseif (1 !== $tokens->countTokenKind(T_NAMESPACE)) {
  32349. return;
  32350. }
  32351. $index = $tokens->getNextTokenOfKind(0, [[T_NAMESPACE]]);
  32352. do {
  32353. $index = $tokens->getNextMeaningfulToken($index);
  32354. } while ($tokens[$index]->isGivenKind([T_STRING, T_NS_SEPARATOR]));
  32355. if (!$tokens[$index]->equals('{')) {
  32356. return;
  32357. }
  32358. $closeIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $index);
  32359. $afterCloseIndex = $tokens->getNextMeaningfulToken($closeIndex);
  32360. if (null !== $afterCloseIndex && (!$tokens[$afterCloseIndex]->isGivenKind(T_CLOSE_TAG) || null !== $tokens->getNextMeaningfulToken($afterCloseIndex))) {
  32361. return;
  32362. }
  32363. $tokens->clearTokenAndMergeSurroundingWhitespace($closeIndex);
  32364. $tokens[$index] = new Token(';');
  32365. if ($tokens[$index - 1]->isWhitespace(" \t") && !$tokens[$index - 2]->isComment()) {
  32366. $tokens->clearTokenAndMergeSurroundingWhitespace($index - 1);
  32367. }
  32368. }
  32369. }
  32370. <?php
  32371. namespace PhpCsFixer\Fixer\ControlStructure;
  32372. use PhpCsFixer\AbstractNoUselessElseFixer;
  32373. use PhpCsFixer\FixerDefinition\CodeSample;
  32374. use PhpCsFixer\FixerDefinition\FixerDefinition;
  32375. use PhpCsFixer\Tokenizer\Tokens;
  32376. final class NoUselessElseFixer extends AbstractNoUselessElseFixer
  32377. {
  32378. public function isCandidate(Tokens $tokens)
  32379. {
  32380. return $tokens->isTokenKindFound(T_ELSE);
  32381. }
  32382. public function getDefinition()
  32383. {
  32384. return new FixerDefinition(
  32385. 'There should not be useless `else` cases.',
  32386. [
  32387. new CodeSample("<?php\nif (\$a) {\n return 1;\n} else {\n return 2;\n}\n"),
  32388. ]
  32389. );
  32390. }
  32391. public function getPriority()
  32392. {
  32393. return parent::getPriority();
  32394. }
  32395. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  32396. {
  32397. foreach ($tokens as $index => $token) {
  32398. if (!$token->isGivenKind(T_ELSE)) {
  32399. continue;
  32400. }
  32401. if ($tokens[$tokens->getNextMeaningfulToken($index)]->equalsAny([':', [T_IF]])) {
  32402. continue;
  32403. }
  32404. $this->fixEmptyElse($tokens, $index);
  32405. if ($tokens->isEmptyAt($index)) {
  32406. continue;
  32407. }
  32408. if ($this->isSuperfluousElse($tokens, $index)) {
  32409. $this->clearElse($tokens, $index);
  32410. }
  32411. }
  32412. }
  32413. private function fixEmptyElse(Tokens $tokens, $index)
  32414. {
  32415. $next = $tokens->getNextMeaningfulToken($index);
  32416. if ($tokens[$next]->equals('{')) {
  32417. $close = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $next);
  32418. if (1 === $close - $next) {
  32419. $this->clearElse($tokens, $index);
  32420. } elseif ($tokens->getNextMeaningfulToken($next) === $close) {
  32421. $this->clearElse($tokens, $index);
  32422. }
  32423. return;
  32424. }
  32425. $end = $tokens->getNextTokenOfKind($index, [';', [T_CLOSE_TAG]]);
  32426. if ($next === $end) {
  32427. $this->clearElse($tokens, $index);
  32428. }
  32429. }
  32430. private function clearElse(Tokens $tokens, $index)
  32431. {
  32432. $tokens->clearTokenAndMergeSurroundingWhitespace($index);
  32433. $next = $tokens->getNextMeaningfulToken($index);
  32434. if (!$tokens[$next]->equals('{')) {
  32435. return;
  32436. }
  32437. $tokens->clearTokenAndMergeSurroundingWhitespace($tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $next));
  32438. $tokens->clearTokenAndMergeSurroundingWhitespace($next);
  32439. }
  32440. }
  32441. <?php
  32442. namespace PhpCsFixer\Fixer\ControlStructure;
  32443. use PhpCsFixer\AbstractFixer;
  32444. use PhpCsFixer\FixerDefinition\CodeSample;
  32445. use PhpCsFixer\FixerDefinition\FixerDefinition;
  32446. use PhpCsFixer\Tokenizer\Token;
  32447. use PhpCsFixer\Tokenizer\Tokens;
  32448. final class NoAlternativeSyntaxFixer extends AbstractFixer
  32449. {
  32450. public function getDefinition()
  32451. {
  32452. return new FixerDefinition(
  32453. 'Replace control structure alternative syntax to use braces.',
  32454. [
  32455. new CodeSample(
  32456. "<?php\nif(true):echo 't';else:echo 'f';endif;\n"
  32457. ),
  32458. new CodeSample(
  32459. "<?php\nwhile(true):echo 'red';endwhile;\n"
  32460. ),
  32461. new CodeSample(
  32462. "<?php\nfor(;;):echo 'xc';endfor;\n"
  32463. ),
  32464. new CodeSample(
  32465. "<?php\nforeach(array('a') as \$item):echo 'xc';endforeach;\n"
  32466. ),
  32467. ]
  32468. );
  32469. }
  32470. public function isCandidate(Tokens $tokens)
  32471. {
  32472. return $tokens->isAnyTokenKindsFound(
  32473. [
  32474. T_ENDIF,
  32475. T_ENDWHILE,
  32476. T_ENDFOREACH,
  32477. T_ENDFOR,
  32478. ]
  32479. );
  32480. }
  32481. public function getPriority()
  32482. {
  32483. return 26;
  32484. }
  32485. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  32486. {
  32487. for ($index = \count($tokens) - 1; 0 <= $index; --$index) {
  32488. $token = $tokens[$index];
  32489. $this->fixElseif($index, $token, $tokens);
  32490. $this->fixElse($index, $token, $tokens);
  32491. $this->fixOpenCloseControls($index, $token, $tokens);
  32492. }
  32493. }
  32494. private function findParenthesisEnd(Tokens $tokens, $structureTokenIndex)
  32495. {
  32496. $nextIndex = $tokens->getNextMeaningfulToken($structureTokenIndex);
  32497. $nextToken = $tokens[$nextIndex];
  32498. if (!$nextToken->equals('(')) {
  32499. return $structureTokenIndex;
  32500. }
  32501. return $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $nextIndex);
  32502. }
  32503. private function fixOpenCloseControls($index, Token $token, Tokens $tokens)
  32504. {
  32505. if ($token->isGivenKind([T_IF, T_FOREACH, T_WHILE, T_FOR])) {
  32506. $openIndex = $tokens->getNextTokenOfKind($index, ['(']);
  32507. $closeIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $openIndex);
  32508. $afterParenthesisIndex = $tokens->getNextNonWhitespace($closeIndex);
  32509. $afterParenthesis = $tokens[$afterParenthesisIndex];
  32510. if (!$afterParenthesis->equals(':')) {
  32511. return;
  32512. }
  32513. $items = [];
  32514. if (!$tokens[$afterParenthesisIndex - 1]->isWhitespace()) {
  32515. $items[] = new Token([T_WHITESPACE, ' ']);
  32516. }
  32517. $items[] = new Token('{');
  32518. if (!$tokens[$afterParenthesisIndex + 1]->isWhitespace()) {
  32519. $items[] = new Token([T_WHITESPACE, ' ']);
  32520. }
  32521. $tokens->clearAt($afterParenthesisIndex);
  32522. $tokens->insertAt($afterParenthesisIndex, $items);
  32523. }
  32524. if (!$token->isGivenKind([T_ENDIF, T_ENDFOREACH, T_ENDWHILE, T_ENDFOR])) {
  32525. return;
  32526. }
  32527. $nextTokenIndex = $tokens->getNextMeaningfulToken($index);
  32528. $nextToken = $tokens[$nextTokenIndex];
  32529. $tokens[$index] = new Token('}');
  32530. if ($nextToken->equals(';')) {
  32531. $tokens->clearAt($nextTokenIndex);
  32532. }
  32533. }
  32534. private function fixElse($index, Token $token, Tokens $tokens)
  32535. {
  32536. if (!$token->isGivenKind(T_ELSE)) {
  32537. return;
  32538. }
  32539. $tokenAfterElseIndex = $tokens->getNextMeaningfulToken($index);
  32540. $tokenAfterElse = $tokens[$tokenAfterElseIndex];
  32541. if (!$tokenAfterElse->equals(':')) {
  32542. return;
  32543. }
  32544. $this->addBraces($tokens, new Token([T_ELSE, 'else']), $index, $tokenAfterElseIndex);
  32545. }
  32546. private function fixElseif($index, Token $token, Tokens $tokens)
  32547. {
  32548. if (!$token->isGivenKind(T_ELSEIF)) {
  32549. return;
  32550. }
  32551. $parenthesisEndIndex = $this->findParenthesisEnd($tokens, $index);
  32552. $tokenAfterParenthesisIndex = $tokens->getNextMeaningfulToken($parenthesisEndIndex);
  32553. $tokenAfterParenthesis = $tokens[$tokenAfterParenthesisIndex];
  32554. if (!$tokenAfterParenthesis->equals(':')) {
  32555. return;
  32556. }
  32557. $this->addBraces($tokens, new Token([T_ELSEIF, 'elseif']), $index, $tokenAfterParenthesisIndex);
  32558. }
  32559. private function addBraces(Tokens $tokens, Token $token, $index, $colonIndex)
  32560. {
  32561. $items = [
  32562. new Token('}'),
  32563. new Token([T_WHITESPACE, ' ']),
  32564. $token,
  32565. ];
  32566. if (!$tokens[$index + 1]->isWhitespace()) {
  32567. $items[] = new Token([T_WHITESPACE, ' ']);
  32568. }
  32569. $tokens->clearAt($index);
  32570. $tokens->insertAt(
  32571. $index,
  32572. $items
  32573. );
  32574. $colonIndex += \count($items);
  32575. $items = [new Token('{')];
  32576. if (!$tokens[$colonIndex + 1]->isWhitespace()) {
  32577. $items[] = new Token([T_WHITESPACE, ' ']);
  32578. }
  32579. $tokens->clearAt($colonIndex);
  32580. $tokens->insertAt(
  32581. $colonIndex,
  32582. $items
  32583. );
  32584. }
  32585. }
  32586. <?php
  32587. namespace PhpCsFixer\Fixer\ControlStructure;
  32588. use PhpCsFixer\AbstractFixer;
  32589. use PhpCsFixer\FixerDefinition\CodeSample;
  32590. use PhpCsFixer\FixerDefinition\FixerDefinition;
  32591. use PhpCsFixer\Tokenizer\Tokens;
  32592. final class SwitchCaseSpaceFixer extends AbstractFixer
  32593. {
  32594. public function getDefinition()
  32595. {
  32596. return new FixerDefinition(
  32597. 'Removes extra spaces between colon and case value.',
  32598. [
  32599. new CodeSample(
  32600. '<?php
  32601. switch($a) {
  32602. case 1 :
  32603. break;
  32604. default :
  32605. return 2;
  32606. }
  32607. '
  32608. ),
  32609. ]
  32610. );
  32611. }
  32612. public function isCandidate(Tokens $tokens)
  32613. {
  32614. return $tokens->isAnyTokenKindsFound([T_CASE, T_DEFAULT]);
  32615. }
  32616. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  32617. {
  32618. foreach ($tokens as $index => $token) {
  32619. if (!$token->isGivenKind([T_CASE, T_DEFAULT])) {
  32620. continue;
  32621. }
  32622. $ternariesCount = 0;
  32623. for ($colonIndex = $index + 1;; ++$colonIndex) {
  32624. if ($tokens[$colonIndex]->equals('?')) {
  32625. ++$ternariesCount;
  32626. }
  32627. if ($tokens[$colonIndex]->equalsAny([':', ';'])) {
  32628. if (0 === $ternariesCount) {
  32629. break;
  32630. }
  32631. --$ternariesCount;
  32632. }
  32633. }
  32634. $valueIndex = $tokens->getPrevNonWhitespace($colonIndex);
  32635. if ($valueIndex === $colonIndex - 1 || $tokens[$valueIndex]->isComment()) {
  32636. continue;
  32637. }
  32638. $tokens->clearAt($valueIndex + 1);
  32639. }
  32640. }
  32641. }
  32642. <?php
  32643. namespace PhpCsFixer\Fixer\ControlStructure;
  32644. use PhpCsFixer\AbstractFixer;
  32645. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  32646. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverRootless;
  32647. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  32648. use PhpCsFixer\FixerDefinition\CodeSample;
  32649. use PhpCsFixer\FixerDefinition\FixerDefinition;
  32650. use PhpCsFixer\Tokenizer\CT;
  32651. use PhpCsFixer\Tokenizer\Token;
  32652. use PhpCsFixer\Tokenizer\Tokens;
  32653. /**
  32654. @gmail
  32655. @web
  32656. */
  32657. final class NoUnneededControlParenthesesFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface
  32658. {
  32659. private static $loops = [
  32660. 'break' => ['lookupTokens' => T_BREAK, 'neededSuccessors' => [';']],
  32661. 'clone' => ['lookupTokens' => T_CLONE, 'neededSuccessors' => [';', ':', ',', ')'], 'forbiddenContents' => ['?', ':']],
  32662. 'continue' => ['lookupTokens' => T_CONTINUE, 'neededSuccessors' => [';']],
  32663. 'echo_print' => ['lookupTokens' => [T_ECHO, T_PRINT], 'neededSuccessors' => [';', [T_CLOSE_TAG]]],
  32664. 'return' => ['lookupTokens' => T_RETURN, 'neededSuccessors' => [';', [T_CLOSE_TAG]]],
  32665. 'switch_case' => ['lookupTokens' => T_CASE, 'neededSuccessors' => [';', ':']],
  32666. 'yield' => ['lookupTokens' => T_YIELD, 'neededSuccessors' => [';', ')']],
  32667. ];
  32668. public function __construct()
  32669. {
  32670. parent::__construct();
  32671. if (\defined('T_COALESCE')) {
  32672. self::$loops['clone']['forbiddenContents'][] = [T_COALESCE, '??'];
  32673. }
  32674. }
  32675. public function isCandidate(Tokens $tokens)
  32676. {
  32677. $types = [];
  32678. foreach (self::$loops as $loop) {
  32679. $types[] = (array) $loop['lookupTokens'];
  32680. }
  32681. $types = array_merge(...$types);
  32682. return $tokens->isAnyTokenKindsFound($types);
  32683. }
  32684. public function getDefinition()
  32685. {
  32686. return new FixerDefinition(
  32687. 'Removes unneeded parentheses around control statements.',
  32688. [
  32689. new CodeSample(
  32690. '<?php
  32691. while ($x) { while ($y) { break (2); } }
  32692. clone($a);
  32693. while ($y) { continue (2); }
  32694. echo("foo");
  32695. print("foo");
  32696. return (1 + 2);
  32697. switch ($a) { case($x); }
  32698. yield(2);
  32699. '
  32700. ),
  32701. new CodeSample(
  32702. '<?php
  32703. while ($x) { while ($y) { break (2); } }
  32704. clone($a);
  32705. while ($y) { continue (2); }
  32706. echo("foo");
  32707. print("foo");
  32708. return (1 + 2);
  32709. switch ($a) { case($x); }
  32710. yield(2);
  32711. ',
  32712. ['statements' => ['break', 'continue']]
  32713. ),
  32714. ]
  32715. );
  32716. }
  32717. public function getPriority()
  32718. {
  32719. return 30;
  32720. }
  32721. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  32722. {
  32723. $loops = array_intersect_key(self::$loops, array_flip($this->configuration['statements']));
  32724. foreach ($tokens as $index => $token) {
  32725. if (!$token->equalsAny(['(', [CT::T_BRACE_CLASS_INSTANTIATION_OPEN]])) {
  32726. continue;
  32727. }
  32728. $blockStartIndex = $index;
  32729. $index = $tokens->getPrevMeaningfulToken($index);
  32730. $prevToken = $tokens[$index];
  32731. foreach ($loops as $loop) {
  32732. if (!$prevToken->isGivenKind($loop['lookupTokens'])) {
  32733. continue;
  32734. }
  32735. $blockEndIndex = $tokens->findBlockEnd(
  32736. $token->equals('(') ? Tokens::BLOCK_TYPE_PARENTHESIS_BRACE : Tokens::BLOCK_TYPE_BRACE_CLASS_INSTANTIATION,
  32737. $blockStartIndex
  32738. );
  32739. $blockEndNextIndex = $tokens->getNextMeaningfulToken($blockEndIndex);
  32740. if (!$tokens[$blockEndNextIndex]->equalsAny($loop['neededSuccessors'])) {
  32741. continue;
  32742. }
  32743. if (\array_key_exists('forbiddenContents', $loop)) {
  32744. $forbiddenTokenIndex = $tokens->getNextTokenOfKind($blockStartIndex, $loop['forbiddenContents']);
  32745. if (null !== $forbiddenTokenIndex && $forbiddenTokenIndex < $blockEndIndex) {
  32746. continue;
  32747. }
  32748. }
  32749. if ($tokens[$blockStartIndex - 1]->isWhitespace() || $tokens[$blockStartIndex - 1]->isComment()) {
  32750. $tokens->clearTokenAndMergeSurroundingWhitespace($blockStartIndex);
  32751. } else {
  32752. $tokens[$blockStartIndex] = new Token([T_WHITESPACE, ' ']);
  32753. }
  32754. $tokens->clearTokenAndMergeSurroundingWhitespace($blockEndIndex);
  32755. }
  32756. }
  32757. }
  32758. protected function createConfigurationDefinition()
  32759. {
  32760. return new FixerConfigurationResolverRootless('statements', [
  32761. (new FixerOptionBuilder('statements', 'List of control statements to fix.'))
  32762. ->setAllowedTypes(['array'])
  32763. ->setDefault([
  32764. 'break',
  32765. 'clone',
  32766. 'continue',
  32767. 'echo_print',
  32768. 'return',
  32769. 'switch_case',
  32770. 'yield',
  32771. ])
  32772. ->getOption(),
  32773. ], $this->getName());
  32774. }
  32775. }
  32776. <?php
  32777. namespace PhpCsFixer\Fixer\ControlStructure;
  32778. use PhpCsFixer\AbstractFixer;
  32779. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  32780. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  32781. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  32782. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  32783. use PhpCsFixer\FixerDefinition\CodeSample;
  32784. use PhpCsFixer\FixerDefinition\FixerDefinition;
  32785. use PhpCsFixer\Preg;
  32786. use PhpCsFixer\Tokenizer\Token;
  32787. use PhpCsFixer\Tokenizer\Tokens;
  32788. use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException;
  32789. use Symfony\Component\OptionsResolver\Options;
  32790. final class NoBreakCommentFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface, WhitespacesAwareFixerInterface
  32791. {
  32792. public function getDefinition()
  32793. {
  32794. return new FixerDefinition(
  32795. 'There must be a comment when fall-through is intentional in a non-empty case body.',
  32796. [
  32797. new CodeSample(
  32798. '<?php
  32799. switch ($foo) {
  32800. case 1:
  32801. foo();
  32802. case 2:
  32803. bar();
  32804. // no break
  32805. break;
  32806. case 3:
  32807. baz();
  32808. }
  32809. '
  32810. ),
  32811. new CodeSample(
  32812. '<?php
  32813. switch ($foo) {
  32814. case 1:
  32815. foo();
  32816. case 2:
  32817. foo();
  32818. }
  32819. ',
  32820. ['comment_text' => 'some comment']
  32821. ),
  32822. ],
  32823. 'Adds a "no break" comment before fall-through cases, and removes it if there is no fall-through.'
  32824. );
  32825. }
  32826. public function isCandidate(Tokens $tokens)
  32827. {
  32828. return $tokens->isAnyTokenKindsFound([T_CASE, T_DEFAULT]);
  32829. }
  32830. protected function createConfigurationDefinition()
  32831. {
  32832. return new FixerConfigurationResolver([
  32833. (new FixerOptionBuilder('comment_text', 'The text to use in the added comment and to detect it.'))
  32834. ->setAllowedTypes(['string'])
  32835. ->setAllowedValues([
  32836. static function ($value) {
  32837. if (\is_string($value) && Preg::match('/\R/', $value)) {
  32838. throw new InvalidOptionsException('The comment text must not contain new lines.');
  32839. }
  32840. return true;
  32841. },
  32842. ])
  32843. ->setNormalizer(static function (Options $options, $value) {
  32844. return rtrim($value);
  32845. })
  32846. ->setDefault('no break')
  32847. ->getOption(),
  32848. ]);
  32849. }
  32850. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  32851. {
  32852. for ($position = \count($tokens) - 1; $position >= 0; --$position) {
  32853. if ($tokens[$position]->isGivenKind([T_CASE, T_DEFAULT])) {
  32854. $this->fixCase($tokens, $position);
  32855. }
  32856. }
  32857. }
  32858. private function fixCase(Tokens $tokens, $casePosition)
  32859. {
  32860. $empty = true;
  32861. $fallThrough = true;
  32862. $commentPosition = null;
  32863. for ($i = $tokens->getNextTokenOfKind($casePosition, [':', ';']) + 1, $max = \count($tokens); $i < $max; ++$i) {
  32864. if ($tokens[$i]->isGivenKind([T_SWITCH, T_IF, T_ELSE, T_ELSEIF, T_FOR, T_FOREACH, T_WHILE, T_DO, T_FUNCTION, T_CLASS])) {
  32865. $empty = false;
  32866. $i = $this->getStructureEnd($tokens, $i);
  32867. continue;
  32868. }
  32869. if ($tokens[$i]->isGivenKind([T_BREAK, T_CONTINUE, T_RETURN, T_EXIT, T_THROW, T_GOTO])) {
  32870. $fallThrough = false;
  32871. continue;
  32872. }
  32873. if ($tokens[$i]->equals('}') || $tokens[$i]->isGivenKind(T_ENDSWITCH)) {
  32874. if (null !== $commentPosition) {
  32875. $this->removeComment($tokens, $commentPosition);
  32876. }
  32877. break;
  32878. }
  32879. if ($this->isNoBreakComment($tokens[$i])) {
  32880. $commentPosition = $i;
  32881. continue;
  32882. }
  32883. if ($tokens[$i]->isGivenKind([T_CASE, T_DEFAULT])) {
  32884. if (!$empty && $fallThrough) {
  32885. if (null !== $commentPosition && $tokens->getPrevNonWhitespace($i) !== $commentPosition) {
  32886. $this->removeComment($tokens, $commentPosition);
  32887. $commentPosition = null;
  32888. }
  32889. if (null === $commentPosition) {
  32890. $this->insertCommentAt($tokens, $i);
  32891. } else {
  32892. $text = $this->configuration['comment_text'];
  32893. $tokens[$commentPosition] = new Token([
  32894. $tokens[$commentPosition]->getId(),
  32895. str_ireplace($text, $text, $tokens[$commentPosition]->getContent()),
  32896. ]);
  32897. $this->ensureNewLineAt($tokens, $commentPosition);
  32898. }
  32899. } elseif (null !== $commentPosition) {
  32900. $this->removeComment($tokens, $commentPosition);
  32901. }
  32902. break;
  32903. }
  32904. if (!$tokens[$i]->isGivenKind([T_COMMENT, T_WHITESPACE])) {
  32905. $empty = false;
  32906. }
  32907. }
  32908. }
  32909. private function isNoBreakComment(Token $token)
  32910. {
  32911. if (!$token->isComment()) {
  32912. return false;
  32913. }
  32914. $text = preg_quote($this->configuration['comment_text'], '~');
  32915. return 1 === Preg::match("~^((//|#)\\s*{$text}\\s*)|(/\\*\\*?\\s*{$text}\\s*\\*/)$~i", $token->getContent());
  32916. }
  32917. private function insertCommentAt(Tokens $tokens, $casePosition)
  32918. {
  32919. $lineEnding = $this->whitespacesConfig->getLineEnding();
  32920. $newlinePosition = $this->ensureNewLineAt($tokens, $casePosition);
  32921. $newlineToken = $tokens[$newlinePosition];
  32922. $nbNewlines = substr_count($newlineToken->getContent(), $lineEnding);
  32923. if ($newlineToken->isGivenKind(T_OPEN_TAG) && Preg::match('/\R/', $newlineToken->getContent())) {
  32924. ++$nbNewlines;
  32925. } elseif ($tokens[$newlinePosition - 1]->isGivenKind(T_OPEN_TAG) && Preg::match('/\R/', $tokens[$newlinePosition - 1]->getContent())) {
  32926. ++$nbNewlines;
  32927. if (!Preg::match('/\R/', $newlineToken->getContent())) {
  32928. $tokens[$newlinePosition] = new Token([$newlineToken->getId(), $lineEnding.$newlineToken->getContent()]);
  32929. }
  32930. }
  32931. if ($nbNewlines > 1) {
  32932. Preg::match('/^(.*?)(\R\h*)$/s', $newlineToken->getContent(), $matches);
  32933. $indent = $this->getIndentAt($tokens, $newlinePosition - 1);
  32934. $tokens[$newlinePosition] = new Token([$newlineToken->getId(), $matches[1].$lineEnding.$indent]);
  32935. $tokens->insertAt(++$newlinePosition, new Token([T_WHITESPACE, $matches[2]]));
  32936. }
  32937. $tokens->insertAt($newlinePosition, new Token([T_COMMENT, '// '.$this->configuration['comment_text']]));
  32938. $this->ensureNewLineAt($tokens, $newlinePosition);
  32939. }
  32940. private function ensureNewLineAt(Tokens $tokens, $position)
  32941. {
  32942. $lineEnding = $this->whitespacesConfig->getLineEnding();
  32943. $content = $lineEnding.$this->getIndentAt($tokens, $position);
  32944. $whitespaceToken = $tokens[$position - 1];
  32945. if (!$whitespaceToken->isGivenKind(T_WHITESPACE)) {
  32946. if ($whitespaceToken->isGivenKind(T_OPEN_TAG)) {
  32947. $content = Preg::replace('/\R/', '', $content);
  32948. if (!Preg::match('/\R/', $whitespaceToken->getContent())) {
  32949. $tokens[$position - 1] = new Token([T_OPEN_TAG, Preg::replace('/\s+$/', $lineEnding, $whitespaceToken->getContent())]);
  32950. }
  32951. }
  32952. if ('' !== $content) {
  32953. $tokens->insertAt($position, new Token([T_WHITESPACE, $content]));
  32954. return $position;
  32955. }
  32956. return $position - 1;
  32957. }
  32958. if ($tokens[$position - 2]->isGivenKind(T_OPEN_TAG) && Preg::match('/\R/', $tokens[$position - 2]->getContent())) {
  32959. $content = Preg::replace('/^\R/', '', $content);
  32960. }
  32961. if (!Preg::match('/\R/', $whitespaceToken->getContent())) {
  32962. $tokens[$position - 1] = new Token([T_WHITESPACE, $content]);
  32963. }
  32964. return $position - 1;
  32965. }
  32966. private function removeComment(Tokens $tokens, $commentPosition)
  32967. {
  32968. if ($tokens[$tokens->getPrevNonWhitespace($commentPosition)]->isGivenKind(T_OPEN_TAG)) {
  32969. $whitespacePosition = $commentPosition + 1;
  32970. $regex = '/^\R\h*/';
  32971. } else {
  32972. $whitespacePosition = $commentPosition - 1;
  32973. $regex = '/\R\h*$/';
  32974. }
  32975. $whitespaceToken = $tokens[$whitespacePosition];
  32976. if ($whitespaceToken->isGivenKind(T_WHITESPACE)) {
  32977. $content = Preg::replace($regex, '', $whitespaceToken->getContent());
  32978. if ('' !== $content) {
  32979. $tokens[$whitespacePosition] = new Token([T_WHITESPACE, $content]);
  32980. } else {
  32981. $tokens->clearAt($whitespacePosition);
  32982. }
  32983. }
  32984. $tokens->clearTokenAndMergeSurroundingWhitespace($commentPosition);
  32985. }
  32986. private function getIndentAt(Tokens $tokens, $position)
  32987. {
  32988. while (true) {
  32989. $position = $tokens->getPrevTokenOfKind($position, [[T_WHITESPACE]]);
  32990. if (null === $position) {
  32991. break;
  32992. }
  32993. $content = $tokens[$position]->getContent();
  32994. $prevToken = $tokens[$position - 1];
  32995. if ($prevToken->isGivenKind(T_OPEN_TAG) && Preg::match('/\R$/', $prevToken->getContent())) {
  32996. $content = $this->whitespacesConfig->getLineEnding().$content;
  32997. }
  32998. if (Preg::match('/\R(\h*)$/', $content, $matches)) {
  32999. return $matches[1];
  33000. }
  33001. }
  33002. return '';
  33003. }
  33004. private function getStructureEnd(Tokens $tokens, $position)
  33005. {
  33006. $initialToken = $tokens[$position];
  33007. if ($initialToken->isGivenKind([T_FOR, T_FOREACH, T_WHILE, T_IF, T_ELSEIF, T_SWITCH, T_FUNCTION])) {
  33008. $position = $tokens->findBlockEnd(
  33009. Tokens::BLOCK_TYPE_PARENTHESIS_BRACE,
  33010. $tokens->getNextTokenOfKind($position, ['('])
  33011. );
  33012. } elseif ($initialToken->isGivenKind(T_CLASS)) {
  33013. $openParenthesisPosition = $tokens->getNextMeaningfulToken($position);
  33014. if ('(' === $tokens[$openParenthesisPosition]->getContent()) {
  33015. $position = $tokens->findBlockEnd(
  33016. Tokens::BLOCK_TYPE_PARENTHESIS_BRACE,
  33017. $openParenthesisPosition
  33018. );
  33019. }
  33020. }
  33021. $position = $tokens->getNextMeaningfulToken($position);
  33022. if ('{' !== $tokens[$position]->getContent()) {
  33023. return $tokens->getNextTokenOfKind($position, [';']);
  33024. }
  33025. $position = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $position);
  33026. if ($initialToken->isGivenKind(T_DO)) {
  33027. $position = $tokens->findBlockEnd(
  33028. Tokens::BLOCK_TYPE_PARENTHESIS_BRACE,
  33029. $tokens->getNextTokenOfKind($position, ['('])
  33030. );
  33031. return $tokens->getNextTokenOfKind($position, [';']);
  33032. }
  33033. return $position;
  33034. }
  33035. }
  33036. <?php
  33037. namespace PhpCsFixer\Fixer\ControlStructure;
  33038. use PhpCsFixer\AbstractFixer;
  33039. use PhpCsFixer\FixerDefinition\CodeSample;
  33040. use PhpCsFixer\FixerDefinition\FixerDefinition;
  33041. use PhpCsFixer\Tokenizer\Token;
  33042. use PhpCsFixer\Tokenizer\Tokens;
  33043. final class SwitchCaseSemicolonToColonFixer extends AbstractFixer
  33044. {
  33045. public function getDefinition()
  33046. {
  33047. return new FixerDefinition(
  33048. 'A case should be followed by a colon and not a semicolon.',
  33049. [
  33050. new CodeSample(
  33051. '<?php
  33052. switch ($a) {
  33053. case 1;
  33054. break;
  33055. default;
  33056. break;
  33057. }
  33058. '
  33059. ),
  33060. ]
  33061. );
  33062. }
  33063. public function getPriority()
  33064. {
  33065. return 0;
  33066. }
  33067. public function isCandidate(Tokens $tokens)
  33068. {
  33069. return $tokens->isAnyTokenKindsFound([T_CASE, T_DEFAULT]);
  33070. }
  33071. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  33072. {
  33073. foreach ($tokens as $index => $token) {
  33074. if ($token->isGivenKind([T_CASE, T_DEFAULT])) {
  33075. $this->fixSwitchCase($tokens, $index);
  33076. }
  33077. }
  33078. }
  33079. protected function fixSwitchCase(Tokens $tokens, $index)
  33080. {
  33081. $ternariesCount = 0;
  33082. do {
  33083. if ($tokens[$index]->equalsAny(['(', '{'])) {
  33084. $type = Tokens::detectBlockType($tokens[$index]);
  33085. $index = $tokens->findBlockEnd($type['type'], $index);
  33086. continue;
  33087. }
  33088. if ($tokens[$index]->equals('?')) {
  33089. ++$ternariesCount;
  33090. continue;
  33091. }
  33092. if ($tokens[$index]->equalsAny([':', ';'])) {
  33093. if (0 === $ternariesCount) {
  33094. break;
  33095. }
  33096. --$ternariesCount;
  33097. }
  33098. } while (++$index);
  33099. if ($tokens[$index]->equals(';')) {
  33100. $tokens[$index] = new Token(':');
  33101. }
  33102. }
  33103. }
  33104. <?php
  33105. namespace PhpCsFixer\Fixer\ControlStructure;
  33106. use PhpCsFixer\AbstractFixer;
  33107. use PhpCsFixer\FixerDefinition\CodeSample;
  33108. use PhpCsFixer\FixerDefinition\FixerDefinition;
  33109. use PhpCsFixer\Tokenizer\Token;
  33110. use PhpCsFixer\Tokenizer\Tokens;
  33111. final class ElseifFixer extends AbstractFixer
  33112. {
  33113. public function getDefinition()
  33114. {
  33115. return new FixerDefinition(
  33116. 'The keyword `elseif` should be used instead of `else if` so that all control keywords look like single words.',
  33117. [new CodeSample("<?php\nif (\$a) {\n} else if (\$b) {\n}\n")]
  33118. );
  33119. }
  33120. public function getPriority()
  33121. {
  33122. return 0;
  33123. }
  33124. public function isCandidate(Tokens $tokens)
  33125. {
  33126. return $tokens->isAllTokenKindsFound([T_IF, T_ELSE]);
  33127. }
  33128. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  33129. {
  33130. foreach ($tokens as $index => $token) {
  33131. if (!$token->isGivenKind(T_ELSE)) {
  33132. continue;
  33133. }
  33134. $ifTokenIndex = $tokens->getNextMeaningfulToken($index);
  33135. if (!$tokens[$ifTokenIndex]->isGivenKind(T_IF)) {
  33136. continue;
  33137. }
  33138. $conditionEndBraceIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $tokens->getNextMeaningfulToken($ifTokenIndex));
  33139. $afterConditionIndex = $tokens->getNextMeaningfulToken($conditionEndBraceIndex);
  33140. if ($tokens[$afterConditionIndex]->equals(':')) {
  33141. continue;
  33142. }
  33143. $tokens->clearAt($index + 1);
  33144. $tokens[$index] = new Token([T_ELSEIF, 'elseif']);
  33145. $tokens->clearAt($ifTokenIndex);
  33146. $beforeIfTokenIndex = $tokens->getPrevNonWhitespace($ifTokenIndex);
  33147. if ($tokens[$beforeIfTokenIndex]->isComment() && $tokens[$ifTokenIndex + 1]->isWhitespace()) {
  33148. $tokens->clearAt($ifTokenIndex + 1);
  33149. }
  33150. }
  33151. }
  33152. }
  33153. <?php
  33154. namespace PhpCsFixer\Fixer\ControlStructure;
  33155. use PhpCsFixer\AbstractFixer;
  33156. use PhpCsFixer\FixerDefinition\CodeSample;
  33157. use PhpCsFixer\FixerDefinition\FixerDefinition;
  33158. use PhpCsFixer\Tokenizer\Tokens;
  33159. final class NoTrailingCommaInListCallFixer extends AbstractFixer
  33160. {
  33161. public function getDefinition()
  33162. {
  33163. return new FixerDefinition(
  33164. 'Remove trailing commas in list function calls.',
  33165. [new CodeSample("<?php\nlist(\$a, \$b,) = foo();\n")]
  33166. );
  33167. }
  33168. public function isCandidate(Tokens $tokens)
  33169. {
  33170. return $tokens->isTokenKindFound(T_LIST);
  33171. }
  33172. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  33173. {
  33174. for ($index = $tokens->count() - 1; $index >= 0; --$index) {
  33175. $token = $tokens[$index];
  33176. if (!$token->isGivenKind(T_LIST)) {
  33177. continue;
  33178. }
  33179. $openIndex = $tokens->getNextMeaningfulToken($index);
  33180. $closeIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $openIndex);
  33181. $markIndex = null;
  33182. $prevIndex = $tokens->getPrevNonWhitespace($closeIndex);
  33183. while ($tokens[$prevIndex]->equals(',')) {
  33184. $markIndex = $prevIndex;
  33185. $prevIndex = $tokens->getPrevNonWhitespace($prevIndex);
  33186. }
  33187. if (null !== $markIndex) {
  33188. $tokens->clearRange(
  33189. $tokens->getPrevNonWhitespace($markIndex) + 1,
  33190. $closeIndex - 1
  33191. );
  33192. }
  33193. }
  33194. }
  33195. }
  33196. <?php
  33197. namespace PhpCsFixer\Fixer\ControlStructure;
  33198. use PhpCsFixer\AbstractFixer;
  33199. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  33200. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  33201. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  33202. use PhpCsFixer\FixerDefinition\CodeSample;
  33203. use PhpCsFixer\FixerDefinition\FixerDefinition;
  33204. use PhpCsFixer\Tokenizer\CT;
  33205. use PhpCsFixer\Tokenizer\Token;
  33206. use PhpCsFixer\Tokenizer\Tokens;
  33207. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  33208. /**
  33209. @gmail
  33210. */
  33211. final class YodaStyleFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface
  33212. {
  33213. private $candidatesMap;
  33214. private $candidateTypesConfiguration;
  33215. private $candidateTypes;
  33216. public function configure(array $configuration = null)
  33217. {
  33218. parent::configure($configuration);
  33219. $this->resolveConfiguration();
  33220. }
  33221. public function getDefinition()
  33222. {
  33223. return new FixerDefinition(
  33224. 'Write conditions in Yoda style (`true`), non-Yoda style (`false`) or ignore those conditions (`null`) based on configuration.',
  33225. [
  33226. new CodeSample(
  33227. '<?php
  33228. if ($a === null) {
  33229. echo "null";
  33230. }
  33231. '
  33232. ),
  33233. new CodeSample(
  33234. '<?php
  33235. $b = $c != 1; // equal
  33236. $a = 1 === $b; // identical
  33237. $c = $c > 3; // less than
  33238. ',
  33239. [
  33240. 'equal' => true,
  33241. 'identical' => false,
  33242. 'less_and_greater' => null,
  33243. ]
  33244. ),
  33245. new CodeSample(
  33246. '<?php
  33247. return $foo === count($bar);
  33248. ',
  33249. [
  33250. 'always_move_variable' => true,
  33251. ]
  33252. ),
  33253. ]
  33254. );
  33255. }
  33256. public function getPriority()
  33257. {
  33258. return 0;
  33259. }
  33260. public function isCandidate(Tokens $tokens)
  33261. {
  33262. return $tokens->isAnyTokenKindsFound($this->candidateTypes);
  33263. }
  33264. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  33265. {
  33266. $this->fixTokens($tokens);
  33267. }
  33268. protected function createConfigurationDefinition()
  33269. {
  33270. return new FixerConfigurationResolver([
  33271. (new FixerOptionBuilder('equal', 'Style for equal (`==`, `!=`) statements.'))
  33272. ->setAllowedTypes(['bool', 'null'])
  33273. ->setDefault(true)
  33274. ->getOption(),
  33275. (new FixerOptionBuilder('identical', 'Style for identical (`===`, `!==`) statements.'))
  33276. ->setAllowedTypes(['bool', 'null'])
  33277. ->setDefault(true)
  33278. ->getOption(),
  33279. (new FixerOptionBuilder('less_and_greater', 'Style for less and greater than (`<`, `<=`, `>`, `>=`) statements.'))
  33280. ->setAllowedTypes(['bool', 'null'])
  33281. ->setDefault(null)
  33282. ->getOption(),
  33283. (new FixerOptionBuilder('always_move_variable', 'Whether variables should always be on non assignable side when applying Yoda style.'))
  33284. ->setAllowedTypes(['bool'])
  33285. ->setDefault(false)
  33286. ->getOption(),
  33287. ]);
  33288. }
  33289. private function findComparisonEnd(Tokens $tokens, $index)
  33290. {
  33291. ++$index;
  33292. $count = \count($tokens);
  33293. while ($index < $count) {
  33294. $token = $tokens[$index];
  33295. if ($token->isGivenKind([T_WHITESPACE, T_COMMENT, T_DOC_COMMENT])) {
  33296. ++$index;
  33297. continue;
  33298. }
  33299. if ($this->isOfLowerPrecedence($token)) {
  33300. break;
  33301. }
  33302. $block = Tokens::detectBlockType($token);
  33303. if (null === $block) {
  33304. ++$index;
  33305. continue;
  33306. }
  33307. if (!$block['isStart']) {
  33308. break;
  33309. }
  33310. $index = $tokens->findBlockEnd($block['type'], $index) + 1;
  33311. }
  33312. $prev = $tokens->getPrevMeaningfulToken($index);
  33313. return $tokens[$prev]->isGivenKind(T_CLOSE_TAG) ? $tokens->getPrevMeaningfulToken($prev) : $prev;
  33314. }
  33315. private function findComparisonStart(Tokens $tokens, $index)
  33316. {
  33317. --$index;
  33318. $nonBlockFound = false;
  33319. while (0 <= $index) {
  33320. $token = $tokens[$index];
  33321. if ($token->isGivenKind([T_WHITESPACE, T_COMMENT, T_DOC_COMMENT])) {
  33322. --$index;
  33323. continue;
  33324. }
  33325. if ($this->isOfLowerPrecedence($token)) {
  33326. break;
  33327. }
  33328. $block = Tokens::detectBlockType($token);
  33329. if (null === $block) {
  33330. --$index;
  33331. $nonBlockFound = true;
  33332. continue;
  33333. }
  33334. if (
  33335. $block['isStart']
  33336. || ($nonBlockFound && Tokens::BLOCK_TYPE_CURLY_BRACE === $block['type'])
  33337. ) {
  33338. break;
  33339. }
  33340. $index = $tokens->findBlockStart($block['type'], $index) - 1;
  33341. }
  33342. return $tokens->getNextMeaningfulToken($index);
  33343. }
  33344. private function fixTokens(Tokens $tokens)
  33345. {
  33346. for ($i = \count($tokens) - 1; $i > 1; --$i) {
  33347. if ($tokens[$i]->isGivenKind($this->candidateTypes)) {
  33348. $yoda = $this->candidateTypesConfiguration[$tokens[$i]->getId()];
  33349. } elseif (
  33350. ($tokens[$i]->equals('<') && \in_array('<', $this->candidateTypes, true))
  33351. || ($tokens[$i]->equals('>') && \in_array('>', $this->candidateTypes, true))
  33352. ) {
  33353. $yoda = $this->candidateTypesConfiguration[$tokens[$i]->getContent()];
  33354. } else {
  33355. continue;
  33356. }
  33357. $fixableCompareInfo = $this->getCompareFixableInfo($tokens, $i, $yoda);
  33358. if (null === $fixableCompareInfo) {
  33359. continue;
  33360. }
  33361. $i = $this->fixTokensCompare(
  33362. $tokens,
  33363. $fixableCompareInfo['left']['start'],
  33364. $fixableCompareInfo['left']['end'],
  33365. $i,
  33366. $fixableCompareInfo['right']['start'],
  33367. $fixableCompareInfo['right']['end']
  33368. );
  33369. }
  33370. return $tokens;
  33371. }
  33372. private function fixTokensCompare(
  33373. Tokens $tokens,
  33374. $startLeft,
  33375. $endLeft,
  33376. $compareOperatorIndex,
  33377. $startRight,
  33378. $endRight
  33379. ) {
  33380. $type = $tokens[$compareOperatorIndex]->getId();
  33381. $content = $tokens[$compareOperatorIndex]->getContent();
  33382. if (\array_key_exists($type, $this->candidatesMap)) {
  33383. $tokens[$compareOperatorIndex] = clone $this->candidatesMap[$type];
  33384. } elseif (\array_key_exists($content, $this->candidatesMap)) {
  33385. $tokens[$compareOperatorIndex] = clone $this->candidatesMap[$content];
  33386. }
  33387. $right = $this->fixTokensComparePart($tokens, $startRight, $endRight);
  33388. $left = $this->fixTokensComparePart($tokens, $startLeft, $endLeft);
  33389. for ($i = $startRight; $i <= $endRight; ++$i) {
  33390. $tokens->clearAt($i);
  33391. }
  33392. for ($i = $startLeft; $i <= $endLeft; ++$i) {
  33393. $tokens->clearAt($i);
  33394. }
  33395. $tokens->insertAt($startRight, $left);
  33396. $tokens->insertAt($startLeft, $right);
  33397. return $startLeft;
  33398. }
  33399. private function fixTokensComparePart(Tokens $tokens, $start, $end)
  33400. {
  33401. $newTokens = $tokens->generatePartialCode($start, $end);
  33402. $newTokens = $this->fixTokens(Tokens::fromCode(sprintf('<?php %s;', $newTokens)));
  33403. $newTokens->clearAt(\count($newTokens) - 1);
  33404. $newTokens->clearAt(0);
  33405. $newTokens->clearEmptyTokens();
  33406. return $newTokens;
  33407. }
  33408. private function getCompareFixableInfo(Tokens $tokens, $index, $yoda)
  33409. {
  33410. $left = $this->getLeftSideCompareFixableInfo($tokens, $index);
  33411. $right = $this->getRightSideCompareFixableInfo($tokens, $index);
  33412. if ($yoda) {
  33413. $expectedAssignableSide = $right;
  33414. $expectedValueSide = $left;
  33415. } else {
  33416. if ($tokens[$tokens->getNextMeaningfulToken($right['end'])]->equals('=')) {
  33417. return null;
  33418. }
  33419. $expectedAssignableSide = $left;
  33420. $expectedValueSide = $right;
  33421. }
  33422. if (
  33423. !(
  33424. !$this->isVariable($tokens, $expectedAssignableSide['start'], $expectedAssignableSide['end'], false)
  33425. && !$this->isListStatement($tokens, $expectedAssignableSide['start'], $expectedAssignableSide['end'])
  33426. && $this->isVariable($tokens, $expectedValueSide['start'], $expectedValueSide['end'], false)
  33427. )
  33428. && !(
  33429. $this->configuration['always_move_variable']
  33430. && !$this->isVariable($tokens, $expectedAssignableSide['start'], $expectedAssignableSide['end'], true)
  33431. && !$this->isListStatement($tokens, $expectedAssignableSide['start'], $expectedAssignableSide['end'])
  33432. && $this->isVariable($tokens, $expectedValueSide['start'], $expectedValueSide['end'], true)
  33433. )
  33434. ) {
  33435. return null;
  33436. }
  33437. return [
  33438. 'left' => $left,
  33439. 'right' => $right,
  33440. ];
  33441. }
  33442. private function getLeftSideCompareFixableInfo(Tokens $tokens, $index)
  33443. {
  33444. return [
  33445. 'start' => $this->findComparisonStart($tokens, $index),
  33446. 'end' => $tokens->getPrevMeaningfulToken($index),
  33447. ];
  33448. }
  33449. private function getRightSideCompareFixableInfo(Tokens $tokens, $index)
  33450. {
  33451. return [
  33452. 'start' => $tokens->getNextMeaningfulToken($index),
  33453. 'end' => $this->findComparisonEnd($tokens, $index),
  33454. ];
  33455. }
  33456. private function isListStatement(Tokens $tokens, $index, $end)
  33457. {
  33458. for ($i = $index; $i <= $end; ++$i) {
  33459. if ($tokens[$i]->isGivenKind([T_LIST, CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN, CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE])) {
  33460. return true;
  33461. }
  33462. }
  33463. return false;
  33464. }
  33465. private function isOfLowerPrecedence(Token $token)
  33466. {
  33467. static $tokens;
  33468. if (null === $tokens) {
  33469. $tokens = [
  33470. T_AND_EQUAL,
  33471. T_BOOLEAN_AND,
  33472. T_BOOLEAN_OR,
  33473. T_CASE,
  33474. T_CONCAT_EQUAL,
  33475. T_DIV_EQUAL,
  33476. T_DOUBLE_ARROW,
  33477. T_ECHO,
  33478. T_GOTO,
  33479. T_LOGICAL_AND,
  33480. T_LOGICAL_OR,
  33481. T_LOGICAL_XOR,
  33482. T_MINUS_EQUAL,
  33483. T_MOD_EQUAL,
  33484. T_MUL_EQUAL,
  33485. T_OPEN_TAG,
  33486. T_OPEN_TAG_WITH_ECHO,
  33487. T_OR_EQUAL,
  33488. T_PLUS_EQUAL,
  33489. T_POW_EQUAL,
  33490. T_PRINT,
  33491. T_RETURN,
  33492. T_SL_EQUAL,
  33493. T_SR_EQUAL,
  33494. T_THROW,
  33495. T_XOR_EQUAL,
  33496. ];
  33497. if (\defined('T_COALESCE')) {
  33498. $tokens[] = T_COALESCE;
  33499. }
  33500. if (\defined('T_COALESCE_EQUAL')) {
  33501. $tokens[] = T_COALESCE_EQUAL;
  33502. }
  33503. }
  33504. static $otherTokens = [
  33505. '&', '|', '^',
  33506. '?', ':',
  33507. '=',
  33508. ',', ';',
  33509. ];
  33510. return $token->isGivenKind($tokens) || $token->equalsAny($otherTokens);
  33511. }
  33512. private function isVariable(Tokens $tokens, $start, $end, $strict)
  33513. {
  33514. $tokenAnalyzer = new TokensAnalyzer($tokens);
  33515. if ($start === $end) {
  33516. return $tokens[$start]->isGivenKind(T_VARIABLE);
  33517. }
  33518. if ($strict) {
  33519. if ($tokens[$start]->equals('(')) {
  33520. return false;
  33521. }
  33522. for ($index = $start; $index <= $end; ++$index) {
  33523. if (
  33524. $tokens[$index]->isCast()
  33525. || $tokens[$index]->isGivenKind(T_INSTANCEOF)
  33526. || $tokens[$index]->equals('!')
  33527. || $tokenAnalyzer->isBinaryOperator($index)
  33528. ) {
  33529. return false;
  33530. }
  33531. }
  33532. }
  33533. $index = $start;
  33534. while (
  33535. $tokens[$index]->equals('(')
  33536. && $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $index) === $end
  33537. ) {
  33538. $index = $tokens->getNextMeaningfulToken($index);
  33539. $end = $tokens->getPrevMeaningfulToken($end);
  33540. }
  33541. $expectString = false;
  33542. while ($index <= $end) {
  33543. $current = $tokens[$index];
  33544. if ($current->isComment() || $current->isWhitespace() || $tokens->isEmptyAt($index)) {
  33545. ++$index;
  33546. continue;
  33547. }
  33548. if ($index === $end) {
  33549. return $current->isGivenKind($expectString ? T_STRING : T_VARIABLE);
  33550. }
  33551. if ($current->isGivenKind([T_LIST, CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN, CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE])) {
  33552. return false;
  33553. }
  33554. $nextIndex = $tokens->getNextMeaningfulToken($index);
  33555. $next = $tokens[$nextIndex];
  33556. if ($current->isGivenKind(T_STRING) && $next->isGivenKind(T_DOUBLE_COLON)) {
  33557. $index = $tokens->getNextMeaningfulToken($nextIndex);
  33558. continue;
  33559. }
  33560. if ($current->isGivenKind(T_NS_SEPARATOR) && $next->isGivenKind(T_STRING)) {
  33561. $index = $nextIndex;
  33562. continue;
  33563. }
  33564. if ($current->isGivenKind(T_STRING) && $next->isGivenKind(T_NS_SEPARATOR)) {
  33565. $index = $nextIndex;
  33566. continue;
  33567. }
  33568. if ($current->isGivenKind([T_STRING, T_VARIABLE]) && $next->isGivenKind(T_OBJECT_OPERATOR)) {
  33569. $index = $tokens->getNextMeaningfulToken($nextIndex);
  33570. $expectString = true;
  33571. continue;
  33572. }
  33573. if (
  33574. $current->isGivenKind($expectString ? T_STRING : T_VARIABLE)
  33575. && $next->equalsAny(['[', [CT::T_ARRAY_INDEX_CURLY_BRACE_OPEN, '{']])
  33576. ) {
  33577. $index = $tokens->findBlockEnd(
  33578. $next->equals('[') ? Tokens::BLOCK_TYPE_INDEX_SQUARE_BRACE : Tokens::BLOCK_TYPE_ARRAY_INDEX_CURLY_BRACE,
  33579. $nextIndex
  33580. );
  33581. if ($index === $end) {
  33582. return true;
  33583. }
  33584. $index = $tokens->getNextMeaningfulToken($index);
  33585. if (!$tokens[$index]->equalsAny([[T_OBJECT_OPERATOR, '->'], '[', [CT::T_ARRAY_INDEX_CURLY_BRACE_OPEN, '{']])) {
  33586. return false;
  33587. }
  33588. $index = $tokens->getNextMeaningfulToken($index);
  33589. $expectString = true;
  33590. continue;
  33591. }
  33592. if ($strict && $current->isGivenKind([T_STRING, T_VARIABLE]) && $next->equals('(')) {
  33593. return false;
  33594. }
  33595. if ($expectString && $current->isGivenKind(CT::T_DYNAMIC_PROP_BRACE_OPEN)) {
  33596. $index = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_DYNAMIC_PROP_BRACE, $index);
  33597. if ($index === $end) {
  33598. return true;
  33599. }
  33600. $index = $tokens->getNextMeaningfulToken($index);
  33601. if (!$tokens[$index]->isGivenKind(T_OBJECT_OPERATOR)) {
  33602. return false;
  33603. }
  33604. $index = $tokens->getNextMeaningfulToken($index);
  33605. $expectString = true;
  33606. continue;
  33607. }
  33608. break;
  33609. }
  33610. return !$this->isConstant($tokens, $start, $end);
  33611. }
  33612. private function isConstant(Tokens $tokens, $index, $end)
  33613. {
  33614. $expectArrayOnly = false;
  33615. $expectNumberOnly = false;
  33616. $expectNothing = false;
  33617. for (; $index <= $end; ++$index) {
  33618. $token = $tokens[$index];
  33619. if ($token->isComment() || $token->isWhitespace()) {
  33620. continue;
  33621. }
  33622. if ($expectNothing) {
  33623. return false;
  33624. }
  33625. if ($expectArrayOnly) {
  33626. if ($token->equalsAny(['(', ')', [CT::T_ARRAY_SQUARE_BRACE_CLOSE]])) {
  33627. continue;
  33628. }
  33629. return false;
  33630. }
  33631. if ($token->isGivenKind([T_ARRAY, CT::T_ARRAY_SQUARE_BRACE_OPEN])) {
  33632. $expectArrayOnly = true;
  33633. continue;
  33634. }
  33635. if ($expectNumberOnly && !$token->isGivenKind([T_LNUMBER, T_DNUMBER])) {
  33636. return false;
  33637. }
  33638. if ($token->equals('-')) {
  33639. $expectNumberOnly = true;
  33640. continue;
  33641. }
  33642. if (
  33643. $token->isGivenKind([T_LNUMBER, T_DNUMBER, T_CONSTANT_ENCAPSED_STRING])
  33644. || $token->equalsAny([[T_STRING, 'true'], [T_STRING, 'false'], [T_STRING, 'null']])
  33645. ) {
  33646. $expectNothing = true;
  33647. continue;
  33648. }
  33649. return false;
  33650. }
  33651. return true;
  33652. }
  33653. private function resolveConfiguration()
  33654. {
  33655. $candidateTypes = [];
  33656. $this->candidatesMap = [];
  33657. if (null !== $this->configuration['equal']) {
  33658. $candidateTypes[T_IS_EQUAL] = $this->configuration['equal'];
  33659. $candidateTypes[T_IS_NOT_EQUAL] = $this->configuration['equal'];
  33660. }
  33661. if (null !== $this->configuration['identical']) {
  33662. $candidateTypes[T_IS_IDENTICAL] = $this->configuration['identical'];
  33663. $candidateTypes[T_IS_NOT_IDENTICAL] = $this->configuration['identical'];
  33664. }
  33665. if (null !== $this->configuration['less_and_greater']) {
  33666. $candidateTypes[T_IS_SMALLER_OR_EQUAL] = $this->configuration['less_and_greater'];
  33667. $this->candidatesMap[T_IS_SMALLER_OR_EQUAL] = new Token([T_IS_GREATER_OR_EQUAL, '>=']);
  33668. $candidateTypes[T_IS_GREATER_OR_EQUAL] = $this->configuration['less_and_greater'];
  33669. $this->candidatesMap[T_IS_GREATER_OR_EQUAL] = new Token([T_IS_SMALLER_OR_EQUAL, '<=']);
  33670. $candidateTypes['<'] = $this->configuration['less_and_greater'];
  33671. $this->candidatesMap['<'] = new Token('>');
  33672. $candidateTypes['>'] = $this->configuration['less_and_greater'];
  33673. $this->candidatesMap['>'] = new Token('<');
  33674. }
  33675. $this->candidateTypesConfiguration = $candidateTypes;
  33676. $this->candidateTypes = array_keys($candidateTypes);
  33677. }
  33678. }
  33679. <?php
  33680. namespace PhpCsFixer\Fixer\ControlStructure;
  33681. use PhpCsFixer\AbstractNoUselessElseFixer;
  33682. use PhpCsFixer\FixerDefinition\CodeSample;
  33683. use PhpCsFixer\FixerDefinition\FixerDefinition;
  33684. use PhpCsFixer\Preg;
  33685. use PhpCsFixer\Tokenizer\Token;
  33686. use PhpCsFixer\Tokenizer\Tokens;
  33687. final class NoSuperfluousElseifFixer extends AbstractNoUselessElseFixer
  33688. {
  33689. public function isCandidate(Tokens $tokens)
  33690. {
  33691. return $tokens->isAnyTokenKindsFound([T_ELSE, T_ELSEIF]);
  33692. }
  33693. public function getDefinition()
  33694. {
  33695. return new FixerDefinition(
  33696. 'Replaces superfluous `elseif` with `if`.',
  33697. [
  33698. new CodeSample("<?php\nif (\$a) {\n return 1;\n} elseif (\$b) {\n return 2;\n}\n"),
  33699. ]
  33700. );
  33701. }
  33702. public function getPriority()
  33703. {
  33704. return parent::getPriority();
  33705. }
  33706. protected function applyFix(\SplFileInfo $file, Tokens $tokens)
  33707. {
  33708. foreach ($tokens as $index => $token) {
  33709. if ($this->isElseif($tokens, $index) && $this->isSuperfluousElse($tokens, $index)) {
  33710. $this->convertElseifToIf($tokens, $index);
  33711. }
  33712. }
  33713. }
  33714. private function isElseif(Tokens $tokens, $index)
  33715. {
  33716. if ($tokens[$index]->isGivenKind(T_ELSEIF)) {
  33717. return true;
  33718. }
  33719. return $tokens[$index]->isGivenKind(T_ELSE) && $tokens[$tokens->getNextMeaningfulToken($index)]->isGivenKind(T_IF);
  33720. }
  33721. private function convertElseifToIf(Tokens $tokens, $index)
  33722. {
  33723. if ($tokens[$index]->isGivenKind(T_ELSE)) {
  33724. $tokens->clearTokenAndMergeSurroundingWhitespace($index);
  33725. } else {
  33726. $tokens[$index] = new Token([T_IF, 'if']);
  33727. }
  33728. $whitespace = '';
  33729. for ($previous = $index - 1; $previous > 0; --$previous) {
  33730. $token = $tokens[$previous];
  33731. if ($token->isWhitespace() && Preg::match('/(\R\N*)$/', $token->getContent(), $matches)) {
  33732. $whitespace = $matches[1];
  33733. break;
  33734. }
  33735. }
  33736. if ('' === $whitespace) {
  33737. return;
  33738. }
  33739. $previousToken = $tokens[$index - 1];
  33740. if (!$previousToken->isWhitespace()) {
  33741. $tokens->insertAt($index, new Token([T_WHITESPACE, $whitespace]));
  33742. } elseif (!Preg::match('/\R/', $previousToken->getContent())) {
  33743. $tokens[$index - 1] = new Token([T_WHITESPACE, $whitespace]);
  33744. }
  33745. }
  33746. }
  33747. <?php
  33748. namespace PhpCsFixer;
  33749. final class PregException extends \RuntimeException
  33750. {
  33751. }
  33752. <?php
  33753. namespace PhpCsFixer\Indicator;
  33754. use PhpCsFixer\Preg;
  33755. use PhpCsFixer\Tokenizer\Tokens;
  33756. final class PhpUnitTestCaseIndicator
  33757. {
  33758. public function isPhpUnitClass(Tokens $tokens, $index)
  33759. {
  33760. if (!$tokens[$index]->isGivenKind(T_CLASS)) {
  33761. throw new \LogicException(sprintf('No T_CLASS at given index %d, got %s.', $index, $tokens[$index]->getName()));
  33762. }
  33763. $index = $tokens->getNextMeaningfulToken($index);
  33764. if (0 !== Preg::match('/(?:Test|TestCase)$/', $tokens[$index]->getContent())) {
  33765. return true;
  33766. }
  33767. while (null !== $index = $tokens->getNextMeaningfulToken($index)) {
  33768. if ($tokens[$index]->equals('{')) {
  33769. break;
  33770. }
  33771. if (!$tokens[$index]->isGivenKind(T_STRING)) {
  33772. continue;
  33773. }
  33774. if (0 !== Preg::match('/(?:Test|TestCase)(?:Interface)?$/', $tokens[$index]->getContent())) {
  33775. return true;
  33776. }
  33777. }
  33778. return false;
  33779. }
  33780. public function findPhpUnitClasses(Tokens $tokens, $beginAtBottom = true)
  33781. {
  33782. $direction = $beginAtBottom ? -1 : 1;
  33783. for ($index = 1 === $direction ? 0 : $tokens->count() - 1; $tokens->offsetExists($index); $index += $direction) {
  33784. if (!$tokens[$index]->isGivenKind(T_CLASS) || !$this->isPhpUnitClass($tokens, $index)) {
  33785. continue;
  33786. }
  33787. $startIndex = $tokens->getNextTokenOfKind($index, ['{'], false);
  33788. if (null === $startIndex) {
  33789. return;
  33790. }
  33791. $endIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $startIndex);
  33792. yield [$startIndex, $endIndex];
  33793. }
  33794. }
  33795. }
  33796. <?php
  33797. namespace PhpCsFixer\ConfigurationException;
  33798. final class RequiredFixerConfigurationException extends InvalidFixerConfigurationException
  33799. {
  33800. }
  33801. <?php
  33802. namespace PhpCsFixer\ConfigurationException;
  33803. final class InvalidForEnvFixerConfigurationException extends InvalidFixerConfigurationException
  33804. {
  33805. }
  33806. <?php
  33807. namespace PhpCsFixer\ConfigurationException;
  33808. use PhpCsFixer\Console\Command\FixCommandExitStatusCalculator;
  33809. class InvalidFixerConfigurationException extends InvalidConfigurationException
  33810. {
  33811. private $fixerName;
  33812. public function __construct($fixerName, $message, $previous = null)
  33813. {
  33814. parent::__construct(
  33815. sprintf('[%s] %s', $fixerName, $message),
  33816. FixCommandExitStatusCalculator::EXIT_STATUS_FLAG_HAS_INVALID_FIXER_CONFIG,
  33817. $previous
  33818. );
  33819. $this->fixerName = $fixerName;
  33820. }
  33821. public function getFixerName()
  33822. {
  33823. return $this->fixerName;
  33824. }
  33825. }
  33826. <?php
  33827. namespace PhpCsFixer\ConfigurationException;
  33828. use PhpCsFixer\Console\Command\FixCommandExitStatusCalculator;
  33829. class InvalidConfigurationException extends \InvalidArgumentException
  33830. {
  33831. public function __construct($message, $code = null, $previous = null)
  33832. {
  33833. parent::__construct(
  33834. $message,
  33835. null === $code ? FixCommandExitStatusCalculator::EXIT_STATUS_FLAG_HAS_INVALID_CONFIG : $code,
  33836. $previous
  33837. );
  33838. }
  33839. }
  33840. <?php
  33841. namespace PhpCsFixer;
  33842. use PhpCsFixer\Fixer\FixerInterface;
  33843. use PhpCsFixer\Tokenizer\Token;
  33844. /**
  33845. @alt
  33846. @gmail
  33847. */
  33848. final class Utils
  33849. {
  33850. public static function calculateBitmask(array $options)
  33851. {
  33852. $bitmask = 0;
  33853. foreach ($options as $optionName) {
  33854. if (\defined($optionName)) {
  33855. $bitmask |= \constant($optionName);
  33856. }
  33857. }
  33858. return $bitmask;
  33859. }
  33860. public static function camelCaseToUnderscore($string)
  33861. {
  33862. return strtolower(Preg::replace('/(?<!^)((?=[A-Z][^A-Z])|(?<![A-Z])(?=[A-Z]))/', '_', $string));
  33863. }
  33864. public static function cmpInt($a, $b)
  33865. {
  33866. if ($a === $b) {
  33867. return 0;
  33868. }
  33869. return $a < $b ? -1 : 1;
  33870. }
  33871. public static function calculateTrailingWhitespaceIndent(Token $token)
  33872. {
  33873. if (!$token->isWhitespace()) {
  33874. throw new \InvalidArgumentException(sprintf('The given token must be whitespace, got "%s".', $token->getName()));
  33875. }
  33876. $str = strrchr(
  33877. str_replace(["\r\n", "\r"], "\n", $token->getContent()),
  33878. "\n"
  33879. );
  33880. if (false === $str) {
  33881. return '';
  33882. }
  33883. return ltrim($str, "\n");
  33884. }
  33885. public static function stableSort(array $elements, callable $getComparedValue, callable $compareValues)
  33886. {
  33887. array_walk($elements, static function (&$element, $index) use ($getComparedValue) {
  33888. $element = [$element, $index, $getComparedValue($element)];
  33889. });
  33890. usort($elements, static function ($a, $b) use ($compareValues) {
  33891. $comparison = $compareValues($a[2], $b[2]);
  33892. if (0 !== $comparison) {
  33893. return $comparison;
  33894. }
  33895. return self::cmpInt($a[1], $b[1]);
  33896. });
  33897. return array_map(static function (array $item) {
  33898. return $item[0];
  33899. }, $elements);
  33900. }
  33901. public static function sortFixers(array $fixers)
  33902. {
  33903. return self::stableSort(
  33904. $fixers,
  33905. static function (FixerInterface $fixer) {
  33906. return $fixer->getPriority();
  33907. },
  33908. static function ($a, $b) {
  33909. return self::cmpInt($b, $a);
  33910. }
  33911. );
  33912. }
  33913. public static function naturalLanguageJoinWithBackticks(array $names)
  33914. {
  33915. if (empty($names)) {
  33916. throw new \InvalidArgumentException('Array of names cannot be empty');
  33917. }
  33918. $names = array_map(static function ($name) {
  33919. return sprintf('`%s`', $name);
  33920. }, $names);
  33921. $last = array_pop($names);
  33922. if ($names) {
  33923. return implode(', ', $names).' and '.$last;
  33924. }
  33925. return $last;
  33926. }
  33927. }
  33928. <?php
  33929. namespace PhpCsFixer\Tokenizer;
  33930. use PhpCsFixer\Utils;
  33931. class Token
  33932. {
  33933. private $content;
  33934. private $id;
  33935. private $isArray;
  33936. private $changed = false;
  33937. public function __construct($token)
  33938. {
  33939. if (\is_array($token)) {
  33940. if (!\is_int($token[0])) {
  33941. throw new \InvalidArgumentException(sprintf(
  33942. 'Id must be an int, got "%s".',
  33943. \is_object($token[0]) ? \get_class($token[0]) : \gettype($token[0])
  33944. ));
  33945. }
  33946. if (!\is_string($token[1])) {
  33947. throw new \InvalidArgumentException(sprintf(
  33948. 'Content must be a string, got "%s".',
  33949. \is_object($token[1]) ? \get_class($token[1]) : \gettype($token[1])
  33950. ));
  33951. }
  33952. if ('' === $token[1]) {
  33953. throw new \InvalidArgumentException('Cannot set empty content for id-based Token.');
  33954. }
  33955. $this->isArray = true;
  33956. $this->id = $token[0];
  33957. $this->content = $token[1];
  33958. if ($token[0] && '' === $token[1]) {
  33959. throw new \InvalidArgumentException('Cannot set empty content for id-based Token.');
  33960. }
  33961. } elseif (\is_string($token)) {
  33962. $this->isArray = false;
  33963. $this->content = $token;
  33964. } else {
  33965. throw new \InvalidArgumentException(sprintf(
  33966. 'Cannot recognize input value as valid Token prototype, got "%s".',
  33967. \is_object($token) ? \get_class($token) : \gettype($token)
  33968. ));
  33969. }
  33970. }
  33971. public static function getCastTokenKinds()
  33972. {
  33973. static $castTokens = [T_ARRAY_CAST, T_BOOL_CAST, T_DOUBLE_CAST, T_INT_CAST, T_OBJECT_CAST, T_STRING_CAST, T_UNSET_CAST];
  33974. return $castTokens;
  33975. }
  33976. public static function getClassyTokenKinds()
  33977. {
  33978. static $classTokens = [T_CLASS, T_TRAIT, T_INTERFACE];
  33979. return $classTokens;
  33980. }
  33981. public function clear()
  33982. {
  33983. @trigger_error(__METHOD__.' is deprecated and will be removed in 3.0.', E_USER_DEPRECATED);
  33984. Tokens::setLegacyMode(true);
  33985. $this->content = '';
  33986. $this->id = null;
  33987. $this->isArray = false;
  33988. }
  33989. public function clearChanged()
  33990. {
  33991. @trigger_error(__METHOD__.' is deprecated and will be removed in 3.0.', E_USER_DEPRECATED);
  33992. Tokens::setLegacyMode(true);
  33993. $this->changed = false;
  33994. }
  33995. public function equals($other, $caseSensitive = true)
  33996. {
  33997. if ($other instanceof self) {
  33998. if (!$other->isArray) {
  33999. $otherPrototype = $other->content;
  34000. } else {
  34001. $otherPrototype = [
  34002. $other->id,
  34003. $other->content,
  34004. ];
  34005. }
  34006. } else {
  34007. $otherPrototype = $other;
  34008. }
  34009. if ($this->isArray !== \is_array($otherPrototype)) {
  34010. return false;
  34011. }
  34012. if (!$this->isArray) {
  34013. return $this->content === $otherPrototype;
  34014. }
  34015. if ($this->id !== $otherPrototype[0]) {
  34016. return false;
  34017. }
  34018. if (isset($otherPrototype[1])) {
  34019. if ($caseSensitive) {
  34020. if ($this->content !== $otherPrototype[1]) {
  34021. return false;
  34022. }
  34023. } elseif (0 !== strcasecmp($this->content, $otherPrototype[1])) {
  34024. return false;
  34025. }
  34026. }
  34027. unset($otherPrototype[0], $otherPrototype[1]);
  34028. return empty($otherPrototype);
  34029. }
  34030. public function equalsAny(array $others, $caseSensitive = true)
  34031. {
  34032. foreach ($others as $other) {
  34033. if ($this->equals($other, $caseSensitive)) {
  34034. return true;
  34035. }
  34036. }
  34037. return false;
  34038. }
  34039. public static function isKeyCaseSensitive($caseSensitive, $key)
  34040. {
  34041. if (\is_array($caseSensitive)) {
  34042. return isset($caseSensitive[$key]) ? $caseSensitive[$key] : true;
  34043. }
  34044. return $caseSensitive;
  34045. }
  34046. public function getPrototype()
  34047. {
  34048. if (!$this->isArray) {
  34049. return $this->content;
  34050. }
  34051. return [
  34052. $this->id,
  34053. $this->content,
  34054. ];
  34055. }
  34056. public function getContent()
  34057. {
  34058. return $this->content;
  34059. }
  34060. public function getId()
  34061. {
  34062. return $this->id;
  34063. }
  34064. public function getName()
  34065. {
  34066. if (null === $this->id) {
  34067. return null;
  34068. }
  34069. return self::getNameForId($this->id);
  34070. }
  34071. public static function getNameForId($id)
  34072. {
  34073. if (CT::has($id)) {
  34074. return CT::getName($id);
  34075. }
  34076. $name = token_name($id);
  34077. return 'UNKNOWN' === $name ? null : $name;
  34078. }
  34079. public static function getKeywords()
  34080. {
  34081. static $keywords = null;
  34082. if (null === $keywords) {
  34083. $keywords = self::getTokenKindsForNames(['T_ABSTRACT', 'T_ARRAY', 'T_AS', 'T_BREAK', 'T_CALLABLE', 'T_CASE',
  34084. 'T_CATCH', 'T_CLASS', 'T_CLONE', 'T_CONST', 'T_CONTINUE', 'T_DECLARE', 'T_DEFAULT', 'T_DO',
  34085. 'T_ECHO', 'T_ELSE', 'T_ELSEIF', 'T_EMPTY', 'T_ENDDECLARE', 'T_ENDFOR', 'T_ENDFOREACH',
  34086. 'T_ENDIF', 'T_ENDSWITCH', 'T_ENDWHILE', 'T_EVAL', 'T_EXIT', 'T_EXTENDS', 'T_FINAL',
  34087. 'T_FINALLY', 'T_FN', 'T_FOR', 'T_FOREACH', 'T_FUNCTION', 'T_GLOBAL', 'T_GOTO', 'T_HALT_COMPILER',
  34088. 'T_IF', 'T_IMPLEMENTS', 'T_INCLUDE', 'T_INCLUDE_ONCE', 'T_INSTANCEOF', 'T_INSTEADOF',
  34089. 'T_INTERFACE', 'T_ISSET', 'T_LIST', 'T_LOGICAL_AND', 'T_LOGICAL_OR', 'T_LOGICAL_XOR',
  34090. 'T_NAMESPACE', 'T_NEW', 'T_PRINT', 'T_PRIVATE', 'T_PROTECTED', 'T_PUBLIC', 'T_REQUIRE',
  34091. 'T_REQUIRE_ONCE', 'T_RETURN', 'T_STATIC', 'T_SWITCH', 'T_THROW', 'T_TRAIT', 'T_TRY',
  34092. 'T_UNSET', 'T_USE', 'T_VAR', 'T_WHILE', 'T_YIELD', 'T_YIELD_FROM',
  34093. ]) + [
  34094. CT::T_ARRAY_TYPEHINT => CT::T_ARRAY_TYPEHINT,
  34095. CT::T_CLASS_CONSTANT => CT::T_CLASS_CONSTANT,
  34096. CT::T_CONST_IMPORT => CT::T_CONST_IMPORT,
  34097. CT::T_FUNCTION_IMPORT => CT::T_FUNCTION_IMPORT,
  34098. CT::T_NAMESPACE_OPERATOR => CT::T_NAMESPACE_OPERATOR,
  34099. CT::T_USE_TRAIT => CT::T_USE_TRAIT,
  34100. CT::T_USE_LAMBDA => CT::T_USE_LAMBDA,
  34101. ];
  34102. }
  34103. return $keywords;
  34104. }
  34105. public static function getMagicConstants()
  34106. {
  34107. static $magicConstants = null;
  34108. if (null === $magicConstants) {
  34109. $magicConstants = self::getTokenKindsForNames(['T_CLASS_C', 'T_DIR', 'T_FILE', 'T_FUNC_C', 'T_LINE', 'T_METHOD_C', 'T_NS_C', 'T_TRAIT_C']);
  34110. }
  34111. return $magicConstants;
  34112. }
  34113. public function isArray()
  34114. {
  34115. return $this->isArray;
  34116. }
  34117. public function isCast()
  34118. {
  34119. return $this->isGivenKind(self::getCastTokenKinds());
  34120. }
  34121. public function isChanged()
  34122. {
  34123. @trigger_error(__METHOD__.' is deprecated and will be removed in 3.0.', E_USER_DEPRECATED);
  34124. return $this->changed;
  34125. }
  34126. public function isClassy()
  34127. {
  34128. return $this->isGivenKind(self::getClassyTokenKinds());
  34129. }
  34130. public function isComment()
  34131. {
  34132. static $commentTokens = [T_COMMENT, T_DOC_COMMENT];
  34133. return $this->isGivenKind($commentTokens);
  34134. }
  34135. public function isEmpty()
  34136. {
  34137. @trigger_error(__METHOD__.' is deprecated and will be removed in 3.0.', E_USER_DEPRECATED);
  34138. return null === $this->id && ('' === $this->content || null === $this->content);
  34139. }
  34140. public function isGivenKind($possibleKind)
  34141. {
  34142. return $this->isArray && (\is_array($possibleKind) ? \in_array($this->id, $possibleKind, true) : $this->id === $possibleKind);
  34143. }
  34144. public function isKeyword()
  34145. {
  34146. $keywords = static::getKeywords();
  34147. return $this->isArray && isset($keywords[$this->id]);
  34148. }
  34149. public function isNativeConstant()
  34150. {
  34151. static $nativeConstantStrings = ['true', 'false', 'null'];
  34152. return $this->isArray && \in_array(strtolower($this->content), $nativeConstantStrings, true);
  34153. }
  34154. public function isMagicConstant()
  34155. {
  34156. $magicConstants = static::getMagicConstants();
  34157. return $this->isArray && isset($magicConstants[$this->id]);
  34158. }
  34159. public function isWhitespace($whitespaces = " \t\n\r\0\x0B")
  34160. {
  34161. if (null === $whitespaces) {
  34162. $whitespaces = " \t\n\r\0\x0B";
  34163. }
  34164. if ($this->isArray && !$this->isGivenKind(T_WHITESPACE)) {
  34165. return false;
  34166. }
  34167. return '' === trim($this->content, $whitespaces);
  34168. }
  34169. public function override($other)
  34170. {
  34171. @trigger_error(__METHOD__.' is deprecated and will be removed in 3.0.', E_USER_DEPRECATED);
  34172. Tokens::setLegacyMode(true);
  34173. $prototype = $other instanceof self ? $other->getPrototype() : $other;
  34174. if ($this->equals($prototype)) {
  34175. return;
  34176. }
  34177. $this->changed = true;
  34178. if (\is_array($prototype)) {
  34179. $this->isArray = true;
  34180. $this->id = $prototype[0];
  34181. $this->content = $prototype[1];
  34182. return;
  34183. }
  34184. $this->isArray = false;
  34185. $this->id = null;
  34186. $this->content = $prototype;
  34187. }
  34188. public function setContent($content)
  34189. {
  34190. @trigger_error(__METHOD__.' is deprecated and will be removed in 3.0.', E_USER_DEPRECATED);
  34191. Tokens::setLegacyMode(true);
  34192. if ($this->content === $content) {
  34193. return;
  34194. }
  34195. $this->changed = true;
  34196. $this->content = $content;
  34197. if ('' === $content) {
  34198. @trigger_error(__METHOD__.' shall not be used to clear token, use Tokens::clearAt instead.', E_USER_DEPRECATED);
  34199. $this->id = null;
  34200. $this->isArray = false;
  34201. }
  34202. }
  34203. public function toArray()
  34204. {
  34205. return [
  34206. 'id' => $this->id,
  34207. 'name' => $this->getName(),
  34208. 'content' => $this->content,
  34209. 'isArray' => $this->isArray,
  34210. 'changed' => $this->changed,
  34211. ];
  34212. }
  34213. public function toJson(array $options = null)
  34214. {
  34215. static $defaultOptions = null;
  34216. if (null === $options) {
  34217. if (null === $defaultOptions) {
  34218. $defaultOptions = Utils::calculateBitmask(['JSON_PRETTY_PRINT', 'JSON_NUMERIC_CHECK']);
  34219. }
  34220. $options = $defaultOptions;
  34221. } else {
  34222. $options = Utils::calculateBitmask($options);
  34223. }
  34224. return json_encode($this->toArray(), $options);
  34225. }
  34226. private static function getTokenKindsForNames(array $tokenNames)
  34227. {
  34228. $keywords = [];
  34229. foreach ($tokenNames as $keywordName) {
  34230. if (\defined($keywordName)) {
  34231. $keyword = \constant($keywordName);
  34232. $keywords[$keyword] = $keyword;
  34233. }
  34234. }
  34235. return $keywords;
  34236. }
  34237. }
  34238. <?php
  34239. namespace PhpCsFixer\Tokenizer\Resolver;
  34240. use PhpCsFixer\Preg;
  34241. use PhpCsFixer\Tokenizer\Analyzer\Analysis\NamespaceAnalysis;
  34242. use PhpCsFixer\Tokenizer\Analyzer\NamespacesAnalyzer;
  34243. use PhpCsFixer\Tokenizer\Analyzer\NamespaceUsesAnalyzer;
  34244. use PhpCsFixer\Tokenizer\Tokens;
  34245. final class TypeShortNameResolver
  34246. {
  34247. public function resolve(Tokens $tokens, $typeName)
  34248. {
  34249. $useMap = $this->getUseMapFromTokens($tokens);
  34250. foreach ($useMap as $shortName => $fullName) {
  34251. $regex = '/^\\\\?'.preg_quote($fullName, '/').'$/';
  34252. if (Preg::match($regex, $typeName)) {
  34253. return $shortName;
  34254. }
  34255. }
  34256. $namespaces = $this->getNamespacesFromTokens($tokens);
  34257. if (1 === \count($namespaces)) {
  34258. foreach ($namespaces as $fullName) {
  34259. $matches = [];
  34260. $regex = '/^\\\\?'.preg_quote($fullName, '/').'\\\\(?P<className>.+)$/';
  34261. if (Preg::match($regex, $typeName, $matches)) {
  34262. return $matches['className'];
  34263. }
  34264. }
  34265. }
  34266. foreach ($useMap as $shortName => $fullName) {
  34267. $matches = [];
  34268. $regex = '/^\\\\?'.preg_quote($fullName, '/').'\\\\(?P<className>.+)$/';
  34269. if (Preg::match($regex, $typeName, $matches)) {
  34270. return $shortName.'\\'.$matches['className'];
  34271. }
  34272. }
  34273. return $typeName;
  34274. }
  34275. private function getNamespacesFromTokens(Tokens $tokens)
  34276. {
  34277. return array_map(static function (NamespaceAnalysis $info) {
  34278. return $info->getFullName();
  34279. }, (new NamespacesAnalyzer())->getDeclarations($tokens));
  34280. }
  34281. private function getUseMapFromTokens(Tokens $tokens)
  34282. {
  34283. $map = [];
  34284. foreach ((new NamespaceUsesAnalyzer())->getDeclarationsFromTokens($tokens) as $useDeclaration) {
  34285. $map[$useDeclaration->getShortName()] = $useDeclaration->getFullName();
  34286. }
  34287. return $map;
  34288. }
  34289. }
  34290. <?php
  34291. namespace PhpCsFixer\Tokenizer;
  34292. interface TransformerInterface
  34293. {
  34294. public function getCustomTokens();
  34295. public function getName();
  34296. public function getPriority();
  34297. public function getRequiredPhpVersionId();
  34298. public function process(Tokens $tokens, Token $token, $index);
  34299. }
  34300. <?php
  34301. namespace PhpCsFixer\Tokenizer;
  34302. /**
  34303. @web
  34304. */
  34305. final class TokensAnalyzer
  34306. {
  34307. private $tokens;
  34308. public function __construct(Tokens $tokens)
  34309. {
  34310. $this->tokens = $tokens;
  34311. }
  34312. public function getClassyElements()
  34313. {
  34314. $this->tokens->rewind();
  34315. $elements = [];
  34316. for ($index = 1, $count = \count($this->tokens) - 2; $index < $count; ++$index) {
  34317. if ($this->tokens[$index]->isClassy()) {
  34318. list($index, $newElements) = $this->findClassyElements($index, $index);
  34319. $elements += $newElements;
  34320. }
  34321. }
  34322. ksort($elements);
  34323. return $elements;
  34324. }
  34325. public function getImportUseIndexes($perNamespace = false)
  34326. {
  34327. $tokens = $this->tokens;
  34328. $tokens->rewind();
  34329. $uses = [];
  34330. $namespaceIndex = 0;
  34331. for ($index = 0, $limit = $tokens->count(); $index < $limit; ++$index) {
  34332. $token = $tokens[$index];
  34333. if ($token->isGivenKind(T_NAMESPACE)) {
  34334. $nextTokenIndex = $tokens->getNextTokenOfKind($index, [';', '{']);
  34335. $nextToken = $tokens[$nextTokenIndex];
  34336. if ($nextToken->equals('{')) {
  34337. $index = $nextTokenIndex;
  34338. }
  34339. if ($perNamespace) {
  34340. ++$namespaceIndex;
  34341. }
  34342. continue;
  34343. }
  34344. if ($token->isGivenKind(T_USE)) {
  34345. $uses[$namespaceIndex][] = $index;
  34346. }
  34347. }
  34348. if (!$perNamespace && isset($uses[$namespaceIndex])) {
  34349. return $uses[$namespaceIndex];
  34350. }
  34351. return $uses;
  34352. }
  34353. public function isArray($index)
  34354. {
  34355. return $this->tokens[$index]->isGivenKind([T_ARRAY, CT::T_ARRAY_SQUARE_BRACE_OPEN]);
  34356. }
  34357. public function isArrayMultiLine($index)
  34358. {
  34359. if (!$this->isArray($index)) {
  34360. throw new \InvalidArgumentException(sprintf('Not an array at given index %d.', $index));
  34361. }
  34362. $tokens = $this->tokens;
  34363. if ($tokens[$index]->isGivenKind(T_ARRAY)) {
  34364. $index = $tokens->getNextMeaningfulToken($index);
  34365. }
  34366. $endIndex = $tokens[$index]->equals('(')
  34367. ? $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $index)
  34368. : $tokens->findBlockEnd(Tokens::BLOCK_TYPE_ARRAY_SQUARE_BRACE, $index)
  34369. ;
  34370. for (++$index; $index < $endIndex; ++$index) {
  34371. $token = $tokens[$index];
  34372. $blockType = Tokens::detectBlockType($token);
  34373. if ($blockType && $blockType['isStart']) {
  34374. $index = $tokens->findBlockEnd($blockType['type'], $index);
  34375. continue;
  34376. }
  34377. if (
  34378. $token->isWhitespace() &&
  34379. !$tokens[$index - 1]->isGivenKind(T_END_HEREDOC) &&
  34380. false !== strpos($token->getContent(), "\n")
  34381. ) {
  34382. return true;
  34383. }
  34384. }
  34385. return false;
  34386. }
  34387. public function getMethodAttributes($index)
  34388. {
  34389. $tokens = $this->tokens;
  34390. $token = $tokens[$index];
  34391. if (!$token->isGivenKind(T_FUNCTION)) {
  34392. throw new \LogicException(sprintf('No T_FUNCTION at given index %d, got %s.', $index, $token->getName()));
  34393. }
  34394. $attributes = [
  34395. 'visibility' => null,
  34396. 'static' => false,
  34397. 'abstract' => false,
  34398. 'final' => false,
  34399. ];
  34400. for ($i = $index; $i >= 0; --$i) {
  34401. $tokenIndex = $tokens->getPrevMeaningfulToken($i);
  34402. $i = $tokenIndex;
  34403. $token = $tokens[$tokenIndex];
  34404. if ($token->isGivenKind(T_STATIC)) {
  34405. $attributes['static'] = true;
  34406. continue;
  34407. }
  34408. if ($token->isGivenKind(T_FINAL)) {
  34409. $attributes['final'] = true;
  34410. continue;
  34411. }
  34412. if ($token->isGivenKind(T_ABSTRACT)) {
  34413. $attributes['abstract'] = true;
  34414. continue;
  34415. }
  34416. if ($token->isGivenKind(T_PRIVATE)) {
  34417. $attributes['visibility'] = T_PRIVATE;
  34418. continue;
  34419. }
  34420. if ($token->isGivenKind(T_PROTECTED)) {
  34421. $attributes['visibility'] = T_PROTECTED;
  34422. continue;
  34423. }
  34424. if ($token->isGivenKind(T_PUBLIC)) {
  34425. $attributes['visibility'] = T_PUBLIC;
  34426. continue;
  34427. }
  34428. break;
  34429. }
  34430. return $attributes;
  34431. }
  34432. public function isAnonymousClass($index)
  34433. {
  34434. $tokens = $this->tokens;
  34435. $token = $tokens[$index];
  34436. if (!$token->isClassy()) {
  34437. throw new \LogicException(sprintf('No classy token at given index %d.', $index));
  34438. }
  34439. if (!$token->isGivenKind(T_CLASS)) {
  34440. return false;
  34441. }
  34442. return $tokens[$tokens->getPrevMeaningfulToken($index)]->isGivenKind(T_NEW);
  34443. }
  34444. public function isLambda($index)
  34445. {
  34446. if (
  34447. !$this->tokens[$index]->isGivenKind(T_FUNCTION)
  34448. && (\PHP_VERSION_ID < 70400 || !$this->tokens[$index]->isGivenKind(T_FN))
  34449. ) {
  34450. throw new \LogicException(sprintf('No T_FUNCTION or T_FN at given index %d, got %s.', $index, $this->tokens[$index]->getName()));
  34451. }
  34452. $startParenthesisIndex = $this->tokens->getNextMeaningfulToken($index);
  34453. $startParenthesisToken = $this->tokens[$startParenthesisIndex];
  34454. if ($startParenthesisToken->isGivenKind(CT::T_RETURN_REF)) {
  34455. $startParenthesisIndex = $this->tokens->getNextMeaningfulToken($startParenthesisIndex);
  34456. $startParenthesisToken = $this->tokens[$startParenthesisIndex];
  34457. }
  34458. return $startParenthesisToken->equals('(');
  34459. }
  34460. public function isConstantInvocation($index)
  34461. {
  34462. if (!$this->tokens[$index]->isGivenKind(T_STRING)) {
  34463. throw new \LogicException(sprintf('No T_STRING at given index %d, got %s.', $index, $this->tokens[$index]->getName()));
  34464. }
  34465. $nextIndex = $this->tokens->getNextMeaningfulToken($index);
  34466. if (
  34467. $this->tokens[$nextIndex]->equalsAny(['(', '{']) ||
  34468. $this->tokens[$nextIndex]->isGivenKind([T_AS, T_DOUBLE_COLON, T_ELLIPSIS, T_NS_SEPARATOR, CT::T_RETURN_REF, CT::T_TYPE_ALTERNATION, T_VARIABLE])
  34469. ) {
  34470. return false;
  34471. }
  34472. $prevIndex = $this->tokens->getPrevMeaningfulToken($index);
  34473. if ($this->tokens[$prevIndex]->isGivenKind([T_AS, T_CLASS, T_CONST, T_DOUBLE_COLON, T_FUNCTION, T_GOTO, CT::T_GROUP_IMPORT_BRACE_OPEN, T_INTERFACE, T_OBJECT_OPERATOR, T_TRAIT, CT::T_TYPE_COLON])) {
  34474. return false;
  34475. }
  34476. while ($this->tokens[$prevIndex]->isGivenKind([CT::T_NAMESPACE_OPERATOR, T_NS_SEPARATOR, T_STRING])) {
  34477. $prevIndex = $this->tokens->getPrevMeaningfulToken($prevIndex);
  34478. }
  34479. 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])) {
  34480. return false;
  34481. }
  34482. if ($this->tokens[$nextIndex]->equals('&') && $this->tokens[$this->tokens->getNextMeaningfulToken($nextIndex)]->isGivenKind(T_VARIABLE)) {
  34483. $checkIndex = $this->tokens->getPrevTokenOfKind($prevIndex, [';', '{', '}', [T_FUNCTION], [T_OPEN_TAG], [T_OPEN_TAG_WITH_ECHO]]);
  34484. if ($this->tokens[$checkIndex]->isGivenKind(T_FUNCTION)) {
  34485. return false;
  34486. }
  34487. }
  34488. if ($this->tokens[$prevIndex]->equals(',')) {
  34489. $checkIndex = $prevIndex;
  34490. while ($this->tokens[$checkIndex]->equalsAny([',', [T_AS], [CT::T_NAMESPACE_OPERATOR], [T_NS_SEPARATOR], [T_STRING]])) {
  34491. $checkIndex = $this->tokens->getPrevMeaningfulToken($checkIndex);
  34492. }
  34493. if ($this->tokens[$checkIndex]->isGivenKind([T_EXTENDS, CT::T_GROUP_IMPORT_BRACE_OPEN, T_IMPLEMENTS, T_USE, CT::T_USE_TRAIT])) {
  34494. return false;
  34495. }
  34496. }
  34497. if ($this->tokens[$prevIndex]->equals('[') && $this->tokens[$nextIndex]->equals(']')) {
  34498. $checkToken = $this->tokens[$this->tokens->getNextMeaningfulToken($nextIndex)];
  34499. if ($checkToken->equals('"') || $checkToken->isGivenKind([T_CURLY_OPEN, T_DOLLAR_OPEN_CURLY_BRACES, T_ENCAPSED_AND_WHITESPACE, T_VARIABLE])) {
  34500. return false;
  34501. }
  34502. }
  34503. if ($this->tokens[$nextIndex]->equals(':') && $this->tokens[$prevIndex]->equalsAny([';', '}', [T_OPEN_TAG], [T_OPEN_TAG_WITH_ECHO]])) {
  34504. return false;
  34505. }
  34506. return true;
  34507. }
  34508. public function isUnarySuccessorOperator($index)
  34509. {
  34510. static $allowedPrevToken = [
  34511. ']',
  34512. [T_STRING],
  34513. [T_VARIABLE],
  34514. [CT::T_ARRAY_INDEX_CURLY_BRACE_CLOSE],
  34515. [CT::T_DYNAMIC_PROP_BRACE_CLOSE],
  34516. [CT::T_DYNAMIC_VAR_BRACE_CLOSE],
  34517. ];
  34518. $tokens = $this->tokens;
  34519. $token = $tokens[$index];
  34520. if (!$token->isGivenKind([T_INC, T_DEC])) {
  34521. return false;
  34522. }
  34523. $prevToken = $tokens[$tokens->getPrevMeaningfulToken($index)];
  34524. return $prevToken->equalsAny($allowedPrevToken);
  34525. }
  34526. public function isUnaryPredecessorOperator($index)
  34527. {
  34528. static $potentialSuccessorOperator = [T_INC, T_DEC];
  34529. static $potentialBinaryOperator = ['+', '-', '&', [CT::T_RETURN_REF]];
  34530. static $otherOperators;
  34531. if (null === $otherOperators) {
  34532. $otherOperators = ['!', '~', '@', [T_ELLIPSIS]];
  34533. }
  34534. static $disallowedPrevTokens;
  34535. if (null === $disallowedPrevTokens) {
  34536. $disallowedPrevTokens = [
  34537. ']',
  34538. '}',
  34539. ')',
  34540. '"',
  34541. '`',
  34542. [CT::T_ARRAY_SQUARE_BRACE_CLOSE],
  34543. [CT::T_ARRAY_INDEX_CURLY_BRACE_CLOSE],
  34544. [CT::T_DYNAMIC_PROP_BRACE_CLOSE],
  34545. [CT::T_DYNAMIC_VAR_BRACE_CLOSE],
  34546. [T_CLASS_C],
  34547. [T_CONSTANT_ENCAPSED_STRING],
  34548. [T_DEC],
  34549. [T_DIR],
  34550. [T_DNUMBER],
  34551. [T_FILE],
  34552. [T_FUNC_C],
  34553. [T_INC],
  34554. [T_LINE],
  34555. [T_LNUMBER],
  34556. [T_METHOD_C],
  34557. [T_NS_C],
  34558. [T_STRING],
  34559. [T_TRAIT_C],
  34560. [T_VARIABLE],
  34561. ];
  34562. }
  34563. $tokens = $this->tokens;
  34564. $token = $tokens[$index];
  34565. if ($token->isGivenKind($potentialSuccessorOperator)) {
  34566. return !$this->isUnarySuccessorOperator($index);
  34567. }
  34568. if ($token->equalsAny($otherOperators)) {
  34569. return true;
  34570. }
  34571. if (!$token->equalsAny($potentialBinaryOperator)) {
  34572. return false;
  34573. }
  34574. $prevToken = $tokens[$tokens->getPrevMeaningfulToken($index)];
  34575. if (!$prevToken->equalsAny($disallowedPrevTokens)) {
  34576. return true;
  34577. }
  34578. if (!$token->equals('&') || !$prevToken->isGivenKind(T_STRING)) {
  34579. return false;
  34580. }
  34581. static $searchTokens = [
  34582. ';',
  34583. '{',
  34584. '}',
  34585. [T_FUNCTION],
  34586. [T_OPEN_TAG],
  34587. [T_OPEN_TAG_WITH_ECHO],
  34588. ];
  34589. $prevToken = $tokens[$tokens->getPrevTokenOfKind($index, $searchTokens)];
  34590. return $prevToken->isGivenKind(T_FUNCTION);
  34591. }
  34592. public function isBinaryOperator($index)
  34593. {
  34594. static $nonArrayOperators = [
  34595. '=' => true,
  34596. '*' => true,
  34597. '/' => true,
  34598. '%' => true,
  34599. '<' => true,
  34600. '>' => true,
  34601. '|' => true,
  34602. '^' => true,
  34603. '.' => true,
  34604. ];
  34605. static $potentialUnaryNonArrayOperators = [
  34606. '+' => true,
  34607. '-' => true,
  34608. '&' => true,
  34609. ];
  34610. static $arrayOperators;
  34611. if (null === $arrayOperators) {
  34612. $arrayOperators = [
  34613. T_AND_EQUAL => true,
  34614. T_BOOLEAN_AND => true,
  34615. T_BOOLEAN_OR => true,
  34616. T_CONCAT_EQUAL => true,
  34617. T_DIV_EQUAL => true,
  34618. T_DOUBLE_ARROW => true,
  34619. T_IS_EQUAL => true,
  34620. T_IS_GREATER_OR_EQUAL => true,
  34621. T_IS_IDENTICAL => true,
  34622. T_IS_NOT_EQUAL => true,
  34623. T_IS_NOT_IDENTICAL => true,
  34624. T_IS_SMALLER_OR_EQUAL => true,
  34625. T_LOGICAL_AND => true,
  34626. T_LOGICAL_OR => true,
  34627. T_LOGICAL_XOR => true,
  34628. T_MINUS_EQUAL => true,
  34629. T_MOD_EQUAL => true,
  34630. T_MUL_EQUAL => true,
  34631. T_OR_EQUAL => true,
  34632. T_PLUS_EQUAL => true,
  34633. T_POW => true,
  34634. T_POW_EQUAL => true,
  34635. T_SL => true,
  34636. T_SL_EQUAL => true,
  34637. T_SR => true,
  34638. T_SR_EQUAL => true,
  34639. T_XOR_EQUAL => true,
  34640. CT::T_TYPE_ALTERNATION => true,
  34641. ];
  34642. if (\defined('T_SPACESHIP')) {
  34643. $arrayOperators[T_SPACESHIP] = true;
  34644. }
  34645. if (\defined('T_COALESCE')) {
  34646. $arrayOperators[T_COALESCE] = true;
  34647. }
  34648. if (\defined('T_COALESCE_EQUAL')) {
  34649. $arrayOperators[T_COALESCE_EQUAL] = true;
  34650. }
  34651. }
  34652. $tokens = $this->tokens;
  34653. $token = $tokens[$index];
  34654. if ($token->isArray()) {
  34655. return isset($arrayOperators[$token->getId()]);
  34656. }
  34657. if (isset($nonArrayOperators[$token->getContent()])) {
  34658. return true;
  34659. }
  34660. if (isset($potentialUnaryNonArrayOperators[$token->getContent()])) {
  34661. return !$this->isUnaryPredecessorOperator($index);
  34662. }
  34663. return false;
  34664. }
  34665. public function isWhilePartOfDoWhile($index)
  34666. {
  34667. $tokens = $this->tokens;
  34668. $token = $tokens[$index];
  34669. if (!$token->isGivenKind(T_WHILE)) {
  34670. throw new \LogicException(sprintf('No T_WHILE at given index %d, got %s.', $index, $token->getName()));
  34671. }
  34672. $endIndex = $tokens->getPrevMeaningfulToken($index);
  34673. if (!$tokens[$endIndex]->equals('}')) {
  34674. return false;
  34675. }
  34676. $startIndex = $tokens->findBlockStart(Tokens::BLOCK_TYPE_CURLY_BRACE, $endIndex);
  34677. $beforeStartIndex = $tokens->getPrevMeaningfulToken($startIndex);
  34678. return $tokens[$beforeStartIndex]->isGivenKind(T_DO);
  34679. }
  34680. private function findClassyElements($classIndex, $index)
  34681. {
  34682. $elements = [];
  34683. $curlyBracesLevel = 0;
  34684. $bracesLevel = 0;
  34685. ++$index;
  34686. for ($count = \count($this->tokens); $index < $count; ++$index) {
  34687. $token = $this->tokens[$index];
  34688. if ($token->isGivenKind(T_ENCAPSED_AND_WHITESPACE)) {
  34689. continue;
  34690. }
  34691. if ($token->isClassy()) {
  34692. $nestedClassIndex = $index;
  34693. $index = $this->tokens->getNextMeaningfulToken($index);
  34694. if ($this->tokens[$index]->equals('(')) {
  34695. ++$index;
  34696. for ($nestedBracesLevel = 1; $index < $count; ++$index) {
  34697. $token = $this->tokens[$index];
  34698. if ($token->equals('(')) {
  34699. ++$nestedBracesLevel;
  34700. continue;
  34701. }
  34702. if ($token->equals(')')) {
  34703. --$nestedBracesLevel;
  34704. if (0 === $nestedBracesLevel) {
  34705. list($index, $newElements) = $this->findClassyElements($nestedClassIndex, $index);
  34706. $elements += $newElements;
  34707. break;
  34708. }
  34709. continue;
  34710. }
  34711. if ($token->isClassy()) {
  34712. list($index, $newElements) = $this->findClassyElements($index, $index);
  34713. $elements += $newElements;
  34714. }
  34715. }
  34716. } else {
  34717. list($index, $newElements) = $this->findClassyElements($nestedClassIndex, $nestedClassIndex);
  34718. $elements += $newElements;
  34719. }
  34720. continue;
  34721. }
  34722. if ($token->equals('(')) {
  34723. ++$bracesLevel;
  34724. continue;
  34725. }
  34726. if ($token->equals(')')) {
  34727. --$bracesLevel;
  34728. continue;
  34729. }
  34730. if ($token->equals('{')) {
  34731. ++$curlyBracesLevel;
  34732. continue;
  34733. }
  34734. if ($token->equals('}')) {
  34735. --$curlyBracesLevel;
  34736. if (0 === $curlyBracesLevel) {
  34737. break;
  34738. }
  34739. continue;
  34740. }
  34741. if (1 !== $curlyBracesLevel || !$token->isArray()) {
  34742. continue;
  34743. }
  34744. if (0 === $bracesLevel && $token->isGivenKind(T_VARIABLE)) {
  34745. $elements[$index] = [
  34746. 'token' => $token,
  34747. 'type' => 'property',
  34748. 'classIndex' => $classIndex,
  34749. ];
  34750. continue;
  34751. }
  34752. if ($token->isGivenKind(T_FUNCTION)) {
  34753. $elements[$index] = [
  34754. 'token' => $token,
  34755. 'type' => 'method',
  34756. 'classIndex' => $classIndex,
  34757. ];
  34758. } elseif ($token->isGivenKind(T_CONST)) {
  34759. $elements[$index] = [
  34760. 'token' => $token,
  34761. 'type' => 'const',
  34762. 'classIndex' => $classIndex,
  34763. ];
  34764. }
  34765. }
  34766. return [$index, $elements];
  34767. }
  34768. }
  34769. <?php
  34770. namespace PhpCsFixer\Tokenizer\Generator;
  34771. use PhpCsFixer\Tokenizer\Token;
  34772. final class NamespacedStringTokenGenerator
  34773. {
  34774. public function generate($input)
  34775. {
  34776. $tokens = [];
  34777. $parts = explode('\\', $input);
  34778. foreach ($parts as $index => $part) {
  34779. $tokens[] = new Token([T_STRING, $part]);
  34780. if ($index !== \count($parts) - 1) {
  34781. $tokens[] = new Token([T_NS_SEPARATOR, '\\']);
  34782. }
  34783. }
  34784. return $tokens;
  34785. }
  34786. }
  34787. <?php
  34788. namespace PhpCsFixer\Tokenizer;
  34789. final class CodeHasher
  34790. {
  34791. private function __construct()
  34792. {
  34793. }
  34794. public static function calculateCodeHash($code)
  34795. {
  34796. return (string) crc32($code);
  34797. }
  34798. }
  34799. <?php
  34800. namespace PhpCsFixer\Tokenizer\Transformer;
  34801. use PhpCsFixer\Tokenizer\AbstractTransformer;
  34802. use PhpCsFixer\Tokenizer\Token;
  34803. use PhpCsFixer\Tokenizer\Tokens;
  34804. final class WhitespacyCommentTransformer extends AbstractTransformer
  34805. {
  34806. public function getCustomTokens()
  34807. {
  34808. return [];
  34809. }
  34810. public function getRequiredPhpVersionId()
  34811. {
  34812. return 50000;
  34813. }
  34814. public function process(Tokens $tokens, Token $token, $index)
  34815. {
  34816. if (!$token->isComment()) {
  34817. return;
  34818. }
  34819. $content = $token->getContent();
  34820. $trimmedContent = rtrim($content);
  34821. if ($content === $trimmedContent) {
  34822. return;
  34823. }
  34824. $whitespaces = substr($content, \strlen($trimmedContent));
  34825. $tokens[$index] = new Token([$token->getId(), $trimmedContent]);
  34826. if (isset($tokens[$index + 1]) && $tokens[$index + 1]->isWhitespace()) {
  34827. $tokens[$index + 1] = new Token([T_WHITESPACE, $whitespaces.$tokens[$index + 1]->getContent()]);
  34828. } else {
  34829. $tokens->insertAt($index + 1, new Token([T_WHITESPACE, $whitespaces]));
  34830. }
  34831. }
  34832. }
  34833. <?php
  34834. namespace PhpCsFixer\Tokenizer\Transformer;
  34835. use PhpCsFixer\Tokenizer\AbstractTransformer;
  34836. use PhpCsFixer\Tokenizer\CT;
  34837. use PhpCsFixer\Tokenizer\Token;
  34838. use PhpCsFixer\Tokenizer\Tokens;
  34839. final class NullableTypeTransformer extends AbstractTransformer
  34840. {
  34841. public function getCustomTokens()
  34842. {
  34843. return [CT::T_NULLABLE_TYPE];
  34844. }
  34845. public function getPriority()
  34846. {
  34847. return -20;
  34848. }
  34849. public function getRequiredPhpVersionId()
  34850. {
  34851. return 70100;
  34852. }
  34853. public function process(Tokens $tokens, Token $token, $index)
  34854. {
  34855. if (!$token->equals('?')) {
  34856. return;
  34857. }
  34858. $prevIndex = $tokens->getPrevMeaningfulToken($index);
  34859. $prevToken = $tokens[$prevIndex];
  34860. if ($prevToken->equalsAny(['(', ',', [CT::T_TYPE_COLON], [T_PRIVATE], [T_PROTECTED], [T_PUBLIC], [T_VAR], [T_STATIC]])) {
  34861. $tokens[$index] = new Token([CT::T_NULLABLE_TYPE, '?']);
  34862. }
  34863. }
  34864. }
  34865. <?php
  34866. namespace PhpCsFixer\Tokenizer\Transformer;
  34867. use PhpCsFixer\Tokenizer\AbstractTransformer;
  34868. use PhpCsFixer\Tokenizer\CT;
  34869. use PhpCsFixer\Tokenizer\Token;
  34870. use PhpCsFixer\Tokenizer\Tokens;
  34871. final class CurlyBraceTransformer extends AbstractTransformer
  34872. {
  34873. public function getCustomTokens()
  34874. {
  34875. return [
  34876. CT::T_CURLY_CLOSE,
  34877. CT::T_DOLLAR_CLOSE_CURLY_BRACES,
  34878. CT::T_DYNAMIC_PROP_BRACE_OPEN,
  34879. CT::T_DYNAMIC_PROP_BRACE_CLOSE,
  34880. CT::T_DYNAMIC_VAR_BRACE_OPEN,
  34881. CT::T_DYNAMIC_VAR_BRACE_CLOSE,
  34882. CT::T_ARRAY_INDEX_CURLY_BRACE_OPEN,
  34883. CT::T_ARRAY_INDEX_CURLY_BRACE_CLOSE,
  34884. CT::T_GROUP_IMPORT_BRACE_OPEN,
  34885. CT::T_GROUP_IMPORT_BRACE_CLOSE,
  34886. ];
  34887. }
  34888. public function getRequiredPhpVersionId()
  34889. {
  34890. return 50000;
  34891. }
  34892. public function process(Tokens $tokens, Token $token, $index)
  34893. {
  34894. $this->transformIntoCurlyCloseBrace($tokens, $token, $index);
  34895. $this->transformIntoDollarCloseBrace($tokens, $token, $index);
  34896. $this->transformIntoDynamicPropBraces($tokens, $token, $index);
  34897. $this->transformIntoDynamicVarBraces($tokens, $token, $index);
  34898. $this->transformIntoCurlyIndexBraces($tokens, $token, $index);
  34899. if (\PHP_VERSION_ID >= 70000) {
  34900. $this->transformIntoGroupUseBraces($tokens, $token, $index);
  34901. }
  34902. }
  34903. private function transformIntoCurlyCloseBrace(Tokens $tokens, Token $token, $index)
  34904. {
  34905. if (!$token->isGivenKind(T_CURLY_OPEN)) {
  34906. return;
  34907. }
  34908. $level = 1;
  34909. $nestIndex = $index;
  34910. while (0 < $level) {
  34911. ++$nestIndex;
  34912. if ($tokens[$nestIndex]->equals('{')) {
  34913. ++$level;
  34914. continue;
  34915. }
  34916. if ($tokens[$nestIndex]->equals('}')) {
  34917. --$level;
  34918. }
  34919. }
  34920. $tokens[$nestIndex] = new Token([CT::T_CURLY_CLOSE, '}']);
  34921. }
  34922. private function transformIntoDollarCloseBrace(Tokens $tokens, Token $token, $index)
  34923. {
  34924. if ($token->isGivenKind(T_DOLLAR_OPEN_CURLY_BRACES)) {
  34925. $nextIndex = $tokens->getNextTokenOfKind($index, ['}']);
  34926. $tokens[$nextIndex] = new Token([CT::T_DOLLAR_CLOSE_CURLY_BRACES, '}']);
  34927. }
  34928. }
  34929. private function transformIntoDynamicPropBraces(Tokens $tokens, Token $token, $index)
  34930. {
  34931. if (!$token->isGivenKind(T_OBJECT_OPERATOR)) {
  34932. return;
  34933. }
  34934. if (!$tokens[$index + 1]->equals('{')) {
  34935. return;
  34936. }
  34937. $openIndex = $index + 1;
  34938. $closeIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $openIndex);
  34939. $tokens[$openIndex] = new Token([CT::T_DYNAMIC_PROP_BRACE_OPEN, '{']);
  34940. $tokens[$closeIndex] = new Token([CT::T_DYNAMIC_PROP_BRACE_CLOSE, '}']);
  34941. }
  34942. private function transformIntoDynamicVarBraces(Tokens $tokens, Token $token, $index)
  34943. {
  34944. if (!$token->equals('$')) {
  34945. return;
  34946. }
  34947. $openIndex = $tokens->getNextMeaningfulToken($index);
  34948. if (null === $openIndex) {
  34949. return;
  34950. }
  34951. $openToken = $tokens[$openIndex];
  34952. if (!$openToken->equals('{')) {
  34953. return;
  34954. }
  34955. $closeIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $openIndex);
  34956. $tokens[$openIndex] = new Token([CT::T_DYNAMIC_VAR_BRACE_OPEN, '{']);
  34957. $tokens[$closeIndex] = new Token([CT::T_DYNAMIC_VAR_BRACE_CLOSE, '}']);
  34958. }
  34959. private function transformIntoCurlyIndexBraces(Tokens $tokens, Token $token, $index)
  34960. {
  34961. if (!$token->equals('{')) {
  34962. return;
  34963. }
  34964. $prevIndex = $tokens->getPrevMeaningfulToken($index);
  34965. if (!$tokens[$prevIndex]->equalsAny([
  34966. [T_STRING],
  34967. [T_VARIABLE],
  34968. [CT::T_ARRAY_INDEX_CURLY_BRACE_CLOSE],
  34969. ']',
  34970. ')',
  34971. ])) {
  34972. return;
  34973. }
  34974. if (
  34975. $tokens[$prevIndex]->isGivenKind(T_STRING)
  34976. && !$tokens[$tokens->getPrevMeaningfulToken($prevIndex)]->isGivenKind(T_OBJECT_OPERATOR)
  34977. ) {
  34978. return;
  34979. }
  34980. if (
  34981. $tokens[$prevIndex]->equals(')')
  34982. && !$tokens[$tokens->getPrevMeaningfulToken(
  34983. $tokens->findBlockStart(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $prevIndex)
  34984. )]->isGivenKind(T_ARRAY)
  34985. ) {
  34986. return;
  34987. }
  34988. $closeIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $index);
  34989. $tokens[$index] = new Token([CT::T_ARRAY_INDEX_CURLY_BRACE_OPEN, '{']);
  34990. $tokens[$closeIndex] = new Token([CT::T_ARRAY_INDEX_CURLY_BRACE_CLOSE, '}']);
  34991. }
  34992. private function transformIntoGroupUseBraces(Tokens $tokens, Token $token, $index)
  34993. {
  34994. if (!$token->equals('{')) {
  34995. return;
  34996. }
  34997. $prevIndex = $tokens->getPrevMeaningfulToken($index);
  34998. if (!$tokens[$prevIndex]->isGivenKind(T_NS_SEPARATOR)) {
  34999. return;
  35000. }
  35001. $closeIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $index);
  35002. $tokens[$index] = new Token([CT::T_GROUP_IMPORT_BRACE_OPEN, '{']);
  35003. $tokens[$closeIndex] = new Token([CT::T_GROUP_IMPORT_BRACE_CLOSE, '}']);
  35004. }
  35005. }
  35006. <?php
  35007. namespace PhpCsFixer\Tokenizer\Transformer;
  35008. use PhpCsFixer\Tokenizer\AbstractTransformer;
  35009. use PhpCsFixer\Tokenizer\CT;
  35010. use PhpCsFixer\Tokenizer\Token;
  35011. use PhpCsFixer\Tokenizer\Tokens;
  35012. final class UseTransformer extends AbstractTransformer
  35013. {
  35014. public function getCustomTokens()
  35015. {
  35016. return [CT::T_USE_TRAIT, CT::T_USE_LAMBDA];
  35017. }
  35018. public function getPriority()
  35019. {
  35020. return -5;
  35021. }
  35022. public function getRequiredPhpVersionId()
  35023. {
  35024. return 50300;
  35025. }
  35026. public function process(Tokens $tokens, Token $token, $index)
  35027. {
  35028. if ($token->isGivenKind(T_USE) && $this->isUseForLambda($tokens, $index)) {
  35029. $tokens[$index] = new Token([CT::T_USE_LAMBDA, $token->getContent()]);
  35030. return;
  35031. }
  35032. if (!$token->isGivenKind([T_CLASS, T_TRAIT])) {
  35033. return;
  35034. }
  35035. if ($tokens[$tokens->getPrevMeaningfulToken($index)]->isGivenKind(T_DOUBLE_COLON)) {
  35036. return;
  35037. }
  35038. $index = $tokens->getNextTokenOfKind($index, ['{']);
  35039. $innerLimit = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $index);
  35040. while ($index < $innerLimit) {
  35041. $token = $tokens[++$index];
  35042. if (!$token->isGivenKind(T_USE)) {
  35043. continue;
  35044. }
  35045. if ($this->isUseForLambda($tokens, $index)) {
  35046. $tokens[$index] = new Token([CT::T_USE_LAMBDA, $token->getContent()]);
  35047. } else {
  35048. $tokens[$index] = new Token([CT::T_USE_TRAIT, $token->getContent()]);
  35049. }
  35050. }
  35051. }
  35052. private function isUseForLambda(Tokens $tokens, $index)
  35053. {
  35054. $nextToken = $tokens[$tokens->getNextMeaningfulToken($index)];
  35055. return $nextToken->equals('(');
  35056. }
  35057. }
  35058. <?php
  35059. namespace PhpCsFixer\Tokenizer\Transformer;
  35060. use PhpCsFixer\Tokenizer\AbstractTransformer;
  35061. use PhpCsFixer\Tokenizer\CT;
  35062. use PhpCsFixer\Tokenizer\Token;
  35063. use PhpCsFixer\Tokenizer\Tokens;
  35064. final class ClassConstantTransformer extends AbstractTransformer
  35065. {
  35066. public function getCustomTokens()
  35067. {
  35068. return [CT::T_CLASS_CONSTANT];
  35069. }
  35070. public function getRequiredPhpVersionId()
  35071. {
  35072. return 50500;
  35073. }
  35074. public function process(Tokens $tokens, Token $token, $index)
  35075. {
  35076. if (!$token->equalsAny([
  35077. [T_CLASS, 'class'],
  35078. [T_STRING, 'class'],
  35079. ], false)) {
  35080. return;
  35081. }
  35082. $prevIndex = $tokens->getPrevMeaningfulToken($index);
  35083. $prevToken = $tokens[$prevIndex];
  35084. if ($prevToken->isGivenKind(T_DOUBLE_COLON)) {
  35085. $tokens[$index] = new Token([CT::T_CLASS_CONSTANT, $token->getContent()]);
  35086. }
  35087. }
  35088. }
  35089. <?php
  35090. namespace PhpCsFixer\Tokenizer\Transformer;
  35091. use PhpCsFixer\Tokenizer\AbstractTransformer;
  35092. use PhpCsFixer\Tokenizer\CT;
  35093. use PhpCsFixer\Tokenizer\Token;
  35094. use PhpCsFixer\Tokenizer\Tokens;
  35095. final class ArrayTypehintTransformer extends AbstractTransformer
  35096. {
  35097. public function getCustomTokens()
  35098. {
  35099. return [CT::T_ARRAY_TYPEHINT];
  35100. }
  35101. public function getRequiredPhpVersionId()
  35102. {
  35103. return 50000;
  35104. }
  35105. public function process(Tokens $tokens, Token $token, $index)
  35106. {
  35107. if (!$token->isGivenKind(T_ARRAY)) {
  35108. return;
  35109. }
  35110. $nextIndex = $tokens->getNextMeaningfulToken($index);
  35111. $nextToken = $tokens[$nextIndex];
  35112. if (!$nextToken->equals('(')) {
  35113. $tokens[$index] = new Token([CT::T_ARRAY_TYPEHINT, $token->getContent()]);
  35114. }
  35115. }
  35116. }
  35117. <?php
  35118. namespace PhpCsFixer\Tokenizer\Transformer;
  35119. use PhpCsFixer\Tokenizer\AbstractTransformer;
  35120. use PhpCsFixer\Tokenizer\CT;
  35121. use PhpCsFixer\Tokenizer\Token;
  35122. use PhpCsFixer\Tokenizer\Tokens;
  35123. final class NamespaceOperatorTransformer extends AbstractTransformer
  35124. {
  35125. public function getCustomTokens()
  35126. {
  35127. return [CT::T_NAMESPACE_OPERATOR];
  35128. }
  35129. public function getRequiredPhpVersionId()
  35130. {
  35131. return 50300;
  35132. }
  35133. public function process(Tokens $tokens, Token $token, $index)
  35134. {
  35135. if (!$token->isGivenKind(T_NAMESPACE)) {
  35136. return;
  35137. }
  35138. $nextIndex = $tokens->getNextMeaningfulToken($index);
  35139. $nextToken = $tokens[$nextIndex];
  35140. if ($nextToken->isGivenKind(T_NS_SEPARATOR)) {
  35141. $tokens[$index] = new Token([CT::T_NAMESPACE_OPERATOR, $token->getContent()]);
  35142. }
  35143. }
  35144. }
  35145. <?php
  35146. namespace PhpCsFixer\Tokenizer\Transformer;
  35147. use PhpCsFixer\Tokenizer\AbstractTransformer;
  35148. use PhpCsFixer\Tokenizer\CT;
  35149. use PhpCsFixer\Tokenizer\Token;
  35150. use PhpCsFixer\Tokenizer\Tokens;
  35151. final class ImportTransformer extends AbstractTransformer
  35152. {
  35153. public function getCustomTokens()
  35154. {
  35155. return [CT::T_CONST_IMPORT, CT::T_FUNCTION_IMPORT];
  35156. }
  35157. public function getRequiredPhpVersionId()
  35158. {
  35159. return 50600;
  35160. }
  35161. public function process(Tokens $tokens, Token $token, $index)
  35162. {
  35163. if (!$token->isGivenKind([T_CONST, T_FUNCTION])) {
  35164. return;
  35165. }
  35166. $prevToken = $tokens[$tokens->getPrevMeaningfulToken($index)];
  35167. if ($prevToken->isGivenKind(T_USE)) {
  35168. $tokens[$index] = new Token([
  35169. $token->isGivenKind(T_FUNCTION) ? CT::T_FUNCTION_IMPORT : CT::T_CONST_IMPORT,
  35170. $token->getContent(),
  35171. ]);
  35172. }
  35173. }
  35174. }
  35175. <?php
  35176. namespace PhpCsFixer\Tokenizer\Transformer;
  35177. use PhpCsFixer\Tokenizer\AbstractTransformer;
  35178. use PhpCsFixer\Tokenizer\CT;
  35179. use PhpCsFixer\Tokenizer\Token;
  35180. use PhpCsFixer\Tokenizer\Tokens;
  35181. final class TypeColonTransformer extends AbstractTransformer
  35182. {
  35183. public function getCustomTokens()
  35184. {
  35185. return [CT::T_TYPE_COLON];
  35186. }
  35187. public function getPriority()
  35188. {
  35189. return -10;
  35190. }
  35191. public function getRequiredPhpVersionId()
  35192. {
  35193. return 70000;
  35194. }
  35195. public function process(Tokens $tokens, Token $token, $index)
  35196. {
  35197. if (!$token->equals(':')) {
  35198. return;
  35199. }
  35200. $endIndex = $tokens->getPrevMeaningfulToken($index);
  35201. if (!$tokens[$endIndex]->equals(')')) {
  35202. return;
  35203. }
  35204. $startIndex = $tokens->findBlockStart(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $endIndex);
  35205. $prevIndex = $tokens->getPrevMeaningfulToken($startIndex);
  35206. $prevToken = $tokens[$prevIndex];
  35207. if ($prevToken->isGivenKind(T_STRING)) {
  35208. $prevIndex = $tokens->getPrevMeaningfulToken($prevIndex);
  35209. $prevToken = $tokens[$prevIndex];
  35210. }
  35211. $prevKinds = [T_FUNCTION, CT::T_RETURN_REF, CT::T_USE_LAMBDA];
  35212. if (\PHP_VERSION_ID >= 70400) {
  35213. $prevKinds[] = T_FN;
  35214. }
  35215. if ($prevToken->isGivenKind($prevKinds)) {
  35216. $tokens[$index] = new Token([CT::T_TYPE_COLON, ':']);
  35217. }
  35218. }
  35219. }
  35220. <?php
  35221. namespace PhpCsFixer\Tokenizer\Transformer;
  35222. use PhpCsFixer\Tokenizer\AbstractTransformer;
  35223. use PhpCsFixer\Tokenizer\CT;
  35224. use PhpCsFixer\Tokenizer\Token;
  35225. use PhpCsFixer\Tokenizer\Tokens;
  35226. final class BraceClassInstantiationTransformer extends AbstractTransformer
  35227. {
  35228. public function getCustomTokens()
  35229. {
  35230. return [CT::T_BRACE_CLASS_INSTANTIATION_OPEN, CT::T_BRACE_CLASS_INSTANTIATION_CLOSE];
  35231. }
  35232. public function getPriority()
  35233. {
  35234. return -2;
  35235. }
  35236. public function getRequiredPhpVersionId()
  35237. {
  35238. return 50000;
  35239. }
  35240. public function process(Tokens $tokens, Token $token, $index)
  35241. {
  35242. if (!$tokens[$index]->equals('(') || !$tokens[$tokens->getNextMeaningfulToken($index)]->equals([T_NEW])) {
  35243. return;
  35244. }
  35245. if ($tokens[$tokens->getPrevMeaningfulToken($index)]->equalsAny([
  35246. ']',
  35247. [CT::T_ARRAY_INDEX_CURLY_BRACE_CLOSE],
  35248. [CT::T_ARRAY_SQUARE_BRACE_CLOSE],
  35249. [T_ARRAY],
  35250. [T_CLASS],
  35251. [T_ELSEIF],
  35252. [T_FOR],
  35253. [T_FOREACH],
  35254. [T_IF],
  35255. [T_STATIC],
  35256. [T_STRING],
  35257. [T_SWITCH],
  35258. [T_VARIABLE],
  35259. [T_WHILE],
  35260. ])) {
  35261. return;
  35262. }
  35263. $closeIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $index);
  35264. $tokens[$index] = new Token([CT::T_BRACE_CLASS_INSTANTIATION_OPEN, '(']);
  35265. $tokens[$closeIndex] = new Token([CT::T_BRACE_CLASS_INSTANTIATION_CLOSE, ')']);
  35266. }
  35267. }
  35268. <?php
  35269. namespace PhpCsFixer\Tokenizer\Transformer;
  35270. use PhpCsFixer\Tokenizer\AbstractTransformer;
  35271. use PhpCsFixer\Tokenizer\CT;
  35272. use PhpCsFixer\Tokenizer\Token;
  35273. use PhpCsFixer\Tokenizer\Tokens;
  35274. final class TypeAlternationTransformer extends AbstractTransformer
  35275. {
  35276. public function getCustomTokens()
  35277. {
  35278. return [CT::T_TYPE_ALTERNATION];
  35279. }
  35280. public function getRequiredPhpVersionId()
  35281. {
  35282. return 70100;
  35283. }
  35284. public function process(Tokens $tokens, Token $token, $index)
  35285. {
  35286. if (!$token->equals('|')) {
  35287. return;
  35288. }
  35289. $prevIndex = $tokens->getPrevMeaningfulToken($index);
  35290. $prevToken = $tokens[$prevIndex];
  35291. if (!$prevToken->isGivenKind(T_STRING)) {
  35292. return;
  35293. }
  35294. do {
  35295. $prevIndex = $tokens->getPrevMeaningfulToken($prevIndex);
  35296. if (null === $prevIndex) {
  35297. break;
  35298. }
  35299. $prevToken = $tokens[$prevIndex];
  35300. if ($prevToken->isGivenKind([T_NS_SEPARATOR, T_STRING])) {
  35301. continue;
  35302. }
  35303. if (
  35304. $prevToken->isGivenKind(CT::T_TYPE_ALTERNATION)
  35305. || (
  35306. $prevToken->equals('(')
  35307. && $tokens[$tokens->getPrevMeaningfulToken($prevIndex)]->isGivenKind(T_CATCH)
  35308. )
  35309. ) {
  35310. $tokens[$index] = new Token([CT::T_TYPE_ALTERNATION, '|']);
  35311. }
  35312. break;
  35313. } while (true);
  35314. }
  35315. }
  35316. <?php
  35317. namespace PhpCsFixer\Tokenizer\Transformer;
  35318. use PhpCsFixer\Tokenizer\AbstractTransformer;
  35319. use PhpCsFixer\Tokenizer\CT;
  35320. use PhpCsFixer\Tokenizer\Token;
  35321. use PhpCsFixer\Tokenizer\Tokens;
  35322. final class ReturnRefTransformer extends AbstractTransformer
  35323. {
  35324. public function getCustomTokens()
  35325. {
  35326. return [CT::T_RETURN_REF];
  35327. }
  35328. public function getRequiredPhpVersionId()
  35329. {
  35330. return 50000;
  35331. }
  35332. public function process(Tokens $tokens, Token $token, $index)
  35333. {
  35334. $prevKinds = [T_FUNCTION];
  35335. if (\PHP_VERSION_ID >= 70400) {
  35336. $prevKinds[] = T_FN;
  35337. }
  35338. if (
  35339. $token->equals('&')
  35340. && $tokens[$tokens->getPrevMeaningfulToken($index)]->isGivenKind($prevKinds)
  35341. ) {
  35342. $tokens[$index] = new Token([CT::T_RETURN_REF, '&']);
  35343. }
  35344. }
  35345. }
  35346. <?php
  35347. namespace PhpCsFixer\Tokenizer\Transformer;
  35348. use PhpCsFixer\Tokenizer\AbstractTransformer;
  35349. use PhpCsFixer\Tokenizer\CT;
  35350. use PhpCsFixer\Tokenizer\Token;
  35351. use PhpCsFixer\Tokenizer\Tokens;
  35352. final class SquareBraceTransformer extends AbstractTransformer
  35353. {
  35354. public function getCustomTokens()
  35355. {
  35356. return [
  35357. CT::T_ARRAY_SQUARE_BRACE_OPEN,
  35358. CT::T_ARRAY_SQUARE_BRACE_CLOSE,
  35359. CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN,
  35360. CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE,
  35361. ];
  35362. }
  35363. public function getPriority()
  35364. {
  35365. return -1;
  35366. }
  35367. public function getRequiredPhpVersionId()
  35368. {
  35369. return 50000;
  35370. }
  35371. public function process(Tokens $tokens, Token $token, $index)
  35372. {
  35373. if ($this->isArrayDestructing($tokens, $index)) {
  35374. $this->transformIntoDestructuringSquareBrace($tokens, $index);
  35375. return;
  35376. }
  35377. if ($this->isShortArray($tokens, $index)) {
  35378. $this->transformIntoArraySquareBrace($tokens, $index);
  35379. }
  35380. }
  35381. private function transformIntoArraySquareBrace(Tokens $tokens, $index)
  35382. {
  35383. $endIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_INDEX_SQUARE_BRACE, $index);
  35384. $tokens[$index] = new Token([CT::T_ARRAY_SQUARE_BRACE_OPEN, '[']);
  35385. $tokens[$endIndex] = new Token([CT::T_ARRAY_SQUARE_BRACE_CLOSE, ']']);
  35386. }
  35387. private function transformIntoDestructuringSquareBrace(Tokens $tokens, $index)
  35388. {
  35389. $endIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_INDEX_SQUARE_BRACE, $index);
  35390. $tokens[$index] = new Token([CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN, '[']);
  35391. $tokens[$endIndex] = new Token([CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE, ']']);
  35392. $previousMeaningfulIndex = $index;
  35393. $index = $tokens->getNextMeaningfulToken($index);
  35394. while ($index < $endIndex) {
  35395. if ($tokens[$index]->equals('[') && $tokens[$previousMeaningfulIndex]->equalsAny([[CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN], ','])) {
  35396. $tokens[$tokens->findBlockEnd(Tokens::BLOCK_TYPE_INDEX_SQUARE_BRACE, $index)] = new Token([CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE, ']']);
  35397. $tokens[$index] = new Token([CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN, '[']);
  35398. }
  35399. $previousMeaningfulIndex = $index;
  35400. $index = $tokens->getNextMeaningfulToken($index);
  35401. }
  35402. }
  35403. private function isShortArray(Tokens $tokens, $index)
  35404. {
  35405. if (!$tokens[$index]->equals('[')) {
  35406. return false;
  35407. }
  35408. static $disallowedPrevTokens = [
  35409. ')',
  35410. ']',
  35411. '}',
  35412. '"',
  35413. [T_CONSTANT_ENCAPSED_STRING],
  35414. [T_STRING],
  35415. [T_STRING_VARNAME],
  35416. [T_VARIABLE],
  35417. [CT::T_ARRAY_SQUARE_BRACE_CLOSE],
  35418. [CT::T_DYNAMIC_PROP_BRACE_CLOSE],
  35419. [CT::T_DYNAMIC_VAR_BRACE_CLOSE],
  35420. [CT::T_ARRAY_INDEX_CURLY_BRACE_CLOSE],
  35421. ];
  35422. $prevToken = $tokens[$tokens->getPrevMeaningfulToken($index)];
  35423. if ($prevToken->equalsAny($disallowedPrevTokens)) {
  35424. return false;
  35425. }
  35426. $nextToken = $tokens[$tokens->getNextMeaningfulToken($index)];
  35427. if ($nextToken->equals(']')) {
  35428. return true;
  35429. }
  35430. return !$this->isArrayDestructing($tokens, $index);
  35431. }
  35432. private function isArrayDestructing(Tokens $tokens, $index)
  35433. {
  35434. if (\PHP_VERSION_ID < 70100 || !$tokens[$index]->equals('[')) {
  35435. return false;
  35436. }
  35437. static $disallowedPrevTokens = [
  35438. ')',
  35439. ']',
  35440. '"',
  35441. [T_CONSTANT_ENCAPSED_STRING],
  35442. [T_STRING],
  35443. [T_STRING_VARNAME],
  35444. [T_VARIABLE],
  35445. [CT::T_ARRAY_SQUARE_BRACE_CLOSE],
  35446. [CT::T_DYNAMIC_PROP_BRACE_CLOSE],
  35447. [CT::T_DYNAMIC_VAR_BRACE_CLOSE],
  35448. [CT::T_ARRAY_INDEX_CURLY_BRACE_CLOSE],
  35449. ];
  35450. $prevToken = $tokens[$tokens->getPrevMeaningfulToken($index)];
  35451. if ($prevToken->equalsAny($disallowedPrevTokens)) {
  35452. return false;
  35453. }
  35454. $type = Tokens::detectBlockType($tokens[$index]);
  35455. $end = $tokens->findBlockEnd($type['type'], $index);
  35456. $nextToken = $tokens[$tokens->getNextMeaningfulToken($end)];
  35457. return $nextToken->equals('=');
  35458. }
  35459. }
  35460. <?php
  35461. namespace PhpCsFixer\Tokenizer\Analyzer;
  35462. use PhpCsFixer\Tokenizer\Analyzer\Analysis\ArgumentAnalysis;
  35463. use PhpCsFixer\Tokenizer\Analyzer\Analysis\TypeAnalysis;
  35464. use PhpCsFixer\Tokenizer\Tokens;
  35465. /**
  35466. @gmail
  35467. */
  35468. final class ArgumentsAnalyzer
  35469. {
  35470. public function countArguments(Tokens $tokens, $openParenthesis, $closeParenthesis)
  35471. {
  35472. return \count($this->getArguments($tokens, $openParenthesis, $closeParenthesis));
  35473. }
  35474. public function getArguments(Tokens $tokens, $openParenthesis, $closeParenthesis)
  35475. {
  35476. $arguments = [];
  35477. $firstSensibleToken = $tokens->getNextMeaningfulToken($openParenthesis);
  35478. if ($tokens[$firstSensibleToken]->equals(')')) {
  35479. return $arguments;
  35480. }
  35481. $paramContentIndex = $openParenthesis + 1;
  35482. $argumentsStart = $paramContentIndex;
  35483. for (; $paramContentIndex < $closeParenthesis; ++$paramContentIndex) {
  35484. $token = $tokens[$paramContentIndex];
  35485. $blockDefinitionProbe = Tokens::detectBlockType($token);
  35486. if (null !== $blockDefinitionProbe && true === $blockDefinitionProbe['isStart']) {
  35487. $paramContentIndex = $tokens->findBlockEnd($blockDefinitionProbe['type'], $paramContentIndex);
  35488. continue;
  35489. }
  35490. if ($token->equals(',')) {
  35491. if ($tokens->getNextMeaningfulToken($paramContentIndex) === $closeParenthesis) {
  35492. break;
  35493. }
  35494. $arguments[$argumentsStart] = $paramContentIndex - 1;
  35495. $argumentsStart = $paramContentIndex + 1;
  35496. }
  35497. }
  35498. $arguments[$argumentsStart] = $paramContentIndex - 1;
  35499. return $arguments;
  35500. }
  35501. public function getArgumentInfo(Tokens $tokens, $argumentStart, $argumentEnd)
  35502. {
  35503. $info = [
  35504. 'default' => null,
  35505. 'name' => null,
  35506. 'name_index' => null,
  35507. 'type' => null,
  35508. 'type_index_start' => null,
  35509. 'type_index_end' => null,
  35510. ];
  35511. $sawName = false;
  35512. for ($index = $argumentStart; $index <= $argumentEnd; ++$index) {
  35513. $token = $tokens[$index];
  35514. if ($token->isComment() || $token->isWhitespace() || $token->isGivenKind(T_ELLIPSIS) || $token->equals('&')) {
  35515. continue;
  35516. }
  35517. if ($token->isGivenKind(T_VARIABLE)) {
  35518. $sawName = true;
  35519. $info['name_index'] = $index;
  35520. $info['name'] = $token->getContent();
  35521. continue;
  35522. }
  35523. if ($token->equals('=')) {
  35524. continue;
  35525. }
  35526. if ($sawName) {
  35527. $info['default'] .= $token->getContent();
  35528. } else {
  35529. $info['type_index_start'] = ($info['type_index_start'] > 0) ? $info['type_index_start'] : $index;
  35530. $info['type_index_end'] = $index;
  35531. $info['type'] .= $token->getContent();
  35532. }
  35533. }
  35534. return new ArgumentAnalysis(
  35535. $info['name'],
  35536. $info['name_index'],
  35537. $info['default'],
  35538. $info['type'] ? new TypeAnalysis($info['type'], $info['type_index_start'], $info['type_index_end']) : null
  35539. );
  35540. }
  35541. }
  35542. <?php
  35543. namespace PhpCsFixer\Tokenizer\Analyzer;
  35544. use PhpCsFixer\Preg;
  35545. use PhpCsFixer\Tokenizer\CT;
  35546. use PhpCsFixer\Tokenizer\Token;
  35547. use PhpCsFixer\Tokenizer\Tokens;
  35548. final class CommentsAnalyzer
  35549. {
  35550. const TYPE_HASH = 1;
  35551. const TYPE_DOUBLE_SLASH = 2;
  35552. const TYPE_SLASH_ASTERISK = 3;
  35553. public function isHeaderComment(Tokens $tokens, $index)
  35554. {
  35555. if (!$tokens[$index]->isGivenKind([T_COMMENT, T_DOC_COMMENT])) {
  35556. throw new \InvalidArgumentException('Given index must point to a comment.');
  35557. }
  35558. if (null === $tokens->getNextMeaningfulToken($index)) {
  35559. return false;
  35560. }
  35561. $prevIndex = $tokens->getPrevNonWhitespace($index);
  35562. if ($tokens[$prevIndex]->equals(';')) {
  35563. $braceCloseIndex = $tokens->getPrevMeaningfulToken($prevIndex);
  35564. if (!$tokens[$braceCloseIndex]->equals(')')) {
  35565. return false;
  35566. }
  35567. $braceOpenIndex = $tokens->findBlockStart(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $braceCloseIndex);
  35568. $declareIndex = $tokens->getPrevMeaningfulToken($braceOpenIndex);
  35569. if (!$tokens[$declareIndex]->isGivenKind(T_DECLARE)) {
  35570. return false;
  35571. }
  35572. $prevIndex = $tokens->getPrevNonWhitespace($declareIndex);
  35573. }
  35574. return $tokens[$prevIndex]->isGivenKind(T_OPEN_TAG);
  35575. }
  35576. public function isBeforeStructuralElement(Tokens $tokens, $index)
  35577. {
  35578. $token = $tokens[$index];
  35579. if (!$token->isGivenKind([T_COMMENT, T_DOC_COMMENT])) {
  35580. throw new \InvalidArgumentException('Given index must point to a comment.');
  35581. }
  35582. $nextIndex = $index;
  35583. do {
  35584. $nextIndex = $tokens->getNextMeaningfulToken($nextIndex);
  35585. } while (null !== $nextIndex && $tokens[$nextIndex]->equals('('));
  35586. if (null === $nextIndex || $tokens[$nextIndex]->equals('}')) {
  35587. return false;
  35588. }
  35589. $nextToken = $tokens[$nextIndex];
  35590. if ($this->isStructuralElement($nextToken)) {
  35591. return true;
  35592. }
  35593. if ($this->isValidControl($tokens, $token, $nextIndex)) {
  35594. return true;
  35595. }
  35596. if ($this->isValidVariable($tokens, $nextIndex)) {
  35597. return true;
  35598. }
  35599. if ($this->isValidLanguageConstruct($tokens, $token, $nextIndex)) {
  35600. return true;
  35601. }
  35602. return false;
  35603. }
  35604. public function getCommentBlockIndices(Tokens $tokens, $index)
  35605. {
  35606. if (!$tokens[$index]->isGivenKind(T_COMMENT)) {
  35607. throw new \InvalidArgumentException('Given index must point to a comment.');
  35608. }
  35609. $commentType = $this->getCommentType($tokens[$index]->getContent());
  35610. $indices = [$index];
  35611. if (self::TYPE_SLASH_ASTERISK === $commentType) {
  35612. return $indices;
  35613. }
  35614. $count = \count($tokens);
  35615. ++$index;
  35616. for (; $index < $count; ++$index) {
  35617. if ($tokens[$index]->isComment()) {
  35618. if ($commentType === $this->getCommentType($tokens[$index]->getContent())) {
  35619. $indices[] = $index;
  35620. continue;
  35621. }
  35622. break;
  35623. }
  35624. if (!$tokens[$index]->isWhitespace() || $this->getLineBreakCount($tokens, $index, $index + 1) > 1) {
  35625. break;
  35626. }
  35627. }
  35628. return $indices;
  35629. }
  35630. private function isStructuralElement(Token $token)
  35631. {
  35632. static $skip = [
  35633. T_PRIVATE,
  35634. T_PROTECTED,
  35635. T_PUBLIC,
  35636. T_VAR,
  35637. T_FUNCTION,
  35638. T_ABSTRACT,
  35639. T_CONST,
  35640. T_NAMESPACE,
  35641. T_REQUIRE,
  35642. T_REQUIRE_ONCE,
  35643. T_INCLUDE,
  35644. T_INCLUDE_ONCE,
  35645. T_FINAL,
  35646. T_STATIC,
  35647. ];
  35648. return $token->isClassy() || $token->isGivenKind($skip);
  35649. }
  35650. private function isValidControl(Tokens $tokens, Token $docsToken, $controlIndex)
  35651. {
  35652. static $controlStructures = [
  35653. T_FOR,
  35654. T_FOREACH,
  35655. T_IF,
  35656. T_SWITCH,
  35657. T_WHILE,
  35658. ];
  35659. if (!$tokens[$controlIndex]->isGivenKind($controlStructures)) {
  35660. return false;
  35661. }
  35662. $index = $tokens->getNextMeaningfulToken($controlIndex);
  35663. $endIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $index);
  35664. $docsContent = $docsToken->getContent();
  35665. for ($index = $index + 1; $index < $endIndex; ++$index) {
  35666. $token = $tokens[$index];
  35667. if (
  35668. $token->isGivenKind(T_VARIABLE) &&
  35669. false !== strpos($docsContent, $token->getContent())
  35670. ) {
  35671. return true;
  35672. }
  35673. }
  35674. return false;
  35675. }
  35676. private function isValidLanguageConstruct(Tokens $tokens, Token $docsToken, $languageConstructIndex)
  35677. {
  35678. static $languageStructures = [
  35679. T_LIST,
  35680. T_PRINT,
  35681. T_ECHO,
  35682. CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN,
  35683. ];
  35684. if (!$tokens[$languageConstructIndex]->isGivenKind($languageStructures)) {
  35685. return false;
  35686. }
  35687. $endKind = $tokens[$languageConstructIndex]->isGivenKind(CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN)
  35688. ? [CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE]
  35689. : ')';
  35690. $endIndex = $tokens->getNextTokenOfKind($languageConstructIndex, [$endKind]);
  35691. $docsContent = $docsToken->getContent();
  35692. for ($index = $languageConstructIndex + 1; $index < $endIndex; ++$index) {
  35693. $token = $tokens[$index];
  35694. if ($token->isGivenKind(T_VARIABLE) && false !== strpos($docsContent, $token->getContent())) {
  35695. return true;
  35696. }
  35697. }
  35698. return false;
  35699. }
  35700. private function isValidVariable(Tokens $tokens, $index)
  35701. {
  35702. if (!$tokens[$index]->isGivenKind(T_VARIABLE)) {
  35703. return false;
  35704. }
  35705. $nextIndex = $tokens->getNextMeaningfulToken($index);
  35706. return $tokens[$nextIndex]->equals('=');
  35707. }
  35708. private function getCommentType($content)
  35709. {
  35710. if ('#' === $content[0]) {
  35711. return self::TYPE_HASH;
  35712. }
  35713. if ('*' === $content[1]) {
  35714. return self::TYPE_SLASH_ASTERISK;
  35715. }
  35716. return self::TYPE_DOUBLE_SLASH;
  35717. }
  35718. private function getLineBreakCount(Tokens $tokens, $whiteStart, $whiteEnd)
  35719. {
  35720. $lineCount = 0;
  35721. for ($i = $whiteStart; $i < $whiteEnd; ++$i) {
  35722. $lineCount += Preg::matchAll('/\R/u', $tokens[$i]->getContent());
  35723. }
  35724. return $lineCount;
  35725. }
  35726. }
  35727. <?php
  35728. namespace PhpCsFixer\Tokenizer\Analyzer;
  35729. use PhpCsFixer\Tokenizer\Token;
  35730. use PhpCsFixer\Tokenizer\Tokens;
  35731. final class BlocksAnalyzer
  35732. {
  35733. public function isBlock(Tokens $tokens, $openIndex, $closeIndex)
  35734. {
  35735. if (null === $openIndex || null === $closeIndex) {
  35736. return false;
  35737. }
  35738. if (!$tokens->offsetExists($openIndex)) {
  35739. return false;
  35740. }
  35741. if (!$tokens->offsetExists($closeIndex)) {
  35742. return false;
  35743. }
  35744. $blockType = $this->getBlockType($tokens[$openIndex]);
  35745. if (null === $blockType) {
  35746. return false;
  35747. }
  35748. return $closeIndex === $tokens->findBlockEnd($blockType, $openIndex);
  35749. }
  35750. private function getBlockType(Token $token)
  35751. {
  35752. foreach (Tokens::getBlockEdgeDefinitions() as $blockType => $definition) {
  35753. if ($token->equals($definition['start'])) {
  35754. return $blockType;
  35755. }
  35756. }
  35757. return null;
  35758. }
  35759. }
  35760. <?php
  35761. namespace PhpCsFixer\Tokenizer\Analyzer;
  35762. use PhpCsFixer\Tokenizer\Analyzer\Analysis\NamespaceAnalysis;
  35763. use PhpCsFixer\Tokenizer\Tokens;
  35764. final class NamespacesAnalyzer
  35765. {
  35766. public function getDeclarations(Tokens $tokens)
  35767. {
  35768. $namespaces = [];
  35769. for ($index = 1, $count = \count($tokens); $index < $count; ++$index) {
  35770. $token = $tokens[$index];
  35771. if (!$token->isGivenKind(T_NAMESPACE)) {
  35772. continue;
  35773. }
  35774. $declarationEndIndex = $tokens->getNextTokenOfKind($index, [';', '{']);
  35775. $namespace = trim($tokens->generatePartialCode($index + 1, $declarationEndIndex - 1));
  35776. $declarationParts = explode('\\', $namespace);
  35777. $shortName = end($declarationParts);
  35778. if ($tokens[$declarationEndIndex]->equals('{')) {
  35779. $scopeEndIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $declarationEndIndex);
  35780. } else {
  35781. $scopeEndIndex = $tokens->getNextTokenOfKind($declarationEndIndex, [[T_NAMESPACE]]);
  35782. if (null === $scopeEndIndex) {
  35783. $scopeEndIndex = \count($tokens);
  35784. }
  35785. --$scopeEndIndex;
  35786. }
  35787. $namespaces[] = new NamespaceAnalysis(
  35788. $namespace,
  35789. $shortName,
  35790. $index,
  35791. $declarationEndIndex,
  35792. $index,
  35793. $scopeEndIndex
  35794. );
  35795. $index = $scopeEndIndex;
  35796. }
  35797. if (0 === \count($namespaces)) {
  35798. $namespaces[] = new NamespaceAnalysis('', '', 0, 0, 0, \count($tokens) - 1);
  35799. }
  35800. return $namespaces;
  35801. }
  35802. }
  35803. <?php
  35804. namespace PhpCsFixer\Tokenizer\Analyzer;
  35805. use PhpCsFixer\Tokenizer\CT;
  35806. use PhpCsFixer\Tokenizer\Tokens;
  35807. final class ClassyAnalyzer
  35808. {
  35809. public function isClassyInvocation(Tokens $tokens, $index)
  35810. {
  35811. $token = $tokens[$index];
  35812. if (!$token->isGivenKind(T_STRING)) {
  35813. throw new \LogicException(sprintf('No T_STRING at given index %d, got %s.', $index, $tokens[$index]->getName()));
  35814. }
  35815. if (\in_array(strtolower($token->getContent()), ['bool', 'float', 'int', 'iterable', 'object', 'parent', 'self', 'string', 'void'], true)) {
  35816. return false;
  35817. }
  35818. $next = $tokens->getNextMeaningfulToken($index);
  35819. $nextToken = $tokens[$next];
  35820. if ($nextToken->isGivenKind(T_NS_SEPARATOR)) {
  35821. return false;
  35822. }
  35823. if ($nextToken->isGivenKind([T_DOUBLE_COLON, T_ELLIPSIS, CT::T_TYPE_ALTERNATION, T_VARIABLE])) {
  35824. return true;
  35825. }
  35826. $prev = $tokens->getPrevMeaningfulToken($index);
  35827. while ($tokens[$prev]->isGivenKind([CT::T_NAMESPACE_OPERATOR, T_NS_SEPARATOR, T_STRING])) {
  35828. $prev = $tokens->getPrevMeaningfulToken($prev);
  35829. }
  35830. $prevToken = $tokens[$prev];
  35831. if ($prevToken->isGivenKind([T_EXTENDS, T_INSTANCEOF, T_INSTEADOF, T_IMPLEMENTS, T_NEW, CT::T_NULLABLE_TYPE, CT::T_TYPE_ALTERNATION, CT::T_TYPE_COLON, CT::T_USE_TRAIT])) {
  35832. return true;
  35833. }
  35834. if ($nextToken->equals('&') && $tokens[$tokens->getNextMeaningfulToken($next)]->isGivenKind(T_VARIABLE)) {
  35835. $checkIndex = $tokens->getPrevTokenOfKind($prev + 1, [';', '{', '}', [T_FUNCTION], [T_OPEN_TAG], [T_OPEN_TAG_WITH_ECHO]]);
  35836. return $tokens[$checkIndex]->isGivenKind(T_FUNCTION);
  35837. }
  35838. if (!$prevToken->equals(',')) {
  35839. return false;
  35840. }
  35841. do {
  35842. $prev = $tokens->getPrevMeaningfulToken($prev);
  35843. } while ($tokens[$prev]->equalsAny([',', [T_NS_SEPARATOR], [T_STRING], [CT::T_NAMESPACE_OPERATOR]]));
  35844. return $tokens[$prev]->isGivenKind([T_IMPLEMENTS, CT::T_USE_TRAIT]);
  35845. }
  35846. }
  35847. <?php
  35848. namespace PhpCsFixer\Tokenizer\Analyzer;
  35849. use PhpCsFixer\Tokenizer\Analyzer\Analysis\NamespaceUseAnalysis;
  35850. use PhpCsFixer\Tokenizer\CT;
  35851. use PhpCsFixer\Tokenizer\Tokens;
  35852. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  35853. final class NamespaceUsesAnalyzer
  35854. {
  35855. public function getDeclarationsFromTokens(Tokens $tokens)
  35856. {
  35857. $tokenAnalyzer = new TokensAnalyzer($tokens);
  35858. $useIndexes = $tokenAnalyzer->getImportUseIndexes();
  35859. return $this->getDeclarations($tokens, $useIndexes);
  35860. }
  35861. private function getDeclarations(Tokens $tokens, array $useIndexes)
  35862. {
  35863. $uses = [];
  35864. foreach ($useIndexes as $index) {
  35865. $endIndex = $tokens->getNextTokenOfKind($index, [';', [T_CLOSE_TAG]]);
  35866. $analysis = $this->parseDeclaration($tokens, $index, $endIndex);
  35867. if ($analysis) {
  35868. $uses[] = $analysis;
  35869. }
  35870. }
  35871. return $uses;
  35872. }
  35873. private function parseDeclaration(Tokens $tokens, $startIndex, $endIndex)
  35874. {
  35875. $fullName = $shortName = '';
  35876. $aliased = false;
  35877. $type = NamespaceUseAnalysis::TYPE_CLASS;
  35878. for ($i = $startIndex; $i <= $endIndex; ++$i) {
  35879. $token = $tokens[$i];
  35880. if ($token->equals(',') || $token->isGivenKind(CT::T_GROUP_IMPORT_BRACE_CLOSE)) {
  35881. return null;
  35882. }
  35883. if ($token->isGivenKind(CT::T_FUNCTION_IMPORT)) {
  35884. $type = NamespaceUseAnalysis::TYPE_FUNCTION;
  35885. } elseif ($token->isGivenKind(CT::T_CONST_IMPORT)) {
  35886. $type = NamespaceUseAnalysis::TYPE_CONSTANT;
  35887. }
  35888. if ($token->isWhitespace() || $token->isComment() || $token->isGivenKind(T_USE)) {
  35889. continue;
  35890. }
  35891. if ($token->isGivenKind(T_STRING)) {
  35892. $shortName = $token->getContent();
  35893. if (!$aliased) {
  35894. $fullName .= $shortName;
  35895. }
  35896. } elseif ($token->isGivenKind(T_NS_SEPARATOR)) {
  35897. $fullName .= $token->getContent();
  35898. } elseif ($token->isGivenKind(T_AS)) {
  35899. $aliased = true;
  35900. }
  35901. }
  35902. return new NamespaceUseAnalysis(
  35903. trim($fullName),
  35904. $shortName,
  35905. $aliased,
  35906. $startIndex,
  35907. $endIndex,
  35908. $type
  35909. );
  35910. }
  35911. }
  35912. <?php
  35913. namespace PhpCsFixer\Tokenizer\Analyzer\Analysis;
  35914. interface StartEndTokenAwareAnalysis
  35915. {
  35916. public function getStartIndex();
  35917. public function getEndIndex();
  35918. }
  35919. <?php
  35920. namespace PhpCsFixer\Tokenizer\Analyzer\Analysis;
  35921. final class NamespaceUseAnalysis implements StartEndTokenAwareAnalysis
  35922. {
  35923. const TYPE_CLASS = 1;
  35924. const TYPE_FUNCTION = 2;
  35925. const TYPE_CONSTANT = 3;
  35926. private $fullName;
  35927. private $shortName;
  35928. private $isAliased;
  35929. private $startIndex;
  35930. private $endIndex;
  35931. private $type;
  35932. public function __construct($fullName, $shortName, $isAliased, $startIndex, $endIndex, $type)
  35933. {
  35934. $this->fullName = $fullName;
  35935. $this->shortName = $shortName;
  35936. $this->isAliased = $isAliased;
  35937. $this->startIndex = $startIndex;
  35938. $this->endIndex = $endIndex;
  35939. $this->type = $type;
  35940. }
  35941. public function getFullName()
  35942. {
  35943. return $this->fullName;
  35944. }
  35945. public function getShortName()
  35946. {
  35947. return $this->shortName;
  35948. }
  35949. public function isAliased()
  35950. {
  35951. return $this->isAliased;
  35952. }
  35953. public function getStartIndex()
  35954. {
  35955. return $this->startIndex;
  35956. }
  35957. public function getEndIndex()
  35958. {
  35959. return $this->endIndex;
  35960. }
  35961. public function isClass()
  35962. {
  35963. return self::TYPE_CLASS === $this->type;
  35964. }
  35965. public function isFunction()
  35966. {
  35967. return self::TYPE_FUNCTION === $this->type;
  35968. }
  35969. public function isConstant()
  35970. {
  35971. return self::TYPE_CONSTANT === $this->type;
  35972. }
  35973. }
  35974. <?php
  35975. namespace PhpCsFixer\Tokenizer\Analyzer\Analysis;
  35976. final class ArgumentAnalysis
  35977. {
  35978. private $default;
  35979. private $name;
  35980. private $nameIndex;
  35981. private $typeAnalysis;
  35982. public function __construct($name, $nameIndex, $default, TypeAnalysis $typeAnalysis = null)
  35983. {
  35984. $this->name = $name;
  35985. $this->nameIndex = $nameIndex;
  35986. $this->default = $default ?: null;
  35987. $this->typeAnalysis = $typeAnalysis ?: null;
  35988. }
  35989. public function getDefault()
  35990. {
  35991. return $this->default;
  35992. }
  35993. public function hasDefault()
  35994. {
  35995. return null !== $this->default;
  35996. }
  35997. public function getName()
  35998. {
  35999. return $this->name;
  36000. }
  36001. public function getNameIndex()
  36002. {
  36003. return $this->nameIndex;
  36004. }
  36005. public function getTypeAnalysis()
  36006. {
  36007. return $this->typeAnalysis;
  36008. }
  36009. public function hasTypeAnalysis()
  36010. {
  36011. return null !== $this->typeAnalysis;
  36012. }
  36013. }
  36014. <?php
  36015. namespace PhpCsFixer\Tokenizer\Analyzer\Analysis;
  36016. final class NamespaceAnalysis implements StartEndTokenAwareAnalysis
  36017. {
  36018. private $fullName;
  36019. private $shortName;
  36020. private $startIndex;
  36021. private $endIndex;
  36022. private $scopeStartIndex;
  36023. private $scopeEndIndex;
  36024. public function __construct($fullName, $shortName, $startIndex, $endIndex, $scopeStartIndex, $scopeEndIndex)
  36025. {
  36026. $this->fullName = $fullName;
  36027. $this->shortName = $shortName;
  36028. $this->startIndex = $startIndex;
  36029. $this->endIndex = $endIndex;
  36030. $this->scopeStartIndex = $scopeStartIndex;
  36031. $this->scopeEndIndex = $scopeEndIndex;
  36032. }
  36033. public function getFullName()
  36034. {
  36035. return $this->fullName;
  36036. }
  36037. public function getShortName()
  36038. {
  36039. return $this->shortName;
  36040. }
  36041. public function getStartIndex()
  36042. {
  36043. return $this->startIndex;
  36044. }
  36045. public function getEndIndex()
  36046. {
  36047. return $this->endIndex;
  36048. }
  36049. public function getScopeStartIndex()
  36050. {
  36051. return $this->scopeStartIndex;
  36052. }
  36053. public function getScopeEndIndex()
  36054. {
  36055. return $this->scopeEndIndex;
  36056. }
  36057. }
  36058. <?php
  36059. namespace PhpCsFixer\Tokenizer\Analyzer\Analysis;
  36060. final class TypeAnalysis implements StartEndTokenAwareAnalysis
  36061. {
  36062. private static $reservedTypes = [
  36063. 'array',
  36064. 'bool',
  36065. 'callable',
  36066. 'int',
  36067. 'iterable',
  36068. 'float',
  36069. 'mixed',
  36070. 'numeric',
  36071. 'object',
  36072. 'resource',
  36073. 'self',
  36074. 'string',
  36075. 'void',
  36076. ];
  36077. private $name;
  36078. private $startIndex;
  36079. private $endIndex;
  36080. private $nullable;
  36081. public function __construct($name, $startIndex, $endIndex)
  36082. {
  36083. $this->name = $name;
  36084. $this->nullable = false;
  36085. if (0 === strpos($name, '?')) {
  36086. $this->name = substr($name, 1);
  36087. $this->nullable = true;
  36088. }
  36089. $this->startIndex = $startIndex;
  36090. $this->endIndex = $endIndex;
  36091. }
  36092. public function getName()
  36093. {
  36094. return $this->name;
  36095. }
  36096. public function getStartIndex()
  36097. {
  36098. return $this->startIndex;
  36099. }
  36100. public function getEndIndex()
  36101. {
  36102. return $this->endIndex;
  36103. }
  36104. public function isReservedType()
  36105. {
  36106. return \in_array($this->name, self::$reservedTypes, true);
  36107. }
  36108. public function isNullable()
  36109. {
  36110. return $this->nullable;
  36111. }
  36112. }
  36113. <?php
  36114. namespace PhpCsFixer\Tokenizer\Analyzer;
  36115. use PhpCsFixer\Tokenizer\Analyzer\Analysis\ArgumentAnalysis;
  36116. use PhpCsFixer\Tokenizer\Analyzer\Analysis\NamespaceUseAnalysis;
  36117. use PhpCsFixer\Tokenizer\Analyzer\Analysis\TypeAnalysis;
  36118. use PhpCsFixer\Tokenizer\CT;
  36119. use PhpCsFixer\Tokenizer\Token;
  36120. use PhpCsFixer\Tokenizer\Tokens;
  36121. final class FunctionsAnalyzer
  36122. {
  36123. private $functionsAnalysis = ['tokens' => '', 'imports' => [], 'declarations' => []];
  36124. public function isGlobalFunctionCall(Tokens $tokens, $index)
  36125. {
  36126. if (!$tokens[$index]->isGivenKind(T_STRING)) {
  36127. return false;
  36128. }
  36129. $nextIndex = $tokens->getNextMeaningfulToken($index);
  36130. if (!$tokens[$nextIndex]->equals('(')) {
  36131. return false;
  36132. }
  36133. $previousIsNamespaceSeparator = false;
  36134. $prevIndex = $tokens->getPrevMeaningfulToken($index);
  36135. if ($tokens[$prevIndex]->isGivenKind(T_NS_SEPARATOR)) {
  36136. $previousIsNamespaceSeparator = true;
  36137. $prevIndex = $tokens->getPrevMeaningfulToken($prevIndex);
  36138. }
  36139. if ($tokens[$prevIndex]->isGivenKind([T_DOUBLE_COLON, T_FUNCTION, CT::T_NAMESPACE_OPERATOR, T_NEW, T_OBJECT_OPERATOR, CT::T_RETURN_REF, T_STRING])) {
  36140. return false;
  36141. }
  36142. if ($previousIsNamespaceSeparator) {
  36143. return true;
  36144. }
  36145. if ($tokens->isChanged() || $tokens->getCodeHash() !== $this->functionsAnalysis['tokens']) {
  36146. $this->buildFunctionsAnalysis($tokens);
  36147. }
  36148. $namespaceAnalyzer = new NamespacesAnalyzer();
  36149. $declarations = $namespaceAnalyzer->getDeclarations($tokens);
  36150. $scopeStartIndex = 0;
  36151. $scopeEndIndex = \count($tokens) - 1;
  36152. $inGlobalNamespace = false;
  36153. foreach ($declarations as $declaration) {
  36154. $scopeStartIndex = $declaration->getScopeStartIndex();
  36155. $scopeEndIndex = $declaration->getScopeEndIndex();
  36156. if ($index >= $scopeStartIndex && $index <= $scopeEndIndex) {
  36157. $inGlobalNamespace = '' === $declaration->getFullName();
  36158. break;
  36159. }
  36160. }
  36161. $call = strtolower($tokens[$index]->getContent());
  36162. if (!$inGlobalNamespace) {
  36163. foreach ($this->functionsAnalysis['declarations'] as $functionNameIndex) {
  36164. if ($functionNameIndex < $scopeStartIndex || $functionNameIndex > $scopeEndIndex) {
  36165. continue;
  36166. }
  36167. if (strtolower($tokens[$functionNameIndex]->getContent()) === $call) {
  36168. return false;
  36169. }
  36170. }
  36171. }
  36172. foreach ($this->functionsAnalysis['imports'] as $functionUse) {
  36173. if ($functionUse->getStartIndex() < $scopeStartIndex || $functionUse->getEndIndex() > $scopeEndIndex) {
  36174. continue;
  36175. }
  36176. if ($call !== strtolower($functionUse->getShortName())) {
  36177. continue;
  36178. }
  36179. return $functionUse->getShortName() === ltrim($functionUse->getFullName(), '\\');
  36180. }
  36181. return true;
  36182. }
  36183. public function getFunctionArguments(Tokens $tokens, $methodIndex)
  36184. {
  36185. $argumentsStart = $tokens->getNextTokenOfKind($methodIndex, ['(']);
  36186. $argumentsEnd = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $argumentsStart);
  36187. $argumentAnalyzer = new ArgumentsAnalyzer();
  36188. $arguments = [];
  36189. foreach ($argumentAnalyzer->getArguments($tokens, $argumentsStart, $argumentsEnd) as $start => $end) {
  36190. $argumentInfo = $argumentAnalyzer->getArgumentInfo($tokens, $start, $end);
  36191. $arguments[$argumentInfo->getName()] = $argumentInfo;
  36192. }
  36193. return $arguments;
  36194. }
  36195. public function getFunctionReturnType(Tokens $tokens, $methodIndex)
  36196. {
  36197. $argumentsStart = $tokens->getNextTokenOfKind($methodIndex, ['(']);
  36198. $argumentsEnd = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $argumentsStart);
  36199. $typeColonIndex = $tokens->getNextMeaningfulToken($argumentsEnd);
  36200. if (':' !== $tokens[$typeColonIndex]->getContent()) {
  36201. return null;
  36202. }
  36203. $type = '';
  36204. $typeStartIndex = $tokens->getNextMeaningfulToken($typeColonIndex);
  36205. $typeEndIndex = $typeStartIndex;
  36206. $functionBodyStart = $tokens->getNextTokenOfKind($typeColonIndex, ['{', ';', [T_DOUBLE_ARROW]]);
  36207. for ($i = $typeStartIndex; $i < $functionBodyStart; ++$i) {
  36208. if ($tokens[$i]->isWhitespace() || $tokens[$i]->isComment()) {
  36209. continue;
  36210. }
  36211. $type .= $tokens[$i]->getContent();
  36212. $typeEndIndex = $i;
  36213. }
  36214. return new TypeAnalysis($type, $typeStartIndex, $typeEndIndex);
  36215. }
  36216. public function isTheSameClassCall(Tokens $tokens, $index)
  36217. {
  36218. if (!$tokens->offsetExists($index)) {
  36219. return false;
  36220. }
  36221. $operatorIndex = $tokens->getPrevMeaningfulToken($index);
  36222. if (!$tokens->offsetExists($operatorIndex)) {
  36223. return false;
  36224. }
  36225. $referenceIndex = $tokens->getPrevMeaningfulToken($operatorIndex);
  36226. if (!$tokens->offsetExists($referenceIndex)) {
  36227. return false;
  36228. }
  36229. return $tokens[$operatorIndex]->equals([T_OBJECT_OPERATOR, '->']) && $tokens[$referenceIndex]->equals([T_VARIABLE, '$this'], false)
  36230. || $tokens[$operatorIndex]->equals([T_DOUBLE_COLON, '::']) && $tokens[$referenceIndex]->equals([T_STRING, 'self'], false)
  36231. || $tokens[$operatorIndex]->equals([T_DOUBLE_COLON, '::']) && $tokens[$referenceIndex]->equals([T_STATIC, 'static'], false);
  36232. }
  36233. private function buildFunctionsAnalysis(Tokens $tokens)
  36234. {
  36235. $this->functionsAnalysis = [
  36236. 'tokens' => $tokens->getCodeHash(),
  36237. 'imports' => [],
  36238. 'declarations' => [],
  36239. ];
  36240. if ($tokens->isTokenKindFound(T_FUNCTION)) {
  36241. $end = \count($tokens);
  36242. for ($i = 0; $i < $end; ++$i) {
  36243. if ($tokens[$i]->isGivenKind(Token::getClassyTokenKinds())) {
  36244. $i = $tokens->getNextTokenOfKind($i, ['(', '{']);
  36245. if ($tokens[$i]->equals('(')) {
  36246. $i = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $i);
  36247. $i = $tokens->getNextTokenOfKind($i, ['{']);
  36248. }
  36249. $i = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $i);
  36250. continue;
  36251. }
  36252. if (!$tokens[$i]->isGivenKind(T_FUNCTION)) {
  36253. continue;
  36254. }
  36255. $i = $tokens->getNextMeaningfulToken($i);
  36256. if ($tokens[$i]->isGivenKind(CT::T_RETURN_REF)) {
  36257. $i = $tokens->getNextMeaningfulToken($i);
  36258. }
  36259. if (!$tokens[$i]->isGivenKind(T_STRING)) {
  36260. continue;
  36261. }
  36262. $this->functionsAnalysis['declarations'][] = $i;
  36263. }
  36264. }
  36265. $namespaceUsesAnalyzer = new NamespaceUsesAnalyzer();
  36266. if ($tokens->isTokenKindFound(CT::T_FUNCTION_IMPORT)) {
  36267. $declarations = $namespaceUsesAnalyzer->getDeclarationsFromTokens($tokens);
  36268. foreach ($declarations as $declaration) {
  36269. if ($declaration->isFunction()) {
  36270. $this->functionsAnalysis['imports'][] = $declaration;
  36271. }
  36272. }
  36273. }
  36274. }
  36275. }
  36276. <?php
  36277. namespace PhpCsFixer\Tokenizer;
  36278. use PhpCsFixer\Utils;
  36279. use Symfony\Component\Finder\Finder;
  36280. use Symfony\Component\Finder\SplFileInfo;
  36281. final class Transformers
  36282. {
  36283. private $items = [];
  36284. private function __construct()
  36285. {
  36286. $this->registerBuiltInTransformers();
  36287. usort($this->items, static function (TransformerInterface $a, TransformerInterface $b) {
  36288. return Utils::cmpInt($b->getPriority(), $a->getPriority());
  36289. });
  36290. }
  36291. public static function create()
  36292. {
  36293. static $instance = null;
  36294. if (!$instance) {
  36295. $instance = new self();
  36296. }
  36297. return $instance;
  36298. }
  36299. public function transform(Tokens $tokens)
  36300. {
  36301. foreach ($this->items as $transformer) {
  36302. foreach ($tokens as $index => $token) {
  36303. $transformer->process($tokens, $token, $index);
  36304. }
  36305. }
  36306. }
  36307. private function registerTransformer(TransformerInterface $transformer)
  36308. {
  36309. if (\PHP_VERSION_ID >= $transformer->getRequiredPhpVersionId()) {
  36310. $this->items[] = $transformer;
  36311. }
  36312. }
  36313. private function registerBuiltInTransformers()
  36314. {
  36315. static $registered = false;
  36316. if ($registered) {
  36317. return;
  36318. }
  36319. $registered = true;
  36320. foreach ($this->findBuiltInTransformers() as $transformer) {
  36321. $this->registerTransformer($transformer);
  36322. }
  36323. }
  36324. private function findBuiltInTransformers()
  36325. {
  36326. foreach (Finder::create()->files()->in(__DIR__.'/Transformer') as $file) {
  36327. $relativeNamespace = $file->getRelativePath();
  36328. $class = __NAMESPACE__.'\\Transformer\\'.($relativeNamespace ? $relativeNamespace.'\\' : '').$file->getBasename('.php');
  36329. yield new $class();
  36330. }
  36331. }
  36332. }
  36333. <?php
  36334. namespace PhpCsFixer\Tokenizer;
  36335. use PhpCsFixer\Preg;
  36336. use PhpCsFixer\Utils;
  36337. /**
  36338. @extends
  36339. */
  36340. class Tokens extends \SplFixedArray
  36341. {
  36342. const BLOCK_TYPE_PARENTHESIS_BRACE = 1;
  36343. const BLOCK_TYPE_CURLY_BRACE = 2;
  36344. const BLOCK_TYPE_INDEX_SQUARE_BRACE = 3;
  36345. const BLOCK_TYPE_ARRAY_SQUARE_BRACE = 4;
  36346. const BLOCK_TYPE_DYNAMIC_PROP_BRACE = 5;
  36347. const BLOCK_TYPE_DYNAMIC_VAR_BRACE = 6;
  36348. const BLOCK_TYPE_ARRAY_INDEX_CURLY_BRACE = 7;
  36349. const BLOCK_TYPE_GROUP_IMPORT_BRACE = 8;
  36350. const BLOCK_TYPE_DESTRUCTURING_SQUARE_BRACE = 9;
  36351. const BLOCK_TYPE_BRACE_CLASS_INSTANTIATION = 10;
  36352. private static $cache = [];
  36353. private $blockEndCache = [];
  36354. private $codeHash;
  36355. private $changed = false;
  36356. private $foundTokenKinds = [];
  36357. private static $isLegacyMode = false;
  36358. public function __clone()
  36359. {
  36360. foreach ($this as $key => $val) {
  36361. $this[$key] = clone $val;
  36362. }
  36363. }
  36364. public static function isLegacyMode()
  36365. {
  36366. return self::$isLegacyMode;
  36367. }
  36368. public static function setLegacyMode($isLegacy)
  36369. {
  36370. if (getenv('PHP_CS_FIXER_FUTURE_MODE') && $isLegacy) {
  36371. throw new \RuntimeException('Cannot enable `legacy mode` when using `future mode`. This check was performed as `PHP_CS_FIXER_FUTURE_MODE` env var is set.');
  36372. }
  36373. self::$isLegacyMode = $isLegacy;
  36374. }
  36375. public static function clearCache($key = null)
  36376. {
  36377. if (null === $key) {
  36378. self::$cache = [];
  36379. return;
  36380. }
  36381. if (self::hasCache($key)) {
  36382. unset(self::$cache[$key]);
  36383. }
  36384. }
  36385. public static function detectBlockType(Token $token)
  36386. {
  36387. foreach (self::getBlockEdgeDefinitions() as $type => $definition) {
  36388. if ($token->equals($definition['start'])) {
  36389. return ['type' => $type, 'isStart' => true];
  36390. }
  36391. if ($token->equals($definition['end'])) {
  36392. return ['type' => $type, 'isStart' => false];
  36393. }
  36394. }
  36395. return null;
  36396. }
  36397. public static function fromArray($array, $saveIndexes = null)
  36398. {
  36399. $tokens = new self(\count($array));
  36400. if (null === $saveIndexes || $saveIndexes) {
  36401. foreach ($array as $key => $val) {
  36402. $tokens[$key] = $val;
  36403. }
  36404. } else {
  36405. $index = 0;
  36406. foreach ($array as $val) {
  36407. $tokens[$index++] = $val;
  36408. }
  36409. }
  36410. $tokens->generateCode();
  36411. return $tokens;
  36412. }
  36413. public static function fromCode($code)
  36414. {
  36415. $codeHash = self::calculateCodeHash($code);
  36416. if (self::hasCache($codeHash)) {
  36417. $tokens = self::getCache($codeHash);
  36418. $tokens->generateCode();
  36419. if ($codeHash === $tokens->codeHash) {
  36420. $tokens->clearEmptyTokens();
  36421. $tokens->clearChanged();
  36422. return $tokens;
  36423. }
  36424. }
  36425. $tokens = new self();
  36426. $tokens->setCode($code);
  36427. $tokens->clearChanged();
  36428. return $tokens;
  36429. }
  36430. public static function getBlockEdgeDefinitions()
  36431. {
  36432. return [
  36433. self::BLOCK_TYPE_CURLY_BRACE => [
  36434. 'start' => '{',
  36435. 'end' => '}',
  36436. ],
  36437. self::BLOCK_TYPE_PARENTHESIS_BRACE => [
  36438. 'start' => '(',
  36439. 'end' => ')',
  36440. ],
  36441. self::BLOCK_TYPE_INDEX_SQUARE_BRACE => [
  36442. 'start' => '[',
  36443. 'end' => ']',
  36444. ],
  36445. self::BLOCK_TYPE_ARRAY_SQUARE_BRACE => [
  36446. 'start' => [CT::T_ARRAY_SQUARE_BRACE_OPEN, '['],
  36447. 'end' => [CT::T_ARRAY_SQUARE_BRACE_CLOSE, ']'],
  36448. ],
  36449. self::BLOCK_TYPE_DYNAMIC_PROP_BRACE => [
  36450. 'start' => [CT::T_DYNAMIC_PROP_BRACE_OPEN, '{'],
  36451. 'end' => [CT::T_DYNAMIC_PROP_BRACE_CLOSE, '}'],
  36452. ],
  36453. self::BLOCK_TYPE_DYNAMIC_VAR_BRACE => [
  36454. 'start' => [CT::T_DYNAMIC_VAR_BRACE_OPEN, '{'],
  36455. 'end' => [CT::T_DYNAMIC_VAR_BRACE_CLOSE, '}'],
  36456. ],
  36457. self::BLOCK_TYPE_ARRAY_INDEX_CURLY_BRACE => [
  36458. 'start' => [CT::T_ARRAY_INDEX_CURLY_BRACE_OPEN, '{'],
  36459. 'end' => [CT::T_ARRAY_INDEX_CURLY_BRACE_CLOSE, '}'],
  36460. ],
  36461. self::BLOCK_TYPE_GROUP_IMPORT_BRACE => [
  36462. 'start' => [CT::T_GROUP_IMPORT_BRACE_OPEN, '{'],
  36463. 'end' => [CT::T_GROUP_IMPORT_BRACE_CLOSE, '}'],
  36464. ],
  36465. self::BLOCK_TYPE_DESTRUCTURING_SQUARE_BRACE => [
  36466. 'start' => [CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN, '['],
  36467. 'end' => [CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE, ']'],
  36468. ],
  36469. self::BLOCK_TYPE_BRACE_CLASS_INSTANTIATION => [
  36470. 'start' => [CT::T_BRACE_CLASS_INSTANTIATION_OPEN, '('],
  36471. 'end' => [CT::T_BRACE_CLASS_INSTANTIATION_CLOSE, ')'],
  36472. ],
  36473. ];
  36474. }
  36475. public function setSize($size)
  36476. {
  36477. if ($this->getSize() !== $size) {
  36478. $this->changed = true;
  36479. parent::setSize($size);
  36480. }
  36481. }
  36482. public function offsetUnset($index)
  36483. {
  36484. $this->changed = true;
  36485. $this->unregisterFoundToken($this[$index]);
  36486. parent::offsetUnset($index);
  36487. }
  36488. public function offsetSet($index, $newval)
  36489. {
  36490. $this->blockEndCache = [];
  36491. if (!isset($this[$index]) || !$this[$index]->equals($newval)) {
  36492. $this->changed = true;
  36493. if (isset($this[$index])) {
  36494. $this->unregisterFoundToken($this[$index]);
  36495. }
  36496. $this->registerFoundToken($newval);
  36497. }
  36498. parent::offsetSet($index, $newval);
  36499. }
  36500. public function clearChanged()
  36501. {
  36502. $this->changed = false;
  36503. if (self::isLegacyMode()) {
  36504. foreach ($this as $token) {
  36505. $token->clearChanged();
  36506. }
  36507. }
  36508. }
  36509. public function clearEmptyTokens()
  36510. {
  36511. $limit = $this->count();
  36512. $index = 0;
  36513. for (; $index < $limit; ++$index) {
  36514. if ($this->isEmptyAt($index)) {
  36515. break;
  36516. }
  36517. }
  36518. if ($limit === $index) {
  36519. return;
  36520. }
  36521. for ($count = $index; $index < $limit; ++$index) {
  36522. if (!$this->isEmptyAt($index)) {
  36523. $token = $this[$index];
  36524. $this[$count++] = $token;
  36525. }
  36526. }
  36527. $this->setSize($count);
  36528. }
  36529. public function ensureWhitespaceAtIndex($index, $indexOffset, $whitespace)
  36530. {
  36531. $removeLastCommentLine = static function (self $tokens, $index, $indexOffset, $whitespace) {
  36532. $token = $tokens[$index];
  36533. if (1 === $indexOffset && $token->isGivenKind(T_OPEN_TAG)) {
  36534. if (0 === strpos($whitespace, "\r\n")) {
  36535. $tokens[$index] = new Token([T_OPEN_TAG, rtrim($token->getContent())."\r\n"]);
  36536. return \strlen($whitespace) > 2
  36537. ? substr($whitespace, 2)
  36538. : ''
  36539. ;
  36540. }
  36541. $tokens[$index] = new Token([T_OPEN_TAG, rtrim($token->getContent()).$whitespace[0]]);
  36542. return \strlen($whitespace) > 1
  36543. ? substr($whitespace, 1)
  36544. : ''
  36545. ;
  36546. }
  36547. return $whitespace;
  36548. };
  36549. if ($this[$index]->isWhitespace()) {
  36550. $whitespace = $removeLastCommentLine($this, $index - 1, $indexOffset, $whitespace);
  36551. if ('' === $whitespace) {
  36552. $this->clearAt($index);
  36553. } else {
  36554. $this[$index] = new Token([T_WHITESPACE, $whitespace]);
  36555. }
  36556. return false;
  36557. }
  36558. $whitespace = $removeLastCommentLine($this, $index, $indexOffset, $whitespace);
  36559. if ('' === $whitespace) {
  36560. return false;
  36561. }
  36562. $this->insertAt(
  36563. $index + $indexOffset,
  36564. [
  36565. new Token([T_WHITESPACE, $whitespace]),
  36566. ]
  36567. );
  36568. return true;
  36569. }
  36570. public function findBlockEnd($type, $searchIndex, $findEnd = true)
  36571. {
  36572. if (3 === \func_num_args()) {
  36573. if ($findEnd) {
  36574. @trigger_error('Argument #3 of Tokens::findBlockEnd is deprecated and will be removed in 3.0, you can safely drop the argument.', E_USER_DEPRECATED);
  36575. } else {
  36576. @trigger_error('Argument #3 of Tokens::findBlockEnd is deprecated and will be removed in 3.0, use Tokens::findBlockStart instead.', E_USER_DEPRECATED);
  36577. }
  36578. }
  36579. return $this->findOppositeBlockEdge($type, $searchIndex, $findEnd);
  36580. }
  36581. public function findBlockStart($type, $searchIndex)
  36582. {
  36583. return $this->findOppositeBlockEdge($type, $searchIndex, false);
  36584. }
  36585. public function findGivenKind($possibleKind, $start = 0, $end = null)
  36586. {
  36587. $this->rewind();
  36588. if (null === $end) {
  36589. $end = $this->count();
  36590. }
  36591. $elements = [];
  36592. $possibleKinds = (array) $possibleKind;
  36593. foreach ($possibleKinds as $kind) {
  36594. $elements[$kind] = [];
  36595. }
  36596. if (!self::isLegacyMode()) {
  36597. $possibleKinds = array_filter($possibleKinds, function ($kind) {
  36598. return $this->isTokenKindFound($kind);
  36599. });
  36600. }
  36601. if (\count($possibleKinds)) {
  36602. for ($i = $start; $i < $end; ++$i) {
  36603. $token = $this[$i];
  36604. if ($token->isGivenKind($possibleKinds)) {
  36605. $elements[$token->getId()][$i] = $token;
  36606. }
  36607. }
  36608. }
  36609. return \is_array($possibleKind) ? $elements : $elements[$possibleKind];
  36610. }
  36611. public function generateCode()
  36612. {
  36613. $code = $this->generatePartialCode(0, \count($this) - 1);
  36614. $this->changeCodeHash(self::calculateCodeHash($code));
  36615. return $code;
  36616. }
  36617. public function generatePartialCode($start, $end)
  36618. {
  36619. $code = '';
  36620. for ($i = $start; $i <= $end; ++$i) {
  36621. $code .= $this[$i]->getContent();
  36622. }
  36623. return $code;
  36624. }
  36625. public function getCodeHash()
  36626. {
  36627. return $this->codeHash;
  36628. }
  36629. public function getNextNonWhitespace($index, $whitespaces = null)
  36630. {
  36631. return $this->getNonWhitespaceSibling($index, 1, $whitespaces);
  36632. }
  36633. public function getNextTokenOfKind($index, array $tokens = [], $caseSensitive = true)
  36634. {
  36635. return $this->getTokenOfKindSibling($index, 1, $tokens, $caseSensitive);
  36636. }
  36637. public function getNonWhitespaceSibling($index, $direction, $whitespaces = null)
  36638. {
  36639. while (true) {
  36640. $index += $direction;
  36641. if (!$this->offsetExists($index)) {
  36642. return null;
  36643. }
  36644. $token = $this[$index];
  36645. if (!$token->isWhitespace($whitespaces)) {
  36646. return $index;
  36647. }
  36648. }
  36649. }
  36650. public function getPrevNonWhitespace($index, $whitespaces = null)
  36651. {
  36652. return $this->getNonWhitespaceSibling($index, -1, $whitespaces);
  36653. }
  36654. public function getPrevTokenOfKind($index, array $tokens = [], $caseSensitive = true)
  36655. {
  36656. return $this->getTokenOfKindSibling($index, -1, $tokens, $caseSensitive);
  36657. }
  36658. public function getTokenOfKindSibling($index, $direction, array $tokens = [], $caseSensitive = true)
  36659. {
  36660. if (!self::isLegacyMode()) {
  36661. $tokens = array_filter($tokens, function ($token) {
  36662. return $this->isTokenKindFound($this->extractTokenKind($token));
  36663. });
  36664. }
  36665. if (!\count($tokens)) {
  36666. return null;
  36667. }
  36668. while (true) {
  36669. $index += $direction;
  36670. if (!$this->offsetExists($index)) {
  36671. return null;
  36672. }
  36673. $token = $this[$index];
  36674. if ($token->equalsAny($tokens, $caseSensitive)) {
  36675. return $index;
  36676. }
  36677. }
  36678. }
  36679. public function getTokenNotOfKindSibling($index, $direction, array $tokens = [])
  36680. {
  36681. while (true) {
  36682. $index += $direction;
  36683. if (!$this->offsetExists($index)) {
  36684. return null;
  36685. }
  36686. if ($this->isEmptyAt($index)) {
  36687. continue;
  36688. }
  36689. if ($this[$index]->equalsAny($tokens)) {
  36690. continue;
  36691. }
  36692. return $index;
  36693. }
  36694. }
  36695. public function getMeaningfulTokenSibling($index, $direction)
  36696. {
  36697. return $this->getTokenNotOfKindSibling(
  36698. $index,
  36699. $direction,
  36700. [[T_WHITESPACE], [T_COMMENT], [T_DOC_COMMENT]]
  36701. );
  36702. }
  36703. public function getNonEmptySibling($index, $direction)
  36704. {
  36705. while (true) {
  36706. $index += $direction;
  36707. if (!$this->offsetExists($index)) {
  36708. return null;
  36709. }
  36710. if (!$this->isEmptyAt($index)) {
  36711. return $index;
  36712. }
  36713. }
  36714. }
  36715. public function getNextMeaningfulToken($index)
  36716. {
  36717. return $this->getMeaningfulTokenSibling($index, 1);
  36718. }
  36719. public function getPrevMeaningfulToken($index)
  36720. {
  36721. return $this->getMeaningfulTokenSibling($index, -1);
  36722. }
  36723. public function findSequence(array $sequence, $start = 0, $end = null, $caseSensitive = true)
  36724. {
  36725. $sequenceCount = \count($sequence);
  36726. if (0 === $sequenceCount) {
  36727. throw new \InvalidArgumentException('Invalid sequence.');
  36728. }
  36729. $end = null === $end ? \count($this) - 1 : min($end, \count($this) - 1);
  36730. if ($start + $sequenceCount - 1 > $end) {
  36731. return null;
  36732. }
  36733. foreach ($sequence as $key => $token) {
  36734. if (!$token instanceof Token) {
  36735. if (\is_array($token) && !isset($token[1])) {
  36736. $token[1] = 'DUMMY';
  36737. }
  36738. $token = new Token($token);
  36739. }
  36740. if ($token->isWhitespace() || $token->isComment() || '' === $token->getContent()) {
  36741. throw new \InvalidArgumentException(sprintf('Non-meaningful token at position: "%s".', $key));
  36742. }
  36743. }
  36744. if (!self::isLegacyMode()) {
  36745. foreach ($sequence as $token) {
  36746. if (!$this->isTokenKindFound($this->extractTokenKind($token))) {
  36747. return null;
  36748. }
  36749. }
  36750. }
  36751. $key = key($sequence);
  36752. $firstCs = Token::isKeyCaseSensitive($caseSensitive, $key);
  36753. $firstToken = $sequence[$key];
  36754. unset($sequence[$key]);
  36755. $index = $start - 1;
  36756. while (null !== $index && $index <= $end) {
  36757. $index = $this->getNextTokenOfKind($index, [$firstToken], $firstCs);
  36758. if (null === $index || $index > $end) {
  36759. return null;
  36760. }
  36761. $result = [$index => $this[$index]];
  36762. $currIdx = $index;
  36763. foreach ($sequence as $key => $token) {
  36764. $currIdx = $this->getNextMeaningfulToken($currIdx);
  36765. if (null === $currIdx || $currIdx > $end) {
  36766. return null;
  36767. }
  36768. if (!$this[$currIdx]->equals($token, Token::isKeyCaseSensitive($caseSensitive, $key))) {
  36769. continue 2;
  36770. }
  36771. $result[$currIdx] = $this[$currIdx];
  36772. }
  36773. if (\count($sequence) < \count($result)) {
  36774. return $result;
  36775. }
  36776. }
  36777. return null;
  36778. }
  36779. public function insertAt($index, $items)
  36780. {
  36781. $items = \is_array($items) || $items instanceof self ? $items : [$items];
  36782. $itemsCnt = \count($items);
  36783. if (0 === $itemsCnt) {
  36784. return;
  36785. }
  36786. $oldSize = \count($this);
  36787. $this->changed = true;
  36788. $this->blockEndCache = [];
  36789. $this->setSize($oldSize + $itemsCnt);
  36790. for ($i = $oldSize + $itemsCnt - 1; $i >= $index; --$i) {
  36791. $oldItem = parent::offsetExists($i - $itemsCnt) ? parent::offsetGet($i - $itemsCnt) : new Token('');
  36792. parent::offsetSet($i, $oldItem);
  36793. }
  36794. for ($i = 0; $i < $itemsCnt; ++$i) {
  36795. if ('' === $items[$i]->getContent()) {
  36796. throw new \InvalidArgumentException('Must not add empty token to collection.');
  36797. }
  36798. $this->registerFoundToken($items[$i]);
  36799. parent::offsetSet($i + $index, $items[$i]);
  36800. }
  36801. }
  36802. public function isChanged()
  36803. {
  36804. if ($this->changed) {
  36805. return true;
  36806. }
  36807. if (self::isLegacyMode()) {
  36808. foreach ($this as $token) {
  36809. if ($token->isChanged()) {
  36810. return true;
  36811. }
  36812. }
  36813. }
  36814. return false;
  36815. }
  36816. public function isEmptyAt($index)
  36817. {
  36818. $token = $this[$index];
  36819. return null === $token->getId() && '' === $token->getContent();
  36820. }
  36821. public function clearAt($index)
  36822. {
  36823. $this[$index] = new Token('');
  36824. }
  36825. public function overrideAt($index, $token)
  36826. {
  36827. @trigger_error(__METHOD__.' is deprecated and will be removed in 3.0, use offsetSet instead.', E_USER_DEPRECATED);
  36828. self::$isLegacyMode = true;
  36829. $this[$index]->override($token);
  36830. $this->registerFoundToken($token);
  36831. }
  36832. public function overrideRange($indexStart, $indexEnd, $items)
  36833. {
  36834. $oldCode = $this->generatePartialCode($indexStart, $indexEnd);
  36835. $newCode = '';
  36836. foreach ($items as $item) {
  36837. $newCode .= $item->getContent();
  36838. }
  36839. if ($oldCode === $newCode) {
  36840. return;
  36841. }
  36842. $indexToChange = $indexEnd - $indexStart + 1;
  36843. $itemsCount = \count($items);
  36844. if ($itemsCount > $indexToChange) {
  36845. $placeholders = [];
  36846. while ($itemsCount > $indexToChange) {
  36847. $placeholders[] = new Token('__PLACEHOLDER__');
  36848. ++$indexToChange;
  36849. }
  36850. $this->insertAt($indexEnd + 1, $placeholders);
  36851. }
  36852. foreach ($items as $itemIndex => $item) {
  36853. $this[$indexStart + $itemIndex] = $item;
  36854. }
  36855. if ($itemsCount < $indexToChange) {
  36856. $this->clearRange($indexStart + $itemsCount, $indexEnd);
  36857. }
  36858. }
  36859. public function removeLeadingWhitespace($index, $whitespaces = null)
  36860. {
  36861. $this->removeWhitespaceSafely($index, -1, $whitespaces);
  36862. }
  36863. public function removeTrailingWhitespace($index, $whitespaces = null)
  36864. {
  36865. $this->removeWhitespaceSafely($index, 1, $whitespaces);
  36866. }
  36867. public function setCode($code)
  36868. {
  36869. if ($code === $this->generateCode()) {
  36870. return;
  36871. }
  36872. $this->setSize(0);
  36873. $tokens = \defined('TOKEN_PARSE')
  36874. ? token_get_all($code, TOKEN_PARSE)
  36875. : token_get_all($code);
  36876. $this->setSize(\count($tokens));
  36877. foreach ($tokens as $index => $token) {
  36878. $this[$index] = new Token($token);
  36879. }
  36880. $transformers = Transformers::create();
  36881. $transformers->transform($this);
  36882. $this->foundTokenKinds = [];
  36883. foreach ($this as $token) {
  36884. $this->registerFoundToken($token);
  36885. }
  36886. $this->rewind();
  36887. $this->changeCodeHash(self::calculateCodeHash($code));
  36888. $this->changed = true;
  36889. }
  36890. public function toJson()
  36891. {
  36892. static $options = null;
  36893. if (null === $options) {
  36894. $options = Utils::calculateBitmask(['JSON_PRETTY_PRINT', 'JSON_NUMERIC_CHECK']);
  36895. }
  36896. $output = new \SplFixedArray(\count($this));
  36897. foreach ($this as $index => $token) {
  36898. $output[$index] = $token->toArray();
  36899. }
  36900. $this->rewind();
  36901. return json_encode($output, $options);
  36902. }
  36903. public function isAllTokenKindsFound(array $tokenKinds)
  36904. {
  36905. foreach ($tokenKinds as $tokenKind) {
  36906. if (empty($this->foundTokenKinds[$tokenKind])) {
  36907. return false;
  36908. }
  36909. }
  36910. return true;
  36911. }
  36912. public function isAnyTokenKindsFound(array $tokenKinds)
  36913. {
  36914. foreach ($tokenKinds as $tokenKind) {
  36915. if (!empty($this->foundTokenKinds[$tokenKind])) {
  36916. return true;
  36917. }
  36918. }
  36919. return false;
  36920. }
  36921. public function isTokenKindFound($tokenKind)
  36922. {
  36923. return !empty($this->foundTokenKinds[$tokenKind]);
  36924. }
  36925. public function countTokenKind($tokenKind)
  36926. {
  36927. if (self::isLegacyMode()) {
  36928. throw new \RuntimeException(sprintf('"%s" is not available in legacy mode.', __METHOD__));
  36929. }
  36930. return isset($this->foundTokenKinds[$tokenKind]) ? $this->foundTokenKinds[$tokenKind] : 0;
  36931. }
  36932. public function clearRange($indexStart, $indexEnd)
  36933. {
  36934. for ($i = $indexStart; $i <= $indexEnd; ++$i) {
  36935. $this->clearAt($i);
  36936. }
  36937. }
  36938. public function isMonolithicPhp()
  36939. {
  36940. $size = $this->count();
  36941. if (0 === $size) {
  36942. return false;
  36943. }
  36944. if (self::isLegacyMode()) {
  36945. if ($this[0]->isGivenKind(T_INLINE_HTML) || $this[$size - 1]->isGivenKind(T_INLINE_HTML)) {
  36946. return false;
  36947. }
  36948. for ($index = 1; $index < $size; ++$index) {
  36949. if ($this[$index]->isGivenKind([T_INLINE_HTML, T_OPEN_TAG, T_OPEN_TAG_WITH_ECHO])) {
  36950. return false;
  36951. }
  36952. }
  36953. return true;
  36954. }
  36955. if ($this->isTokenKindFound(T_INLINE_HTML)) {
  36956. return false;
  36957. }
  36958. return 1 >= ($this->countTokenKind(T_OPEN_TAG) + $this->countTokenKind(T_OPEN_TAG_WITH_ECHO));
  36959. }
  36960. public function isPartialCodeMultiline($start, $end)
  36961. {
  36962. for ($i = $start; $i <= $end; ++$i) {
  36963. if (false !== strpos($this[$i]->getContent(), "\n")) {
  36964. return true;
  36965. }
  36966. }
  36967. return false;
  36968. }
  36969. public function clearTokenAndMergeSurroundingWhitespace($index)
  36970. {
  36971. $count = \count($this);
  36972. $this->clearAt($index);
  36973. if ($index === $count - 1) {
  36974. return;
  36975. }
  36976. $nextIndex = $this->getNonEmptySibling($index, 1);
  36977. if (null === $nextIndex || !$this[$nextIndex]->isWhitespace()) {
  36978. return;
  36979. }
  36980. $prevIndex = $this->getNonEmptySibling($index, -1);
  36981. if ($this[$prevIndex]->isWhitespace()) {
  36982. $this[$prevIndex] = new Token([T_WHITESPACE, $this[$prevIndex]->getContent().$this[$nextIndex]->getContent()]);
  36983. } elseif ($this->isEmptyAt($prevIndex + 1)) {
  36984. $this[$prevIndex + 1] = new Token([T_WHITESPACE, $this[$nextIndex]->getContent()]);
  36985. }
  36986. $this->clearAt($nextIndex);
  36987. }
  36988. private function removeWhitespaceSafely($index, $direction, $whitespaces = null)
  36989. {
  36990. $whitespaceIndex = $this->getNonEmptySibling($index, $direction);
  36991. if (isset($this[$whitespaceIndex]) && $this[$whitespaceIndex]->isWhitespace()) {
  36992. $newContent = '';
  36993. $tokenToCheck = $this[$whitespaceIndex];
  36994. if (isset($this[$whitespaceIndex - 1]) && $this[$whitespaceIndex - 1]->isComment() && '/*' !== substr($this[$whitespaceIndex - 1]->getContent(), 0, 2)) {
  36995. list($emptyString, $newContent, $whitespacesToCheck) = Preg::split('/^(\R)/', $this[$whitespaceIndex]->getContent(), -1, PREG_SPLIT_DELIM_CAPTURE);
  36996. if ('' === $whitespacesToCheck) {
  36997. return;
  36998. }
  36999. $tokenToCheck = new Token([T_WHITESPACE, $whitespacesToCheck]);
  37000. }
  37001. if (!$tokenToCheck->isWhitespace($whitespaces)) {
  37002. return;
  37003. }
  37004. if ('' === $newContent) {
  37005. $this->clearAt($whitespaceIndex);
  37006. } else {
  37007. $this[$whitespaceIndex] = new Token([T_WHITESPACE, $newContent]);
  37008. }
  37009. }
  37010. }
  37011. private function findOppositeBlockEdge($type, $searchIndex, $findEnd)
  37012. {
  37013. $blockEdgeDefinitions = self::getBlockEdgeDefinitions();
  37014. if (!isset($blockEdgeDefinitions[$type])) {
  37015. throw new \InvalidArgumentException(sprintf('Invalid param type: "%s".', $type));
  37016. }
  37017. if (!self::isLegacyMode() && isset($this->blockEndCache[$searchIndex])) {
  37018. return $this->blockEndCache[$searchIndex];
  37019. }
  37020. $startEdge = $blockEdgeDefinitions[$type]['start'];
  37021. $endEdge = $blockEdgeDefinitions[$type]['end'];
  37022. $startIndex = $searchIndex;
  37023. $endIndex = $this->count() - 1;
  37024. $indexOffset = 1;
  37025. if (!$findEnd) {
  37026. list($startEdge, $endEdge) = [$endEdge, $startEdge];
  37027. $indexOffset = -1;
  37028. $endIndex = 0;
  37029. }
  37030. if (!$this[$startIndex]->equals($startEdge)) {
  37031. throw new \InvalidArgumentException(sprintf('Invalid param $startIndex - not a proper block "%s".', $findEnd ? 'start' : 'end'));
  37032. }
  37033. $blockLevel = 0;
  37034. for ($index = $startIndex; $index !== $endIndex; $index += $indexOffset) {
  37035. $token = $this[$index];
  37036. if ($token->equals($startEdge)) {
  37037. ++$blockLevel;
  37038. continue;
  37039. }
  37040. if ($token->equals($endEdge)) {
  37041. --$blockLevel;
  37042. if (0 === $blockLevel) {
  37043. break;
  37044. }
  37045. continue;
  37046. }
  37047. }
  37048. if (!$this[$index]->equals($endEdge)) {
  37049. throw new \UnexpectedValueException(sprintf('Missing block "%s".', $findEnd ? 'end' : 'start'));
  37050. }
  37051. $this->blockEndCache[$startIndex] = $index;
  37052. $this->blockEndCache[$index] = $startIndex;
  37053. return $index;
  37054. }
  37055. private static function calculateCodeHash($code)
  37056. {
  37057. return CodeHasher::calculateCodeHash($code);
  37058. }
  37059. private static function getCache($key)
  37060. {
  37061. if (!self::hasCache($key)) {
  37062. throw new \OutOfBoundsException(sprintf('Unknown cache key: "%s".', $key));
  37063. }
  37064. return self::$cache[$key];
  37065. }
  37066. private static function hasCache($key)
  37067. {
  37068. return isset(self::$cache[$key]);
  37069. }
  37070. private static function setCache($key, self $value)
  37071. {
  37072. self::$cache[$key] = $value;
  37073. }
  37074. private function changeCodeHash($codeHash)
  37075. {
  37076. if (null !== $this->codeHash) {
  37077. self::clearCache($this->codeHash);
  37078. }
  37079. $this->codeHash = $codeHash;
  37080. self::setCache($this->codeHash, $this);
  37081. }
  37082. private function registerFoundToken($token)
  37083. {
  37084. $tokenKind = $token instanceof Token
  37085. ? ($token->isArray() ? $token->getId() : $token->getContent())
  37086. : (\is_array($token) ? $token[0] : $token)
  37087. ;
  37088. if (!isset($this->foundTokenKinds[$tokenKind])) {
  37089. $this->foundTokenKinds[$tokenKind] = 0;
  37090. }
  37091. ++$this->foundTokenKinds[$tokenKind];
  37092. }
  37093. private function unregisterFoundToken($token)
  37094. {
  37095. $tokenKind = $token instanceof Token
  37096. ? ($token->isArray() ? $token->getId() : $token->getContent())
  37097. : (\is_array($token) ? $token[0] : $token)
  37098. ;
  37099. if (!isset($this->foundTokenKinds[$tokenKind])) {
  37100. return;
  37101. }
  37102. --$this->foundTokenKinds[$tokenKind];
  37103. }
  37104. private function extractTokenKind($token)
  37105. {
  37106. return $token instanceof Token
  37107. ? ($token->isArray() ? $token->getId() : $token->getContent())
  37108. : (\is_array($token) ? $token[0] : $token)
  37109. ;
  37110. }
  37111. }
  37112. <?php
  37113. namespace PhpCsFixer\Tokenizer;
  37114. use PhpCsFixer\Utils;
  37115. abstract class AbstractTransformer implements TransformerInterface
  37116. {
  37117. public function getName()
  37118. {
  37119. $nameParts = explode('\\', static::class);
  37120. $name = substr(end($nameParts), 0, -\strlen('Transformer'));
  37121. return Utils::camelCaseToUnderscore($name);
  37122. }
  37123. public function getPriority()
  37124. {
  37125. return 0;
  37126. }
  37127. }
  37128. <?php
  37129. namespace PhpCsFixer\Tokenizer;
  37130. final class CT
  37131. {
  37132. const T_ARRAY_INDEX_CURLY_BRACE_CLOSE = 10001;
  37133. const T_ARRAY_INDEX_CURLY_BRACE_OPEN = 10002;
  37134. const T_ARRAY_SQUARE_BRACE_CLOSE = 10003;
  37135. const T_ARRAY_SQUARE_BRACE_OPEN = 10004;
  37136. const T_ARRAY_TYPEHINT = 10005;
  37137. const T_BRACE_CLASS_INSTANTIATION_CLOSE = 10006;
  37138. const T_BRACE_CLASS_INSTANTIATION_OPEN = 10007;
  37139. const T_CLASS_CONSTANT = 10008;
  37140. const T_CONST_IMPORT = 10009;
  37141. const T_CURLY_CLOSE = 10010;
  37142. const T_DESTRUCTURING_SQUARE_BRACE_CLOSE = 10011;
  37143. const T_DESTRUCTURING_SQUARE_BRACE_OPEN = 10012;
  37144. const T_DOLLAR_CLOSE_CURLY_BRACES = 10013;
  37145. const T_DYNAMIC_PROP_BRACE_CLOSE = 10014;
  37146. const T_DYNAMIC_PROP_BRACE_OPEN = 10015;
  37147. const T_DYNAMIC_VAR_BRACE_CLOSE = 10016;
  37148. const T_DYNAMIC_VAR_BRACE_OPEN = 10017;
  37149. const T_FUNCTION_IMPORT = 10018;
  37150. const T_GROUP_IMPORT_BRACE_CLOSE = 10019;
  37151. const T_GROUP_IMPORT_BRACE_OPEN = 10020;
  37152. const T_NAMESPACE_OPERATOR = 10021;
  37153. const T_NULLABLE_TYPE = 10022;
  37154. const T_RETURN_REF = 10023;
  37155. const T_TYPE_ALTERNATION = 10024;
  37156. const T_TYPE_COLON = 10025;
  37157. const T_USE_LAMBDA = 10026;
  37158. const T_USE_TRAIT = 10027;
  37159. private function __construct()
  37160. {
  37161. }
  37162. public static function getName($value)
  37163. {
  37164. if (!self::has($value)) {
  37165. throw new \InvalidArgumentException(sprintf('No custom token was found for "%s".', $value));
  37166. }
  37167. $tokens = self::getMapById();
  37168. return 'CT::'.$tokens[$value];
  37169. }
  37170. public static function has($value)
  37171. {
  37172. $tokens = self::getMapById();
  37173. return isset($tokens[$value]);
  37174. }
  37175. private static function getMapById()
  37176. {
  37177. static $constants;
  37178. if (null === $constants) {
  37179. $reflection = new \ReflectionClass(__CLASS__);
  37180. $constants = array_flip($reflection->getConstants());
  37181. }
  37182. return $constants;
  37183. }
  37184. }
  37185. <?php
  37186. namespace PhpCsFixer;
  37187. use PhpCsFixer\ConfigurationException\InvalidFixerConfigurationException;
  37188. use PhpCsFixer\ConfigurationException\InvalidForEnvFixerConfigurationException;
  37189. use PhpCsFixer\ConfigurationException\RequiredFixerConfigurationException;
  37190. use PhpCsFixer\Console\Application;
  37191. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  37192. use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
  37193. use PhpCsFixer\Fixer\DefinedFixerInterface;
  37194. use PhpCsFixer\Fixer\FixerInterface;
  37195. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  37196. use PhpCsFixer\FixerConfiguration\DeprecatedFixerOption;
  37197. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  37198. use PhpCsFixer\FixerConfiguration\InvalidOptionsForEnvException;
  37199. use PhpCsFixer\Tokenizer\Tokens;
  37200. use Symfony\Component\OptionsResolver\Exception\ExceptionInterface;
  37201. use Symfony\Component\OptionsResolver\Exception\MissingOptionsException;
  37202. abstract class AbstractFixer implements FixerInterface, DefinedFixerInterface
  37203. {
  37204. protected $configuration;
  37205. protected $whitespacesConfig;
  37206. private $configurationDefinition;
  37207. public function __construct()
  37208. {
  37209. if ($this instanceof ConfigurableFixerInterface) {
  37210. try {
  37211. $this->configure([]);
  37212. } catch (RequiredFixerConfigurationException $e) {
  37213. }
  37214. }
  37215. if ($this instanceof WhitespacesAwareFixerInterface) {
  37216. $this->whitespacesConfig = $this->getDefaultWhitespacesFixerConfig();
  37217. }
  37218. }
  37219. final public function fix(\SplFileInfo $file, Tokens $tokens)
  37220. {
  37221. if ($this instanceof ConfigurableFixerInterface && null === $this->configuration) {
  37222. throw new RequiredFixerConfigurationException($this->getName(), 'Configuration is required.');
  37223. }
  37224. if (0 < $tokens->count() && $this->isCandidate($tokens) && $this->supports($file)) {
  37225. $this->applyFix($file, $tokens);
  37226. }
  37227. }
  37228. public function isRisky()
  37229. {
  37230. return false;
  37231. }
  37232. public function getName()
  37233. {
  37234. $nameParts = explode('\\', static::class);
  37235. $name = substr(end($nameParts), 0, -\strlen('Fixer'));
  37236. return Utils::camelCaseToUnderscore($name);
  37237. }
  37238. public function getPriority()
  37239. {
  37240. return 0;
  37241. }
  37242. public function supports(\SplFileInfo $file)
  37243. {
  37244. return true;
  37245. }
  37246. public function configure(array $configuration = null)
  37247. {
  37248. if (!$this instanceof ConfigurationDefinitionFixerInterface) {
  37249. throw new \LogicException('Cannot configure using Abstract parent, child not implementing "PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface".');
  37250. }
  37251. if (null === $configuration) {
  37252. $message = 'Passing NULL to set default configuration is deprecated and will not be supported in 3.0, use an empty array instead.';
  37253. if (getenv('PHP_CS_FIXER_FUTURE_MODE')) {
  37254. throw new \InvalidArgumentException("{$message} This check was performed as `PHP_CS_FIXER_FUTURE_MODE` env var is set.");
  37255. }
  37256. @trigger_error($message, E_USER_DEPRECATED);
  37257. $configuration = [];
  37258. }
  37259. foreach ($this->getConfigurationDefinition()->getOptions() as $option) {
  37260. if (!$option instanceof DeprecatedFixerOption) {
  37261. continue;
  37262. }
  37263. $name = $option->getName();
  37264. if (\array_key_exists($name, $configuration)) {
  37265. $message = sprintf(
  37266. 'Option "%s" for rule "%s" is deprecated and will be removed in version %d.0. %s',
  37267. $name,
  37268. $this->getName(),
  37269. Application::getMajorVersion() + 1,
  37270. str_replace('`', '"', $option->getDeprecationMessage())
  37271. );
  37272. if (getenv('PHP_CS_FIXER_FUTURE_MODE')) {
  37273. throw new \InvalidArgumentException("{$message} This check was performed as `PHP_CS_FIXER_FUTURE_MODE` env var is set.");
  37274. }
  37275. @trigger_error($message, E_USER_DEPRECATED);
  37276. }
  37277. }
  37278. try {
  37279. $this->configuration = $this->getConfigurationDefinition()->resolve($configuration);
  37280. } catch (MissingOptionsException $exception) {
  37281. throw new RequiredFixerConfigurationException(
  37282. $this->getName(),
  37283. sprintf('Missing required configuration: %s', $exception->getMessage()),
  37284. $exception
  37285. );
  37286. } catch (InvalidOptionsForEnvException $exception) {
  37287. throw new InvalidForEnvFixerConfigurationException(
  37288. $this->getName(),
  37289. sprintf('Invalid configuration for env: %s', $exception->getMessage()),
  37290. $exception
  37291. );
  37292. } catch (ExceptionInterface $exception) {
  37293. throw new InvalidFixerConfigurationException(
  37294. $this->getName(),
  37295. sprintf('Invalid configuration: %s', $exception->getMessage()),
  37296. $exception
  37297. );
  37298. }
  37299. }
  37300. public function getConfigurationDefinition()
  37301. {
  37302. if (!$this instanceof ConfigurationDefinitionFixerInterface) {
  37303. throw new \LogicException('Cannot get configuration definition using Abstract parent, child not implementing "PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface".');
  37304. }
  37305. if (null === $this->configurationDefinition) {
  37306. $this->configurationDefinition = $this->createConfigurationDefinition();
  37307. }
  37308. return $this->configurationDefinition;
  37309. }
  37310. public function setWhitespacesConfig(WhitespacesFixerConfig $config)
  37311. {
  37312. if (!$this instanceof WhitespacesAwareFixerInterface) {
  37313. throw new \LogicException('Cannot run method for class not implementing "PhpCsFixer\Fixer\WhitespacesAwareFixerInterface".');
  37314. }
  37315. $this->whitespacesConfig = $config;
  37316. }
  37317. abstract protected function applyFix(\SplFileInfo $file, Tokens $tokens);
  37318. protected function createConfigurationDefinition()
  37319. {
  37320. if (!$this instanceof ConfigurationDefinitionFixerInterface) {
  37321. throw new \LogicException('Cannot create configuration definition using Abstract parent, child not implementing "PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface".');
  37322. }
  37323. throw new \LogicException('Not implemented.');
  37324. }
  37325. private function getDefaultWhitespacesFixerConfig()
  37326. {
  37327. static $defaultWhitespacesFixerConfig = null;
  37328. if (null === $defaultWhitespacesFixerConfig) {
  37329. $defaultWhitespacesFixerConfig = new WhitespacesFixerConfig(' ', "\n");
  37330. }
  37331. return $defaultWhitespacesFixerConfig;
  37332. }
  37333. }
  37334. <?php
  37335. namespace PhpCsFixer;
  37336. final class FileReader
  37337. {
  37338. private static $instance;
  37339. private $stdinContent;
  37340. public static function createSingleton()
  37341. {
  37342. if (null === self::$instance) {
  37343. self::$instance = new self();
  37344. }
  37345. return self::$instance;
  37346. }
  37347. public function read($filePath)
  37348. {
  37349. if ('php://stdin' === $filePath) {
  37350. if (null === $this->stdinContent) {
  37351. $this->stdinContent = $this->readRaw($filePath);
  37352. }
  37353. return $this->stdinContent;
  37354. }
  37355. return $this->readRaw($filePath);
  37356. }
  37357. private function readRaw($realPath)
  37358. {
  37359. $content = @file_get_contents($realPath);
  37360. if (false === $content) {
  37361. $error = error_get_last();
  37362. throw new \RuntimeException(sprintf(
  37363. 'Failed to read content from "%s".%s',
  37364. $realPath,
  37365. $error ? ' '.$error['message'] : ''
  37366. ));
  37367. }
  37368. return $content;
  37369. }
  37370. }
  37371. <?php
  37372. namespace PhpCsFixer\Cache;
  37373. interface DirectoryInterface
  37374. {
  37375. public function getRelativePathTo($file);
  37376. }
  37377. <?php
  37378. namespace PhpCsFixer\Cache;
  37379. use Symfony\Component\Filesystem\Exception\IOException;
  37380. final class FileHandler implements FileHandlerInterface
  37381. {
  37382. private $file;
  37383. public function __construct($file)
  37384. {
  37385. $this->file = $file;
  37386. }
  37387. public function getFile()
  37388. {
  37389. return $this->file;
  37390. }
  37391. public function read()
  37392. {
  37393. if (!file_exists($this->file)) {
  37394. return null;
  37395. }
  37396. $content = file_get_contents($this->file);
  37397. try {
  37398. $cache = Cache::fromJson($content);
  37399. } catch (\InvalidArgumentException $exception) {
  37400. return null;
  37401. }
  37402. return $cache;
  37403. }
  37404. public function write(CacheInterface $cache)
  37405. {
  37406. $content = $cache->toJson();
  37407. if (file_exists($this->file)) {
  37408. if (is_dir($this->file)) {
  37409. throw new IOException(
  37410. sprintf('Cannot write cache file "%s" as the location exists as directory.', realpath($this->file)),
  37411. 0,
  37412. null,
  37413. $this->file
  37414. );
  37415. }
  37416. if (!is_writable($this->file)) {
  37417. throw new IOException(
  37418. sprintf('Cannot write to file "%s" as it is not writable.', realpath($this->file)),
  37419. 0,
  37420. null,
  37421. $this->file
  37422. );
  37423. }
  37424. } else {
  37425. @touch($this->file);
  37426. @chmod($this->file, 0666);
  37427. }
  37428. $bytesWritten = @file_put_contents($this->file, $content);
  37429. if (false === $bytesWritten) {
  37430. $error = error_get_last();
  37431. throw new IOException(
  37432. sprintf('Failed to write file "%s", "%s".', $this->file, isset($error['message']) ? $error['message'] : 'no reason available'),
  37433. 0,
  37434. null,
  37435. $this->file
  37436. );
  37437. }
  37438. }
  37439. }
  37440. <?php
  37441. namespace PhpCsFixer\Cache;
  37442. interface CacheInterface
  37443. {
  37444. public function getSignature();
  37445. public function has($file);
  37446. public function get($file);
  37447. public function set($file, $hash);
  37448. public function clear($file);
  37449. public function toJson();
  37450. }
  37451. <?php
  37452. namespace PhpCsFixer\Cache;
  37453. final class Directory implements DirectoryInterface
  37454. {
  37455. private $directoryName;
  37456. public function __construct($directoryName)
  37457. {
  37458. $this->directoryName = $directoryName;
  37459. }
  37460. public function getRelativePathTo($file)
  37461. {
  37462. $file = $this->normalizePath($file);
  37463. if (
  37464. '' === $this->directoryName
  37465. || 0 !== stripos($file, $this->directoryName.\DIRECTORY_SEPARATOR)
  37466. ) {
  37467. return $file;
  37468. }
  37469. return substr($file, \strlen($this->directoryName) + 1);
  37470. }
  37471. private function normalizePath($path)
  37472. {
  37473. return str_replace(['\\', '/'], \DIRECTORY_SEPARATOR, $path);
  37474. }
  37475. }
  37476. <?php
  37477. namespace PhpCsFixer\Cache;
  37478. interface FileHandlerInterface
  37479. {
  37480. public function getFile();
  37481. public function read();
  37482. public function write(CacheInterface $cache);
  37483. }
  37484. <?php
  37485. namespace PhpCsFixer\Cache;
  37486. final class Cache implements CacheInterface
  37487. {
  37488. private $signature;
  37489. private $hashes = [];
  37490. public function __construct(SignatureInterface $signature)
  37491. {
  37492. $this->signature = $signature;
  37493. }
  37494. public function getSignature()
  37495. {
  37496. return $this->signature;
  37497. }
  37498. public function has($file)
  37499. {
  37500. return \array_key_exists($file, $this->hashes);
  37501. }
  37502. public function get($file)
  37503. {
  37504. if (!$this->has($file)) {
  37505. return null;
  37506. }
  37507. return $this->hashes[$file];
  37508. }
  37509. public function set($file, $hash)
  37510. {
  37511. $this->hashes[$file] = $hash;
  37512. }
  37513. public function clear($file)
  37514. {
  37515. unset($this->hashes[$file]);
  37516. }
  37517. public function toJson()
  37518. {
  37519. $json = json_encode([
  37520. 'php' => $this->getSignature()->getPhpVersion(),
  37521. 'version' => $this->getSignature()->getFixerVersion(),
  37522. 'indent' => $this->getSignature()->getIndent(),
  37523. 'lineEnding' => $this->getSignature()->getLineEnding(),
  37524. 'rules' => $this->getSignature()->getRules(),
  37525. 'hashes' => $this->hashes,
  37526. ]);
  37527. if (JSON_ERROR_NONE !== json_last_error()) {
  37528. throw new \UnexpectedValueException(sprintf(
  37529. 'Can not 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`.',
  37530. json_last_error_msg()
  37531. ));
  37532. }
  37533. return $json;
  37534. }
  37535. public static function fromJson($json)
  37536. {
  37537. $data = json_decode($json, true);
  37538. if (null === $data && JSON_ERROR_NONE !== json_last_error()) {
  37539. throw new \InvalidArgumentException(sprintf(
  37540. 'Value needs to be a valid JSON string, got "%s", error: "%s".',
  37541. $json,
  37542. json_last_error_msg()
  37543. ));
  37544. }
  37545. $requiredKeys = [
  37546. 'php',
  37547. 'version',
  37548. 'indent',
  37549. 'lineEnding',
  37550. 'rules',
  37551. 'hashes',
  37552. ];
  37553. $missingKeys = array_diff_key(array_flip($requiredKeys), $data);
  37554. if (\count($missingKeys)) {
  37555. throw new \InvalidArgumentException(sprintf(
  37556. 'JSON data is missing keys "%s"',
  37557. implode('", "', $missingKeys)
  37558. ));
  37559. }
  37560. $signature = new Signature(
  37561. $data['php'],
  37562. $data['version'],
  37563. $data['indent'],
  37564. $data['lineEnding'],
  37565. $data['rules']
  37566. );
  37567. $cache = new self($signature);
  37568. $cache->hashes = $data['hashes'];
  37569. return $cache;
  37570. }
  37571. }
  37572. <?php
  37573. namespace PhpCsFixer\Cache;
  37574. final class Signature implements SignatureInterface
  37575. {
  37576. private $phpVersion;
  37577. private $fixerVersion;
  37578. private $indent;
  37579. private $lineEnding;
  37580. private $rules;
  37581. public function __construct($phpVersion, $fixerVersion, $indent, $lineEnding, array $rules)
  37582. {
  37583. $this->phpVersion = $phpVersion;
  37584. $this->fixerVersion = $fixerVersion;
  37585. $this->indent = $indent;
  37586. $this->lineEnding = $lineEnding;
  37587. $this->rules = self::utf8Encode($rules);
  37588. }
  37589. public function getPhpVersion()
  37590. {
  37591. return $this->phpVersion;
  37592. }
  37593. public function getFixerVersion()
  37594. {
  37595. return $this->fixerVersion;
  37596. }
  37597. public function getIndent()
  37598. {
  37599. return $this->indent;
  37600. }
  37601. public function getLineEnding()
  37602. {
  37603. return $this->lineEnding;
  37604. }
  37605. public function getRules()
  37606. {
  37607. return $this->rules;
  37608. }
  37609. public function equals(SignatureInterface $signature)
  37610. {
  37611. return $this->phpVersion === $signature->getPhpVersion()
  37612. && $this->fixerVersion === $signature->getFixerVersion()
  37613. && $this->indent === $signature->getIndent()
  37614. && $this->lineEnding === $signature->getLineEnding()
  37615. && $this->rules === $signature->getRules();
  37616. }
  37617. private static function utf8Encode(array $data)
  37618. {
  37619. if (!\function_exists('mb_detect_encoding')) {
  37620. return $data;
  37621. }
  37622. array_walk_recursive($data, static function (&$item) {
  37623. if (\is_string($item) && !mb_detect_encoding($item, 'utf-8', true)) {
  37624. $item = utf8_encode($item);
  37625. }
  37626. });
  37627. return $data;
  37628. }
  37629. }
  37630. <?php
  37631. namespace PhpCsFixer\Cache;
  37632. interface SignatureInterface
  37633. {
  37634. public function getPhpVersion();
  37635. public function getFixerVersion();
  37636. public function getIndent();
  37637. public function getLineEnding();
  37638. public function getRules();
  37639. public function equals(self $signature);
  37640. }
  37641. <?php
  37642. namespace PhpCsFixer\Cache;
  37643. final class FileCacheManager implements CacheManagerInterface
  37644. {
  37645. private $handler;
  37646. private $signature;
  37647. private $cache;
  37648. private $isDryRun;
  37649. private $cacheDirectory;
  37650. public function __construct(
  37651. FileHandlerInterface $handler,
  37652. SignatureInterface $signature,
  37653. $isDryRun = false,
  37654. DirectoryInterface $cacheDirectory = null
  37655. ) {
  37656. $this->handler = $handler;
  37657. $this->signature = $signature;
  37658. $this->isDryRun = $isDryRun;
  37659. $this->cacheDirectory = $cacheDirectory ?: new Directory('');
  37660. $this->readCache();
  37661. }
  37662. public function __destruct()
  37663. {
  37664. $this->writeCache();
  37665. }
  37666. public function needFixing($file, $fileContent)
  37667. {
  37668. $file = $this->cacheDirectory->getRelativePathTo($file);
  37669. return !$this->cache->has($file) || $this->cache->get($file) !== $this->calcHash($fileContent);
  37670. }
  37671. public function setFile($file, $fileContent)
  37672. {
  37673. $file = $this->cacheDirectory->getRelativePathTo($file);
  37674. $hash = $this->calcHash($fileContent);
  37675. if ($this->isDryRun && $this->cache->has($file) && $this->cache->get($file) !== $hash) {
  37676. $this->cache->clear($file);
  37677. return;
  37678. }
  37679. $this->cache->set($file, $hash);
  37680. }
  37681. private function readCache()
  37682. {
  37683. $cache = $this->handler->read();
  37684. if (!$cache || !$this->signature->equals($cache->getSignature())) {
  37685. $cache = new Cache($this->signature);
  37686. }
  37687. $this->cache = $cache;
  37688. }
  37689. private function writeCache()
  37690. {
  37691. $this->handler->write($this->cache);
  37692. }
  37693. private function calcHash($content)
  37694. {
  37695. return crc32($content);
  37696. }
  37697. }
  37698. <?php
  37699. namespace PhpCsFixer\Cache;
  37700. interface CacheManagerInterface
  37701. {
  37702. public function needFixing($file, $fileContent);
  37703. public function setFile($file, $fileContent);
  37704. }
  37705. <?php
  37706. namespace PhpCsFixer\Cache;
  37707. final class NullCacheManager implements CacheManagerInterface
  37708. {
  37709. public function needFixing($file, $fileContent)
  37710. {
  37711. return true;
  37712. }
  37713. public function setFile($file, $fileContent)
  37714. {
  37715. }
  37716. }
  37717. #!/bin/sh
  37718. set -eu
  37719. IFS='
  37720. '
  37721. CHANGED_FILES=$(git diff --name-only --diff-filter=ACMRTUXB "${COMMIT_RANGE}")
  37722. if ! echo "${CHANGED_FILES}" | grep -qE "^(\\.php_cs(\\.dist)?|composer\\.lock)$"; then EXTRA_ARGS=$(printf -- '--path-mode=intersection\n--\n%s' "${CHANGED_FILES}"); else EXTRA_ARGS=''; fi
  37723. vendor/bin/php-cs-fixer fix --config=.php_cs.dist -v --dry-run --stop-on-violation --using-cache=no ${EXTRA_ARGS}
  37724. <?php
  37725. namespace Symfony\Component\Filesystem;
  37726. use Symfony\Component\Filesystem\Exception\FileNotFoundException;
  37727. use Symfony\Component\Filesystem\Exception\IOException;
  37728. class Filesystem
  37729. {
  37730. private static $lastError;
  37731. public function copy($originFile, $targetFile, $overwriteNewerFiles = false)
  37732. {
  37733. $originIsLocal = stream_is_local($originFile) || 0 === stripos($originFile, 'file://');
  37734. if ($originIsLocal && !is_file($originFile)) {
  37735. throw new FileNotFoundException(sprintf('Failed to copy "%s" because file does not exist.', $originFile), 0, null, $originFile);
  37736. }
  37737. $this->mkdir(\dirname($targetFile));
  37738. $doCopy = true;
  37739. if (!$overwriteNewerFiles && null === parse_url($originFile, PHP_URL_HOST) && is_file($targetFile)) {
  37740. $doCopy = filemtime($originFile) > filemtime($targetFile);
  37741. }
  37742. if ($doCopy) {
  37743. if (false === $source = @fopen($originFile, 'r')) {
  37744. throw new IOException(sprintf('Failed to copy "%s" to "%s" because source file could not be opened for reading.', $originFile, $targetFile), 0, null, $originFile);
  37745. }
  37746. if (false === $target = @fopen($targetFile, 'w', null, stream_context_create(['ftp' => ['overwrite' => true]]))) {
  37747. throw new IOException(sprintf('Failed to copy "%s" to "%s" because target file could not be opened for writing.', $originFile, $targetFile), 0, null, $originFile);
  37748. }
  37749. $bytesCopied = stream_copy_to_stream($source, $target);
  37750. fclose($source);
  37751. fclose($target);
  37752. unset($source, $target);
  37753. if (!is_file($targetFile)) {
  37754. throw new IOException(sprintf('Failed to copy "%s" to "%s".', $originFile, $targetFile), 0, null, $originFile);
  37755. }
  37756. if ($originIsLocal) {
  37757. @chmod($targetFile, fileperms($targetFile) | (fileperms($originFile) & 0111));
  37758. if ($bytesCopied !== $bytesOrigin = filesize($originFile)) {
  37759. 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);
  37760. }
  37761. }
  37762. }
  37763. }
  37764. public function mkdir($dirs, $mode = 0777)
  37765. {
  37766. foreach ($this->toIterable($dirs) as $dir) {
  37767. if (is_dir($dir)) {
  37768. continue;
  37769. }
  37770. if (!self::box('mkdir', $dir, $mode, true)) {
  37771. if (!is_dir($dir)) {
  37772. if (self::$lastError) {
  37773. throw new IOException(sprintf('Failed to create "%s": ', $dir).self::$lastError, 0, null, $dir);
  37774. }
  37775. throw new IOException(sprintf('Failed to create "%s".', $dir), 0, null, $dir);
  37776. }
  37777. }
  37778. }
  37779. }
  37780. public function exists($files)
  37781. {
  37782. $maxPathLength = PHP_MAXPATHLEN - 2;
  37783. foreach ($this->toIterable($files) as $file) {
  37784. if (\strlen($file) > $maxPathLength) {
  37785. throw new IOException(sprintf('Could not check if file exist because path length exceeds %d characters.', $maxPathLength), 0, null, $file);
  37786. }
  37787. if (!file_exists($file)) {
  37788. return false;
  37789. }
  37790. }
  37791. return true;
  37792. }
  37793. public function touch($files, $time = null, $atime = null)
  37794. {
  37795. foreach ($this->toIterable($files) as $file) {
  37796. $touch = $time ? @touch($file, $time, $atime) : @touch($file);
  37797. if (true !== $touch) {
  37798. throw new IOException(sprintf('Failed to touch "%s".', $file), 0, null, $file);
  37799. }
  37800. }
  37801. }
  37802. public function remove($files)
  37803. {
  37804. if ($files instanceof \Traversable) {
  37805. $files = iterator_to_array($files, false);
  37806. } elseif (!\is_array($files)) {
  37807. $files = [$files];
  37808. }
  37809. $files = array_reverse($files);
  37810. foreach ($files as $file) {
  37811. if (is_link($file)) {
  37812. if (!(self::box('unlink', $file) || '\\' !== \DIRECTORY_SEPARATOR || self::box('rmdir', $file)) && file_exists($file)) {
  37813. throw new IOException(sprintf('Failed to remove symlink "%s": ', $file).self::$lastError);
  37814. }
  37815. } elseif (is_dir($file)) {
  37816. $this->remove(new \FilesystemIterator($file, \FilesystemIterator::CURRENT_AS_PATHNAME | \FilesystemIterator::SKIP_DOTS));
  37817. if (!self::box('rmdir', $file) && file_exists($file)) {
  37818. throw new IOException(sprintf('Failed to remove directory "%s": ', $file).self::$lastError);
  37819. }
  37820. } elseif (!self::box('unlink', $file) && file_exists($file)) {
  37821. throw new IOException(sprintf('Failed to remove file "%s": ', $file).self::$lastError);
  37822. }
  37823. }
  37824. }
  37825. public function chmod($files, $mode, $umask = 0000, $recursive = false)
  37826. {
  37827. foreach ($this->toIterable($files) as $file) {
  37828. if (true !== @chmod($file, $mode & ~$umask)) {
  37829. throw new IOException(sprintf('Failed to chmod file "%s".', $file), 0, null, $file);
  37830. }
  37831. if ($recursive && is_dir($file) && !is_link($file)) {
  37832. $this->chmod(new \FilesystemIterator($file), $mode, $umask, true);
  37833. }
  37834. }
  37835. }
  37836. public function chown($files, $user, $recursive = false)
  37837. {
  37838. foreach ($this->toIterable($files) as $file) {
  37839. if ($recursive && is_dir($file) && !is_link($file)) {
  37840. $this->chown(new \FilesystemIterator($file), $user, true);
  37841. }
  37842. if (is_link($file) && \function_exists('lchown')) {
  37843. if (true !== @lchown($file, $user)) {
  37844. throw new IOException(sprintf('Failed to chown file "%s".', $file), 0, null, $file);
  37845. }
  37846. } else {
  37847. if (true !== @chown($file, $user)) {
  37848. throw new IOException(sprintf('Failed to chown file "%s".', $file), 0, null, $file);
  37849. }
  37850. }
  37851. }
  37852. }
  37853. public function chgrp($files, $group, $recursive = false)
  37854. {
  37855. foreach ($this->toIterable($files) as $file) {
  37856. if ($recursive && is_dir($file) && !is_link($file)) {
  37857. $this->chgrp(new \FilesystemIterator($file), $group, true);
  37858. }
  37859. if (is_link($file) && \function_exists('lchgrp')) {
  37860. if (true !== @lchgrp($file, $group) || (\defined('HHVM_VERSION') && !posix_getgrnam($group))) {
  37861. throw new IOException(sprintf('Failed to chgrp file "%s".', $file), 0, null, $file);
  37862. }
  37863. } else {
  37864. if (true !== @chgrp($file, $group)) {
  37865. throw new IOException(sprintf('Failed to chgrp file "%s".', $file), 0, null, $file);
  37866. }
  37867. }
  37868. }
  37869. }
  37870. public function rename($origin, $target, $overwrite = false)
  37871. {
  37872. if (!$overwrite && $this->isReadable($target)) {
  37873. throw new IOException(sprintf('Cannot rename because the target "%s" already exists.', $target), 0, null, $target);
  37874. }
  37875. if (true !== @rename($origin, $target)) {
  37876. if (is_dir($origin)) {
  37877. $this->mirror($origin, $target, null, ['override' => $overwrite, 'delete' => $overwrite]);
  37878. $this->remove($origin);
  37879. return;
  37880. }
  37881. throw new IOException(sprintf('Cannot rename "%s" to "%s".', $origin, $target), 0, null, $target);
  37882. }
  37883. }
  37884. private function isReadable($filename)
  37885. {
  37886. $maxPathLength = PHP_MAXPATHLEN - 2;
  37887. if (\strlen($filename) > $maxPathLength) {
  37888. throw new IOException(sprintf('Could not check if file is readable because path length exceeds %d characters.', $maxPathLength), 0, null, $filename);
  37889. }
  37890. return is_readable($filename);
  37891. }
  37892. public function symlink($originDir, $targetDir, $copyOnWindows = false)
  37893. {
  37894. if ('\\' === \DIRECTORY_SEPARATOR) {
  37895. $originDir = strtr($originDir, '/', '\\');
  37896. $targetDir = strtr($targetDir, '/', '\\');
  37897. if ($copyOnWindows) {
  37898. $this->mirror($originDir, $targetDir);
  37899. return;
  37900. }
  37901. }
  37902. $this->mkdir(\dirname($targetDir));
  37903. if (is_link($targetDir)) {
  37904. if (readlink($targetDir) === $originDir) {
  37905. return;
  37906. }
  37907. $this->remove($targetDir);
  37908. }
  37909. if (!self::box('symlink', $originDir, $targetDir)) {
  37910. $this->linkException($originDir, $targetDir, 'symbolic');
  37911. }
  37912. }
  37913. public function hardlink($originFile, $targetFiles)
  37914. {
  37915. if (!$this->exists($originFile)) {
  37916. throw new FileNotFoundException(null, 0, null, $originFile);
  37917. }
  37918. if (!is_file($originFile)) {
  37919. throw new FileNotFoundException(sprintf('Origin file "%s" is not a file.', $originFile));
  37920. }
  37921. foreach ($this->toIterable($targetFiles) as $targetFile) {
  37922. if (is_file($targetFile)) {
  37923. if (fileinode($originFile) === fileinode($targetFile)) {
  37924. continue;
  37925. }
  37926. $this->remove($targetFile);
  37927. }
  37928. if (!self::box('link', $originFile, $targetFile)) {
  37929. $this->linkException($originFile, $targetFile, 'hard');
  37930. }
  37931. }
  37932. }
  37933. private function linkException($origin, $target, $linkType)
  37934. {
  37935. if (self::$lastError) {
  37936. if ('\\' === \DIRECTORY_SEPARATOR && false !== strpos(self::$lastError, 'error code(1314)')) {
  37937. 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);
  37938. }
  37939. }
  37940. throw new IOException(sprintf('Failed to create "%s" link from "%s" to "%s".', $linkType, $origin, $target), 0, null, $target);
  37941. }
  37942. public function readlink($path, $canonicalize = false)
  37943. {
  37944. if (!$canonicalize && !is_link($path)) {
  37945. return null;
  37946. }
  37947. if ($canonicalize) {
  37948. if (!$this->exists($path)) {
  37949. return null;
  37950. }
  37951. if ('\\' === \DIRECTORY_SEPARATOR) {
  37952. $path = readlink($path);
  37953. }
  37954. return realpath($path);
  37955. }
  37956. if ('\\' === \DIRECTORY_SEPARATOR) {
  37957. return realpath($path);
  37958. }
  37959. return readlink($path);
  37960. }
  37961. public function makePathRelative($endPath, $startPath)
  37962. {
  37963. if (!$this->isAbsolutePath($endPath) || !$this->isAbsolutePath($startPath)) {
  37964. @trigger_error(sprintf('Support for passing relative paths to %s() is deprecated since Symfony 3.4 and will be removed in 4.0.', __METHOD__), E_USER_DEPRECATED);
  37965. }
  37966. if ('\\' === \DIRECTORY_SEPARATOR) {
  37967. $endPath = str_replace('\\', '/', $endPath);
  37968. $startPath = str_replace('\\', '/', $startPath);
  37969. }
  37970. $splitDriveLetter = function ($path) {
  37971. return (\strlen($path) > 2 && ':' === $path[1] && '/' === $path[2] && ctype_alpha($path[0]))
  37972. ? [substr($path, 2), strtoupper($path[0])]
  37973. : [$path, null];
  37974. };
  37975. $splitPath = function ($path, $absolute) {
  37976. $result = [];
  37977. foreach (explode('/', trim($path, '/')) as $segment) {
  37978. if ('..' === $segment && ($absolute || \count($result))) {
  37979. array_pop($result);
  37980. } elseif ('.' !== $segment && '' !== $segment) {
  37981. $result[] = $segment;
  37982. }
  37983. }
  37984. return $result;
  37985. };
  37986. list($endPath, $endDriveLetter) = $splitDriveLetter($endPath);
  37987. list($startPath, $startDriveLetter) = $splitDriveLetter($startPath);
  37988. $startPathArr = $splitPath($startPath, static::isAbsolutePath($startPath));
  37989. $endPathArr = $splitPath($endPath, static::isAbsolutePath($endPath));
  37990. if ($endDriveLetter && $startDriveLetter && $endDriveLetter != $startDriveLetter) {
  37991. return $endDriveLetter.':/'.($endPathArr ? implode('/', $endPathArr).'/' : '');
  37992. }
  37993. $index = 0;
  37994. while (isset($startPathArr[$index]) && isset($endPathArr[$index]) && $startPathArr[$index] === $endPathArr[$index]) {
  37995. ++$index;
  37996. }
  37997. if (1 === \count($startPathArr) && '' === $startPathArr[0]) {
  37998. $depth = 0;
  37999. } else {
  38000. $depth = \count($startPathArr) - $index;
  38001. }
  38002. $traverser = str_repeat('../', $depth);
  38003. $endPathRemainder = implode('/', \array_slice($endPathArr, $index));
  38004. $relativePath = $traverser.('' !== $endPathRemainder ? $endPathRemainder.'/' : '');
  38005. return '' === $relativePath ? './' : $relativePath;
  38006. }
  38007. public function mirror($originDir, $targetDir, \Traversable $iterator = null, $options = [])
  38008. {
  38009. $targetDir = rtrim($targetDir, '/\\');
  38010. $originDir = rtrim($originDir, '/\\');
  38011. $originDirLen = \strlen($originDir);
  38012. if ($this->exists($targetDir) && isset($options['delete']) && $options['delete']) {
  38013. $deleteIterator = $iterator;
  38014. if (null === $deleteIterator) {
  38015. $flags = \FilesystemIterator::SKIP_DOTS;
  38016. $deleteIterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($targetDir, $flags), \RecursiveIteratorIterator::CHILD_FIRST);
  38017. }
  38018. $targetDirLen = \strlen($targetDir);
  38019. foreach ($deleteIterator as $file) {
  38020. $origin = $originDir.substr($file->getPathname(), $targetDirLen);
  38021. if (!$this->exists($origin)) {
  38022. $this->remove($file);
  38023. }
  38024. }
  38025. }
  38026. $copyOnWindows = false;
  38027. if (isset($options['copy_on_windows'])) {
  38028. $copyOnWindows = $options['copy_on_windows'];
  38029. }
  38030. if (null === $iterator) {
  38031. $flags = $copyOnWindows ? \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::FOLLOW_SYMLINKS : \FilesystemIterator::SKIP_DOTS;
  38032. $iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($originDir, $flags), \RecursiveIteratorIterator::SELF_FIRST);
  38033. }
  38034. if ($this->exists($originDir)) {
  38035. $this->mkdir($targetDir);
  38036. }
  38037. foreach ($iterator as $file) {
  38038. $target = $targetDir.substr($file->getPathname(), $originDirLen);
  38039. if ($copyOnWindows) {
  38040. if (is_file($file)) {
  38041. $this->copy($file, $target, isset($options['override']) ? $options['override'] : false);
  38042. } elseif (is_dir($file)) {
  38043. $this->mkdir($target);
  38044. } else {
  38045. throw new IOException(sprintf('Unable to guess "%s" file type.', $file), 0, null, $file);
  38046. }
  38047. } else {
  38048. if (is_link($file)) {
  38049. $this->symlink($file->getLinkTarget(), $target);
  38050. } elseif (is_dir($file)) {
  38051. $this->mkdir($target);
  38052. } elseif (is_file($file)) {
  38053. $this->copy($file, $target, isset($options['override']) ? $options['override'] : false);
  38054. } else {
  38055. throw new IOException(sprintf('Unable to guess "%s" file type.', $file), 0, null, $file);
  38056. }
  38057. }
  38058. }
  38059. }
  38060. public function isAbsolutePath($file)
  38061. {
  38062. return strspn($file, '/\\', 0, 1)
  38063. || (\strlen($file) > 3 && ctype_alpha($file[0])
  38064. && ':' === $file[1]
  38065. && strspn($file, '/\\', 2, 1)
  38066. )
  38067. || null !== parse_url($file, PHP_URL_SCHEME)
  38068. ;
  38069. }
  38070. public function tempnam($dir, $prefix)
  38071. {
  38072. list($scheme, $hierarchy) = $this->getSchemeAndHierarchy($dir);
  38073. if (null === $scheme || 'file' === $scheme || 'gs' === $scheme) {
  38074. $tmpFile = @tempnam($hierarchy, $prefix);
  38075. if (false !== $tmpFile) {
  38076. if (null !== $scheme && 'gs' !== $scheme) {
  38077. return $scheme.'://'.$tmpFile;
  38078. }
  38079. return $tmpFile;
  38080. }
  38081. throw new IOException('A temporary file could not be created.');
  38082. }
  38083. for ($i = 0; $i < 10; ++$i) {
  38084. $tmpFile = $dir.'/'.$prefix.uniqid(mt_rand(), true);
  38085. $handle = @fopen($tmpFile, 'x+');
  38086. if (false === $handle) {
  38087. continue;
  38088. }
  38089. @fclose($handle);
  38090. return $tmpFile;
  38091. }
  38092. throw new IOException('A temporary file could not be created.');
  38093. }
  38094. public function dumpFile($filename, $content)
  38095. {
  38096. $dir = \dirname($filename);
  38097. if (!is_dir($dir)) {
  38098. $this->mkdir($dir);
  38099. }
  38100. if (!is_writable($dir)) {
  38101. throw new IOException(sprintf('Unable to write to the "%s" directory.', $dir), 0, null, $dir);
  38102. }
  38103. $tmpFile = $this->tempnam($dir, basename($filename));
  38104. if (false === @file_put_contents($tmpFile, $content)) {
  38105. throw new IOException(sprintf('Failed to write file "%s".', $filename), 0, null, $filename);
  38106. }
  38107. @chmod($tmpFile, file_exists($filename) ? fileperms($filename) : 0666 & ~umask());
  38108. $this->rename($tmpFile, $filename, true);
  38109. }
  38110. public function appendToFile($filename, $content)
  38111. {
  38112. $dir = \dirname($filename);
  38113. if (!is_dir($dir)) {
  38114. $this->mkdir($dir);
  38115. }
  38116. if (!is_writable($dir)) {
  38117. throw new IOException(sprintf('Unable to write to the "%s" directory.', $dir), 0, null, $dir);
  38118. }
  38119. if (false === @file_put_contents($filename, $content, FILE_APPEND)) {
  38120. throw new IOException(sprintf('Failed to write file "%s".', $filename), 0, null, $filename);
  38121. }
  38122. }
  38123. private function toIterable($files)
  38124. {
  38125. return \is_array($files) || $files instanceof \Traversable ? $files : [$files];
  38126. }
  38127. private function getSchemeAndHierarchy($filename)
  38128. {
  38129. $components = explode('://', $filename, 2);
  38130. return 2 === \count($components) ? [$components[0], $components[1]] : [null, $components[0]];
  38131. }
  38132. private static function box($func)
  38133. {
  38134. self::$lastError = null;
  38135. set_error_handler(__CLASS__.'::handleError');
  38136. try {
  38137. $result = \call_user_func_array($func, \array_slice(\func_get_args(), 1));
  38138. restore_error_handler();
  38139. return $result;
  38140. } catch (\Throwable $e) {
  38141. } catch (\Exception $e) {
  38142. }
  38143. restore_error_handler();
  38144. throw $e;
  38145. }
  38146. public static function handleError($type, $msg)
  38147. {
  38148. self::$lastError = $msg;
  38149. }
  38150. }
  38151. <?php
  38152. namespace Symfony\Component\Filesystem;
  38153. use Symfony\Component\Filesystem\Exception\IOException;
  38154. use Symfony\Component\Lock\Store\FlockStore;
  38155. use Symfony\Component\Lock\Store\SemaphoreStore;
  38156. @trigger_error(sprintf('The %s class is deprecated since Symfony 3.4 and will be removed in 4.0. Use %s or %s instead.', LockHandler::class, SemaphoreStore::class, FlockStore::class), E_USER_DEPRECATED);
  38157. /**
  38158. @gmail
  38159. @tchwork
  38160. */
  38161. class LockHandler
  38162. {
  38163. private $file;
  38164. private $handle;
  38165. public function __construct($name, $lockPath = null)
  38166. {
  38167. $lockPath = $lockPath ?: sys_get_temp_dir();
  38168. if (!is_dir($lockPath)) {
  38169. $fs = new Filesystem();
  38170. $fs->mkdir($lockPath);
  38171. }
  38172. if (!is_writable($lockPath)) {
  38173. throw new IOException(sprintf('The directory "%s" is not writable.', $lockPath), 0, null, $lockPath);
  38174. }
  38175. $this->file = sprintf('%s/sf.%s.%s.lock', $lockPath, preg_replace('/[^a-z0-9\._-]+/i', '-', $name), hash('sha256', $name));
  38176. }
  38177. public function lock($blocking = false)
  38178. {
  38179. if ($this->handle) {
  38180. return true;
  38181. }
  38182. $error = null;
  38183. set_error_handler(function ($errno, $msg) use (&$error) {
  38184. $error = $msg;
  38185. });
  38186. if (!$this->handle = fopen($this->file, 'r+') ?: fopen($this->file, 'r')) {
  38187. if ($this->handle = fopen($this->file, 'x')) {
  38188. chmod($this->file, 0666);
  38189. } elseif (!$this->handle = fopen($this->file, 'r+') ?: fopen($this->file, 'r')) {
  38190. usleep(100);
  38191. $this->handle = fopen($this->file, 'r+') ?: fopen($this->file, 'r');
  38192. }
  38193. }
  38194. restore_error_handler();
  38195. if (!$this->handle) {
  38196. throw new IOException($error, 0, null, $this->file);
  38197. }
  38198. if (!flock($this->handle, LOCK_EX | ($blocking ? 0 : LOCK_NB))) {
  38199. fclose($this->handle);
  38200. $this->handle = null;
  38201. return false;
  38202. }
  38203. return true;
  38204. }
  38205. public function release()
  38206. {
  38207. if ($this->handle) {
  38208. flock($this->handle, LOCK_UN | LOCK_NB);
  38209. fclose($this->handle);
  38210. $this->handle = null;
  38211. }
  38212. }
  38213. }
  38214. <?php
  38215. namespace Symfony\Component\Filesystem\Exception;
  38216. interface IOExceptionInterface extends ExceptionInterface
  38217. {
  38218. public function getPath();
  38219. }
  38220. <?php
  38221. namespace Symfony\Component\Filesystem\Exception;
  38222. interface ExceptionInterface
  38223. {
  38224. }
  38225. <?php
  38226. namespace Symfony\Component\Filesystem\Exception;
  38227. /**
  38228. @googlemail
  38229. @symfony
  38230. */
  38231. class IOException extends \RuntimeException implements IOExceptionInterface
  38232. {
  38233. private $path;
  38234. public function __construct($message, $code = 0, \Exception $previous = null, $path = null)
  38235. {
  38236. $this->path = $path;
  38237. parent::__construct($message, $code, $previous);
  38238. }
  38239. public function getPath()
  38240. {
  38241. return $this->path;
  38242. }
  38243. }
  38244. <?php
  38245. namespace Symfony\Component\Filesystem\Exception;
  38246. /**
  38247. @googlemail
  38248. */
  38249. class FileNotFoundException extends IOException
  38250. {
  38251. public function __construct($message = null, $code = 0, \Exception $previous = null, $path = null)
  38252. {
  38253. if (null === $message) {
  38254. if (null === $path) {
  38255. $message = 'File could not be found.';
  38256. } else {
  38257. $message = sprintf('File "%s" could not be found.', $path);
  38258. }
  38259. }
  38260. parent::__construct($message, $code, $previous, $path);
  38261. }
  38262. }
  38263. <?php
  38264. namespace Symfony\Component\Finder;
  38265. /**
  38266. @unixbeard
  38267. @symfony
  38268. @unixbeard
  38269. */
  38270. class Glob
  38271. {
  38272. public static function toRegex($glob, $strictLeadingDot = true, $strictWildcardSlash = true, $delimiter = '#')
  38273. {
  38274. $firstByte = true;
  38275. $escaping = false;
  38276. $inCurlies = 0;
  38277. $regex = '';
  38278. $sizeGlob = \strlen($glob);
  38279. for ($i = 0; $i < $sizeGlob; ++$i) {
  38280. $car = $glob[$i];
  38281. if ($firstByte && $strictLeadingDot && '.' !== $car) {
  38282. $regex .= '(?=[^\.])';
  38283. }
  38284. $firstByte = '/' === $car;
  38285. if ($firstByte && $strictWildcardSlash && isset($glob[$i + 2]) && '**' === $glob[$i + 1].$glob[$i + 2] && (!isset($glob[$i + 3]) || '/' === $glob[$i + 3])) {
  38286. $car = '[^/]++/';
  38287. if (!isset($glob[$i + 3])) {
  38288. $car .= '?';
  38289. }
  38290. if ($strictLeadingDot) {
  38291. $car = '(?=[^\.])'.$car;
  38292. }
  38293. $car = '/(?:'.$car.')*';
  38294. $i += 2 + isset($glob[$i + 3]);
  38295. if ('/' === $delimiter) {
  38296. $car = str_replace('/', '\\/', $car);
  38297. }
  38298. }
  38299. if ($delimiter === $car || '.' === $car || '(' === $car || ')' === $car || '|' === $car || '+' === $car || '^' === $car || '$' === $car) {
  38300. $regex .= "\\$car";
  38301. } elseif ('*' === $car) {
  38302. $regex .= $escaping ? '\\*' : ($strictWildcardSlash ? '[^/]*' : '.*');
  38303. } elseif ('?' === $car) {
  38304. $regex .= $escaping ? '\\?' : ($strictWildcardSlash ? '[^/]' : '.');
  38305. } elseif ('{' === $car) {
  38306. $regex .= $escaping ? '\\{' : '(';
  38307. if (!$escaping) {
  38308. ++$inCurlies;
  38309. }
  38310. } elseif ('}' === $car && $inCurlies) {
  38311. $regex .= $escaping ? '}' : ')';
  38312. if (!$escaping) {
  38313. --$inCurlies;
  38314. }
  38315. } elseif (',' === $car && $inCurlies) {
  38316. $regex .= $escaping ? ',' : '|';
  38317. } elseif ('\\' === $car) {
  38318. if ($escaping) {
  38319. $regex .= '\\\\';
  38320. $escaping = false;
  38321. } else {
  38322. $escaping = true;
  38323. }
  38324. continue;
  38325. } else {
  38326. $regex .= $car;
  38327. }
  38328. $escaping = false;
  38329. }
  38330. return $delimiter.'^'.$regex.'$'.$delimiter;
  38331. }
  38332. }
  38333. <?php
  38334. namespace Symfony\Component\Finder;
  38335. class SplFileInfo extends \SplFileInfo
  38336. {
  38337. private $relativePath;
  38338. private $relativePathname;
  38339. public function __construct($file, $relativePath, $relativePathname)
  38340. {
  38341. parent::__construct($file);
  38342. $this->relativePath = $relativePath;
  38343. $this->relativePathname = $relativePathname;
  38344. }
  38345. public function getRelativePath()
  38346. {
  38347. return $this->relativePath;
  38348. }
  38349. public function getRelativePathname()
  38350. {
  38351. return $this->relativePathname;
  38352. }
  38353. public function getContents()
  38354. {
  38355. set_error_handler(function ($type, $msg) use (&$error) { $error = $msg; });
  38356. $content = file_get_contents($this->getPathname());
  38357. restore_error_handler();
  38358. if (false === $content) {
  38359. throw new \RuntimeException($error);
  38360. }
  38361. return $content;
  38362. }
  38363. }
  38364. <?php
  38365. namespace Symfony\Component\Finder\Comparator;
  38366. /**
  38367. @unixbeard
  38368. @symfony
  38369. @unixbeard
  38370. */
  38371. class NumberComparator extends Comparator
  38372. {
  38373. public function __construct($test)
  38374. {
  38375. if (!preg_match('#^\s*(==|!=|[<>]=?)?\s*([0-9\.]+)\s*([kmg]i?)?\s*$#i', $test, $matches)) {
  38376. throw new \InvalidArgumentException(sprintf('Don\'t understand "%s" as a number test.', $test));
  38377. }
  38378. $target = $matches[2];
  38379. if (!is_numeric($target)) {
  38380. throw new \InvalidArgumentException(sprintf('Invalid number "%s".', $target));
  38381. }
  38382. if (isset($matches[3])) {
  38383. switch (strtolower($matches[3])) {
  38384. case 'k':
  38385. $target *= 1000;
  38386. break;
  38387. case 'ki':
  38388. $target *= 1024;
  38389. break;
  38390. case 'm':
  38391. $target *= 1000000;
  38392. break;
  38393. case 'mi':
  38394. $target *= 1024 * 1024;
  38395. break;
  38396. case 'g':
  38397. $target *= 1000000000;
  38398. break;
  38399. case 'gi':
  38400. $target *= 1024 * 1024 * 1024;
  38401. break;
  38402. }
  38403. }
  38404. $this->setTarget($target);
  38405. $this->setOperator(isset($matches[1]) ? $matches[1] : '==');
  38406. }
  38407. }
  38408. <?php
  38409. namespace Symfony\Component\Finder\Comparator;
  38410. class DateComparator extends Comparator
  38411. {
  38412. public function __construct($test)
  38413. {
  38414. if (!preg_match('#^\s*(==|!=|[<>]=?|after|since|before|until)?\s*(.+?)\s*$#i', $test, $matches)) {
  38415. throw new \InvalidArgumentException(sprintf('Don\'t understand "%s" as a date test.', $test));
  38416. }
  38417. try {
  38418. $date = new \DateTime($matches[2]);
  38419. $target = $date->format('U');
  38420. } catch (\Exception $e) {
  38421. throw new \InvalidArgumentException(sprintf('"%s" is not a valid date.', $matches[2]));
  38422. }
  38423. $operator = isset($matches[1]) ? $matches[1] : '==';
  38424. if ('since' === $operator || 'after' === $operator) {
  38425. $operator = '>';
  38426. }
  38427. if ('until' === $operator || 'before' === $operator) {
  38428. $operator = '<';
  38429. }
  38430. $this->setOperator($operator);
  38431. $this->setTarget($target);
  38432. }
  38433. }
  38434. <?php
  38435. namespace Symfony\Component\Finder\Comparator;
  38436. class Comparator
  38437. {
  38438. private $target;
  38439. private $operator = '==';
  38440. public function getTarget()
  38441. {
  38442. return $this->target;
  38443. }
  38444. public function setTarget($target)
  38445. {
  38446. $this->target = $target;
  38447. }
  38448. public function getOperator()
  38449. {
  38450. return $this->operator;
  38451. }
  38452. public function setOperator($operator)
  38453. {
  38454. if (!$operator) {
  38455. $operator = '==';
  38456. }
  38457. if (!\in_array($operator, ['>', '<', '>=', '<=', '==', '!='])) {
  38458. throw new \InvalidArgumentException(sprintf('Invalid operator "%s".', $operator));
  38459. }
  38460. $this->operator = $operator;
  38461. }
  38462. public function test($test)
  38463. {
  38464. switch ($this->operator) {
  38465. case '>':
  38466. return $test > $this->target;
  38467. case '>=':
  38468. return $test >= $this->target;
  38469. case '<':
  38470. return $test < $this->target;
  38471. case '<=':
  38472. return $test <= $this->target;
  38473. case '!=':
  38474. return $test != $this->target;
  38475. }
  38476. return $test == $this->target;
  38477. }
  38478. }
  38479. <?php
  38480. namespace Symfony\Component\Finder\Iterator;
  38481. use Symfony\Component\Finder\Comparator\NumberComparator;
  38482. class SizeRangeFilterIterator extends FilterIterator
  38483. {
  38484. private $comparators = [];
  38485. public function __construct(\Iterator $iterator, array $comparators)
  38486. {
  38487. $this->comparators = $comparators;
  38488. parent::__construct($iterator);
  38489. }
  38490. public function accept()
  38491. {
  38492. $fileinfo = $this->current();
  38493. if (!$fileinfo->isFile()) {
  38494. return true;
  38495. }
  38496. $filesize = $fileinfo->getSize();
  38497. foreach ($this->comparators as $compare) {
  38498. if (!$compare->test($filesize)) {
  38499. return false;
  38500. }
  38501. }
  38502. return true;
  38503. }
  38504. }
  38505. <?php
  38506. namespace Symfony\Component\Finder\Iterator;
  38507. abstract class FilterIterator extends \FilterIterator
  38508. {
  38509. public function rewind()
  38510. {
  38511. if (\PHP_VERSION_ID > 50607 || (\PHP_VERSION_ID > 50523 && \PHP_VERSION_ID < 50600)) {
  38512. parent::rewind();
  38513. return;
  38514. }
  38515. $iterator = $this;
  38516. while ($iterator instanceof \OuterIterator) {
  38517. $innerIterator = $iterator->getInnerIterator();
  38518. if ($innerIterator instanceof RecursiveDirectoryIterator) {
  38519. if ($innerIterator->isRewindable()) {
  38520. $innerIterator->next();
  38521. $innerIterator->rewind();
  38522. }
  38523. } elseif ($innerIterator instanceof \FilesystemIterator) {
  38524. $innerIterator->next();
  38525. $innerIterator->rewind();
  38526. }
  38527. $iterator = $innerIterator;
  38528. }
  38529. parent::rewind();
  38530. }
  38531. }
  38532. <?php
  38533. namespace Symfony\Component\Finder\Iterator;
  38534. abstract class MultiplePcreFilterIterator extends FilterIterator
  38535. {
  38536. protected $matchRegexps = [];
  38537. protected $noMatchRegexps = [];
  38538. public function __construct(\Iterator $iterator, array $matchPatterns, array $noMatchPatterns)
  38539. {
  38540. foreach ($matchPatterns as $pattern) {
  38541. $this->matchRegexps[] = $this->toRegex($pattern);
  38542. }
  38543. foreach ($noMatchPatterns as $pattern) {
  38544. $this->noMatchRegexps[] = $this->toRegex($pattern);
  38545. }
  38546. parent::__construct($iterator);
  38547. }
  38548. protected function isAccepted($string)
  38549. {
  38550. foreach ($this->noMatchRegexps as $regex) {
  38551. if (preg_match($regex, $string)) {
  38552. return false;
  38553. }
  38554. }
  38555. if ($this->matchRegexps) {
  38556. foreach ($this->matchRegexps as $regex) {
  38557. if (preg_match($regex, $string)) {
  38558. return true;
  38559. }
  38560. }
  38561. return false;
  38562. }
  38563. return true;
  38564. }
  38565. protected function isRegex($str)
  38566. {
  38567. if (preg_match('/^(.{3,}?)[imsxuADU]*$/', $str, $m)) {
  38568. $start = substr($m[1], 0, 1);
  38569. $end = substr($m[1], -1);
  38570. if ($start === $end) {
  38571. return !preg_match('/[*?[:alnum:] \\\\]/', $start);
  38572. }
  38573. foreach ([['{', '}'], ['(', ')'], ['[', ']'], ['<', '>']] as $delimiters) {
  38574. if ($start === $delimiters[0] && $end === $delimiters[1]) {
  38575. return true;
  38576. }
  38577. }
  38578. }
  38579. return false;
  38580. }
  38581. abstract protected function toRegex($str);
  38582. }
  38583. <?php
  38584. namespace Symfony\Component\Finder\Iterator;
  38585. use Symfony\Component\Finder\Glob;
  38586. class FilenameFilterIterator extends MultiplePcreFilterIterator
  38587. {
  38588. public function accept()
  38589. {
  38590. return $this->isAccepted($this->current()->getFilename());
  38591. }
  38592. protected function toRegex($str)
  38593. {
  38594. return $this->isRegex($str) ? $str : Glob::toRegex($str);
  38595. }
  38596. }
  38597. <?php
  38598. namespace Symfony\Component\Finder\Iterator;
  38599. class DepthRangeFilterIterator extends FilterIterator
  38600. {
  38601. private $minDepth = 0;
  38602. public function __construct(\RecursiveIteratorIterator $iterator, $minDepth = 0, $maxDepth = PHP_INT_MAX)
  38603. {
  38604. $this->minDepth = $minDepth;
  38605. $iterator->setMaxDepth(PHP_INT_MAX === $maxDepth ? -1 : $maxDepth);
  38606. parent::__construct($iterator);
  38607. }
  38608. public function accept()
  38609. {
  38610. return $this->getInnerIterator()->getDepth() >= $this->minDepth;
  38611. }
  38612. }
  38613. <?php
  38614. namespace Symfony\Component\Finder\Iterator;
  38615. class ExcludeDirectoryFilterIterator extends FilterIterator implements \RecursiveIterator
  38616. {
  38617. private $iterator;
  38618. private $isRecursive;
  38619. private $excludedDirs = [];
  38620. private $excludedPattern;
  38621. public function __construct(\Iterator $iterator, array $directories)
  38622. {
  38623. $this->iterator = $iterator;
  38624. $this->isRecursive = $iterator instanceof \RecursiveIterator;
  38625. $patterns = [];
  38626. foreach ($directories as $directory) {
  38627. $directory = rtrim($directory, '/');
  38628. if (!$this->isRecursive || false !== strpos($directory, '/')) {
  38629. $patterns[] = preg_quote($directory, '#');
  38630. } else {
  38631. $this->excludedDirs[$directory] = true;
  38632. }
  38633. }
  38634. if ($patterns) {
  38635. $this->excludedPattern = '#(?:^|/)(?:'.implode('|', $patterns).')(?:/|$)#';
  38636. }
  38637. parent::__construct($iterator);
  38638. }
  38639. public function accept()
  38640. {
  38641. if ($this->isRecursive && isset($this->excludedDirs[$this->getFilename()]) && $this->isDir()) {
  38642. return false;
  38643. }
  38644. if ($this->excludedPattern) {
  38645. $path = $this->isDir() ? $this->current()->getRelativePathname() : $this->current()->getRelativePath();
  38646. $path = str_replace('\\', '/', $path);
  38647. return !preg_match($this->excludedPattern, $path);
  38648. }
  38649. return true;
  38650. }
  38651. public function hasChildren()
  38652. {
  38653. return $this->isRecursive && $this->iterator->hasChildren();
  38654. }
  38655. public function getChildren()
  38656. {
  38657. $children = new self($this->iterator->getChildren(), []);
  38658. $children->excludedDirs = $this->excludedDirs;
  38659. $children->excludedPattern = $this->excludedPattern;
  38660. return $children;
  38661. }
  38662. }
  38663. <?php
  38664. namespace Symfony\Component\Finder\Iterator;
  38665. use Symfony\Component\Finder\Exception\AccessDeniedException;
  38666. use Symfony\Component\Finder\SplFileInfo;
  38667. class RecursiveDirectoryIterator extends \RecursiveDirectoryIterator
  38668. {
  38669. private $ignoreUnreadableDirs;
  38670. private $rewindable;
  38671. private $rootPath;
  38672. private $subPath;
  38673. private $directorySeparator = '/';
  38674. public function __construct($path, $flags, $ignoreUnreadableDirs = false)
  38675. {
  38676. if ($flags & (self::CURRENT_AS_PATHNAME | self::CURRENT_AS_SELF)) {
  38677. throw new \RuntimeException('This iterator only support returning current as fileinfo.');
  38678. }
  38679. parent::__construct($path, $flags);
  38680. $this->ignoreUnreadableDirs = $ignoreUnreadableDirs;
  38681. $this->rootPath = $path;
  38682. if ('/' !== \DIRECTORY_SEPARATOR && !($flags & self::UNIX_PATHS)) {
  38683. $this->directorySeparator = \DIRECTORY_SEPARATOR;
  38684. }
  38685. }
  38686. public function current()
  38687. {
  38688. if (null === $subPathname = $this->subPath) {
  38689. $subPathname = $this->subPath = (string) $this->getSubPath();
  38690. }
  38691. if ('' !== $subPathname) {
  38692. $subPathname .= $this->directorySeparator;
  38693. }
  38694. $subPathname .= $this->getFilename();
  38695. if ('/' !== $basePath = $this->rootPath) {
  38696. $basePath .= $this->directorySeparator;
  38697. }
  38698. return new SplFileInfo($basePath.$subPathname, $this->subPath, $subPathname);
  38699. }
  38700. public function getChildren()
  38701. {
  38702. try {
  38703. $children = parent::getChildren();
  38704. if ($children instanceof self) {
  38705. $children->ignoreUnreadableDirs = $this->ignoreUnreadableDirs;
  38706. $children->rewindable = &$this->rewindable;
  38707. $children->rootPath = $this->rootPath;
  38708. }
  38709. return $children;
  38710. } catch (\UnexpectedValueException $e) {
  38711. if ($this->ignoreUnreadableDirs) {
  38712. return new \RecursiveArrayIterator([]);
  38713. } else {
  38714. throw new AccessDeniedException($e->getMessage(), $e->getCode(), $e);
  38715. }
  38716. }
  38717. }
  38718. public function rewind()
  38719. {
  38720. if (false === $this->isRewindable()) {
  38721. return;
  38722. }
  38723. if (\PHP_VERSION_ID < 50523 || \PHP_VERSION_ID >= 50600 && \PHP_VERSION_ID < 50607) {
  38724. parent::next();
  38725. }
  38726. parent::rewind();
  38727. }
  38728. public function isRewindable()
  38729. {
  38730. if (null !== $this->rewindable) {
  38731. return $this->rewindable;
  38732. }
  38733. if ('' === $this->getPath()) {
  38734. return $this->rewindable = false;
  38735. }
  38736. if (false !== $stream = @opendir($this->getPath())) {
  38737. $infos = stream_get_meta_data($stream);
  38738. closedir($stream);
  38739. if ($infos['seekable']) {
  38740. return $this->rewindable = true;
  38741. }
  38742. }
  38743. return $this->rewindable = false;
  38744. }
  38745. }
  38746. <?php
  38747. namespace Symfony\Component\Finder\Iterator;
  38748. class FileTypeFilterIterator extends FilterIterator
  38749. {
  38750. const ONLY_FILES = 1;
  38751. const ONLY_DIRECTORIES = 2;
  38752. private $mode;
  38753. public function __construct(\Iterator $iterator, $mode)
  38754. {
  38755. $this->mode = $mode;
  38756. parent::__construct($iterator);
  38757. }
  38758. public function accept()
  38759. {
  38760. $fileinfo = $this->current();
  38761. if (self::ONLY_DIRECTORIES === (self::ONLY_DIRECTORIES & $this->mode) && $fileinfo->isFile()) {
  38762. return false;
  38763. } elseif (self::ONLY_FILES === (self::ONLY_FILES & $this->mode) && $fileinfo->isDir()) {
  38764. return false;
  38765. }
  38766. return true;
  38767. }
  38768. }
  38769. <?php
  38770. namespace Symfony\Component\Finder\Iterator;
  38771. use Symfony\Component\Finder\Comparator\DateComparator;
  38772. class DateRangeFilterIterator extends FilterIterator
  38773. {
  38774. private $comparators = [];
  38775. public function __construct(\Iterator $iterator, array $comparators)
  38776. {
  38777. $this->comparators = $comparators;
  38778. parent::__construct($iterator);
  38779. }
  38780. public function accept()
  38781. {
  38782. $fileinfo = $this->current();
  38783. if (!file_exists($fileinfo->getPathname())) {
  38784. return false;
  38785. }
  38786. $filedate = $fileinfo->getMTime();
  38787. foreach ($this->comparators as $compare) {
  38788. if (!$compare->test($filedate)) {
  38789. return false;
  38790. }
  38791. }
  38792. return true;
  38793. }
  38794. }
  38795. <?php
  38796. namespace Symfony\Component\Finder\Iterator;
  38797. class CustomFilterIterator extends FilterIterator
  38798. {
  38799. private $filters = [];
  38800. public function __construct(\Iterator $iterator, array $filters)
  38801. {
  38802. foreach ($filters as $filter) {
  38803. if (!\is_callable($filter)) {
  38804. throw new \InvalidArgumentException('Invalid PHP callback.');
  38805. }
  38806. }
  38807. $this->filters = $filters;
  38808. parent::__construct($iterator);
  38809. }
  38810. public function accept()
  38811. {
  38812. $fileinfo = $this->current();
  38813. foreach ($this->filters as $filter) {
  38814. if (false === \call_user_func($filter, $fileinfo)) {
  38815. return false;
  38816. }
  38817. }
  38818. return true;
  38819. }
  38820. }
  38821. <?php
  38822. namespace Symfony\Component\Finder\Iterator;
  38823. /**
  38824. @gajdaw
  38825. */
  38826. class PathFilterIterator extends MultiplePcreFilterIterator
  38827. {
  38828. public function accept()
  38829. {
  38830. $filename = $this->current()->getRelativePathname();
  38831. if ('\\' === \DIRECTORY_SEPARATOR) {
  38832. $filename = str_replace('\\', '/', $filename);
  38833. }
  38834. return $this->isAccepted($filename);
  38835. }
  38836. protected function toRegex($str)
  38837. {
  38838. return $this->isRegex($str) ? $str : '/'.preg_quote($str, '/').'/';
  38839. }
  38840. }
  38841. <?php
  38842. namespace Symfony\Component\Finder\Iterator;
  38843. /**
  38844. @gajdaw
  38845. */
  38846. class FilecontentFilterIterator extends MultiplePcreFilterIterator
  38847. {
  38848. public function accept()
  38849. {
  38850. if (!$this->matchRegexps && !$this->noMatchRegexps) {
  38851. return true;
  38852. }
  38853. $fileinfo = $this->current();
  38854. if ($fileinfo->isDir() || !$fileinfo->isReadable()) {
  38855. return false;
  38856. }
  38857. $content = $fileinfo->getContents();
  38858. if (!$content) {
  38859. return false;
  38860. }
  38861. return $this->isAccepted($content);
  38862. }
  38863. protected function toRegex($str)
  38864. {
  38865. return $this->isRegex($str) ? $str : '/'.preg_quote($str, '/').'/';
  38866. }
  38867. }
  38868. <?php
  38869. namespace Symfony\Component\Finder\Iterator;
  38870. class SortableIterator implements \IteratorAggregate
  38871. {
  38872. const SORT_BY_NAME = 1;
  38873. const SORT_BY_TYPE = 2;
  38874. const SORT_BY_ACCESSED_TIME = 3;
  38875. const SORT_BY_CHANGED_TIME = 4;
  38876. const SORT_BY_MODIFIED_TIME = 5;
  38877. private $iterator;
  38878. private $sort;
  38879. public function __construct(\Traversable $iterator, $sort)
  38880. {
  38881. $this->iterator = $iterator;
  38882. if (self::SORT_BY_NAME === $sort) {
  38883. $this->sort = static function ($a, $b) {
  38884. return strcmp($a->getRealPath() ?: $a->getPathname(), $b->getRealPath() ?: $b->getPathname());
  38885. };
  38886. } elseif (self::SORT_BY_TYPE === $sort) {
  38887. $this->sort = static function ($a, $b) {
  38888. if ($a->isDir() && $b->isFile()) {
  38889. return -1;
  38890. } elseif ($a->isFile() && $b->isDir()) {
  38891. return 1;
  38892. }
  38893. return strcmp($a->getRealPath() ?: $a->getPathname(), $b->getRealPath() ?: $b->getPathname());
  38894. };
  38895. } elseif (self::SORT_BY_ACCESSED_TIME === $sort) {
  38896. $this->sort = static function ($a, $b) {
  38897. return $a->getATime() - $b->getATime();
  38898. };
  38899. } elseif (self::SORT_BY_CHANGED_TIME === $sort) {
  38900. $this->sort = static function ($a, $b) {
  38901. return $a->getCTime() - $b->getCTime();
  38902. };
  38903. } elseif (self::SORT_BY_MODIFIED_TIME === $sort) {
  38904. $this->sort = static function ($a, $b) {
  38905. return $a->getMTime() - $b->getMTime();
  38906. };
  38907. } elseif (\is_callable($sort)) {
  38908. $this->sort = $sort;
  38909. } else {
  38910. throw new \InvalidArgumentException('The SortableIterator takes a PHP callable or a valid built-in sort algorithm as an argument.');
  38911. }
  38912. }
  38913. public function getIterator()
  38914. {
  38915. $array = iterator_to_array($this->iterator, true);
  38916. uasort($array, $this->sort);
  38917. return new \ArrayIterator($array);
  38918. }
  38919. }
  38920. <?php
  38921. namespace Symfony\Component\Finder;
  38922. use Symfony\Component\Finder\Comparator\DateComparator;
  38923. use Symfony\Component\Finder\Comparator\NumberComparator;
  38924. use Symfony\Component\Finder\Iterator\CustomFilterIterator;
  38925. use Symfony\Component\Finder\Iterator\DateRangeFilterIterator;
  38926. use Symfony\Component\Finder\Iterator\DepthRangeFilterIterator;
  38927. use Symfony\Component\Finder\Iterator\ExcludeDirectoryFilterIterator;
  38928. use Symfony\Component\Finder\Iterator\FilecontentFilterIterator;
  38929. use Symfony\Component\Finder\Iterator\FilenameFilterIterator;
  38930. use Symfony\Component\Finder\Iterator\SizeRangeFilterIterator;
  38931. use Symfony\Component\Finder\Iterator\SortableIterator;
  38932. class Finder implements \IteratorAggregate, \Countable
  38933. {
  38934. const IGNORE_VCS_FILES = 1;
  38935. const IGNORE_DOT_FILES = 2;
  38936. private $mode = 0;
  38937. private $names = [];
  38938. private $notNames = [];
  38939. private $exclude = [];
  38940. private $filters = [];
  38941. private $depths = [];
  38942. private $sizes = [];
  38943. private $followLinks = false;
  38944. private $sort = false;
  38945. private $ignore = 0;
  38946. private $dirs = [];
  38947. private $dates = [];
  38948. private $iterators = [];
  38949. private $contains = [];
  38950. private $notContains = [];
  38951. private $paths = [];
  38952. private $notPaths = [];
  38953. private $ignoreUnreadableDirs = false;
  38954. private static $vcsPatterns = ['.svn', '_svn', 'CVS', '_darcs', '.arch-params', '.monotone', '.bzr', '.git', '.hg'];
  38955. public function __construct()
  38956. {
  38957. $this->ignore = static::IGNORE_VCS_FILES | static::IGNORE_DOT_FILES;
  38958. }
  38959. public static function create()
  38960. {
  38961. return new static();
  38962. }
  38963. public function directories()
  38964. {
  38965. $this->mode = Iterator\FileTypeFilterIterator::ONLY_DIRECTORIES;
  38966. return $this;
  38967. }
  38968. public function files()
  38969. {
  38970. $this->mode = Iterator\FileTypeFilterIterator::ONLY_FILES;
  38971. return $this;
  38972. }
  38973. public function depth($level)
  38974. {
  38975. $this->depths[] = new Comparator\NumberComparator($level);
  38976. return $this;
  38977. }
  38978. public function date($date)
  38979. {
  38980. $this->dates[] = new Comparator\DateComparator($date);
  38981. return $this;
  38982. }
  38983. public function name($pattern)
  38984. {
  38985. $this->names[] = $pattern;
  38986. return $this;
  38987. }
  38988. public function notName($pattern)
  38989. {
  38990. $this->notNames[] = $pattern;
  38991. return $this;
  38992. }
  38993. public function contains($pattern)
  38994. {
  38995. $this->contains[] = $pattern;
  38996. return $this;
  38997. }
  38998. public function notContains($pattern)
  38999. {
  39000. $this->notContains[] = $pattern;
  39001. return $this;
  39002. }
  39003. public function path($pattern)
  39004. {
  39005. $this->paths[] = $pattern;
  39006. return $this;
  39007. }
  39008. public function notPath($pattern)
  39009. {
  39010. $this->notPaths[] = $pattern;
  39011. return $this;
  39012. }
  39013. public function size($size)
  39014. {
  39015. $this->sizes[] = new Comparator\NumberComparator($size);
  39016. return $this;
  39017. }
  39018. public function exclude($dirs)
  39019. {
  39020. $this->exclude = array_merge($this->exclude, (array) $dirs);
  39021. return $this;
  39022. }
  39023. public function ignoreDotFiles($ignoreDotFiles)
  39024. {
  39025. if ($ignoreDotFiles) {
  39026. $this->ignore |= static::IGNORE_DOT_FILES;
  39027. } else {
  39028. $this->ignore &= ~static::IGNORE_DOT_FILES;
  39029. }
  39030. return $this;
  39031. }
  39032. public function ignoreVCS($ignoreVCS)
  39033. {
  39034. if ($ignoreVCS) {
  39035. $this->ignore |= static::IGNORE_VCS_FILES;
  39036. } else {
  39037. $this->ignore &= ~static::IGNORE_VCS_FILES;
  39038. }
  39039. return $this;
  39040. }
  39041. public static function addVCSPattern($pattern)
  39042. {
  39043. foreach ((array) $pattern as $p) {
  39044. self::$vcsPatterns[] = $p;
  39045. }
  39046. self::$vcsPatterns = array_unique(self::$vcsPatterns);
  39047. }
  39048. public function sort(\Closure $closure)
  39049. {
  39050. $this->sort = $closure;
  39051. return $this;
  39052. }
  39053. public function sortByName()
  39054. {
  39055. $this->sort = Iterator\SortableIterator::SORT_BY_NAME;
  39056. return $this;
  39057. }
  39058. public function sortByType()
  39059. {
  39060. $this->sort = Iterator\SortableIterator::SORT_BY_TYPE;
  39061. return $this;
  39062. }
  39063. public function sortByAccessedTime()
  39064. {
  39065. $this->sort = Iterator\SortableIterator::SORT_BY_ACCESSED_TIME;
  39066. return $this;
  39067. }
  39068. public function sortByChangedTime()
  39069. {
  39070. $this->sort = Iterator\SortableIterator::SORT_BY_CHANGED_TIME;
  39071. return $this;
  39072. }
  39073. public function sortByModifiedTime()
  39074. {
  39075. $this->sort = Iterator\SortableIterator::SORT_BY_MODIFIED_TIME;
  39076. return $this;
  39077. }
  39078. public function filter(\Closure $closure)
  39079. {
  39080. $this->filters[] = $closure;
  39081. return $this;
  39082. }
  39083. public function followLinks()
  39084. {
  39085. $this->followLinks = true;
  39086. return $this;
  39087. }
  39088. public function ignoreUnreadableDirs($ignore = true)
  39089. {
  39090. $this->ignoreUnreadableDirs = (bool) $ignore;
  39091. return $this;
  39092. }
  39093. public function in($dirs)
  39094. {
  39095. $resolvedDirs = [];
  39096. foreach ((array) $dirs as $dir) {
  39097. if (is_dir($dir)) {
  39098. $resolvedDirs[] = $this->normalizeDir($dir);
  39099. } elseif ($glob = glob($dir, (\defined('GLOB_BRACE') ? GLOB_BRACE : 0) | GLOB_ONLYDIR | GLOB_NOSORT)) {
  39100. sort($glob);
  39101. $resolvedDirs = array_merge($resolvedDirs, array_map([$this, 'normalizeDir'], $glob));
  39102. } else {
  39103. throw new \InvalidArgumentException(sprintf('The "%s" directory does not exist.', $dir));
  39104. }
  39105. }
  39106. $this->dirs = array_merge($this->dirs, $resolvedDirs);
  39107. return $this;
  39108. }
  39109. public function getIterator()
  39110. {
  39111. if (0 === \count($this->dirs) && 0 === \count($this->iterators)) {
  39112. throw new \LogicException('You must call one of in() or append() methods before iterating over a Finder.');
  39113. }
  39114. if (1 === \count($this->dirs) && 0 === \count($this->iterators)) {
  39115. return $this->searchInDirectory($this->dirs[0]);
  39116. }
  39117. $iterator = new \AppendIterator();
  39118. foreach ($this->dirs as $dir) {
  39119. $iterator->append($this->searchInDirectory($dir));
  39120. }
  39121. foreach ($this->iterators as $it) {
  39122. $iterator->append($it);
  39123. }
  39124. return $iterator;
  39125. }
  39126. public function append($iterator)
  39127. {
  39128. if ($iterator instanceof \IteratorAggregate) {
  39129. $this->iterators[] = $iterator->getIterator();
  39130. } elseif ($iterator instanceof \Iterator) {
  39131. $this->iterators[] = $iterator;
  39132. } elseif ($iterator instanceof \Traversable || \is_array($iterator)) {
  39133. $it = new \ArrayIterator();
  39134. foreach ($iterator as $file) {
  39135. $it->append($file instanceof \SplFileInfo ? $file : new \SplFileInfo($file));
  39136. }
  39137. $this->iterators[] = $it;
  39138. } else {
  39139. throw new \InvalidArgumentException('Finder::append() method wrong argument type.');
  39140. }
  39141. return $this;
  39142. }
  39143. public function hasResults()
  39144. {
  39145. foreach ($this->getIterator() as $_) {
  39146. return true;
  39147. }
  39148. return false;
  39149. }
  39150. public function count()
  39151. {
  39152. return iterator_count($this->getIterator());
  39153. }
  39154. private function searchInDirectory($dir)
  39155. {
  39156. $exclude = $this->exclude;
  39157. $notPaths = $this->notPaths;
  39158. if (static::IGNORE_VCS_FILES === (static::IGNORE_VCS_FILES & $this->ignore)) {
  39159. $exclude = array_merge($exclude, self::$vcsPatterns);
  39160. }
  39161. if (static::IGNORE_DOT_FILES === (static::IGNORE_DOT_FILES & $this->ignore)) {
  39162. $notPaths[] = '#(^|/)\..+(/|$)#';
  39163. }
  39164. $minDepth = 0;
  39165. $maxDepth = PHP_INT_MAX;
  39166. foreach ($this->depths as $comparator) {
  39167. switch ($comparator->getOperator()) {
  39168. case '>':
  39169. $minDepth = $comparator->getTarget() + 1;
  39170. break;
  39171. case '>=':
  39172. $minDepth = $comparator->getTarget();
  39173. break;
  39174. case '<':
  39175. $maxDepth = $comparator->getTarget() - 1;
  39176. break;
  39177. case '<=':
  39178. $maxDepth = $comparator->getTarget();
  39179. break;
  39180. default:
  39181. $minDepth = $maxDepth = $comparator->getTarget();
  39182. }
  39183. }
  39184. $flags = \RecursiveDirectoryIterator::SKIP_DOTS;
  39185. if ($this->followLinks) {
  39186. $flags |= \RecursiveDirectoryIterator::FOLLOW_SYMLINKS;
  39187. }
  39188. $iterator = new Iterator\RecursiveDirectoryIterator($dir, $flags, $this->ignoreUnreadableDirs);
  39189. if ($exclude) {
  39190. $iterator = new Iterator\ExcludeDirectoryFilterIterator($iterator, $exclude);
  39191. }
  39192. $iterator = new \RecursiveIteratorIterator($iterator, \RecursiveIteratorIterator::SELF_FIRST);
  39193. if ($minDepth > 0 || $maxDepth < PHP_INT_MAX) {
  39194. $iterator = new Iterator\DepthRangeFilterIterator($iterator, $minDepth, $maxDepth);
  39195. }
  39196. if ($this->mode) {
  39197. $iterator = new Iterator\FileTypeFilterIterator($iterator, $this->mode);
  39198. }
  39199. if ($this->names || $this->notNames) {
  39200. $iterator = new Iterator\FilenameFilterIterator($iterator, $this->names, $this->notNames);
  39201. }
  39202. if ($this->contains || $this->notContains) {
  39203. $iterator = new Iterator\FilecontentFilterIterator($iterator, $this->contains, $this->notContains);
  39204. }
  39205. if ($this->sizes) {
  39206. $iterator = new Iterator\SizeRangeFilterIterator($iterator, $this->sizes);
  39207. }
  39208. if ($this->dates) {
  39209. $iterator = new Iterator\DateRangeFilterIterator($iterator, $this->dates);
  39210. }
  39211. if ($this->filters) {
  39212. $iterator = new Iterator\CustomFilterIterator($iterator, $this->filters);
  39213. }
  39214. if ($this->paths || $notPaths) {
  39215. $iterator = new Iterator\PathFilterIterator($iterator, $this->paths, $notPaths);
  39216. }
  39217. if ($this->sort) {
  39218. $iteratorAggregate = new Iterator\SortableIterator($iterator, $this->sort);
  39219. $iterator = $iteratorAggregate->getIterator();
  39220. }
  39221. return $iterator;
  39222. }
  39223. private function normalizeDir($dir)
  39224. {
  39225. if ('/' === $dir) {
  39226. return $dir;
  39227. }
  39228. $dir = rtrim($dir, '/'.\DIRECTORY_SEPARATOR);
  39229. if (preg_match('#^(ssh2\.)?s?ftp://#', $dir)) {
  39230. $dir .= '/';
  39231. }
  39232. return $dir;
  39233. }
  39234. }
  39235. <?php
  39236. namespace Symfony\Component\Finder\Exception;
  39237. class AccessDeniedException extends \UnexpectedValueException
  39238. {
  39239. }
  39240. <?php
  39241. namespace Symfony\Component\Finder\Exception;
  39242. interface ExceptionInterface
  39243. {
  39244. public function getAdapter();
  39245. }
  39246. <?php
  39247. namespace Symfony\Component\Process;
  39248. use Symfony\Component\Process\Exception\RuntimeException;
  39249. class InputStream implements \IteratorAggregate
  39250. {
  39251. private $onEmpty = null;
  39252. private $input = [];
  39253. private $open = true;
  39254. public function onEmpty(callable $onEmpty = null)
  39255. {
  39256. $this->onEmpty = $onEmpty;
  39257. }
  39258. public function write($input)
  39259. {
  39260. if (null === $input) {
  39261. return;
  39262. }
  39263. if ($this->isClosed()) {
  39264. throw new RuntimeException(sprintf('"%s" is closed.', static::class));
  39265. }
  39266. $this->input[] = ProcessUtils::validateInput(__METHOD__, $input);
  39267. }
  39268. public function close()
  39269. {
  39270. $this->open = false;
  39271. }
  39272. public function isClosed()
  39273. {
  39274. return !$this->open;
  39275. }
  39276. public function getIterator()
  39277. {
  39278. $this->open = true;
  39279. while ($this->open || $this->input) {
  39280. if (!$this->input) {
  39281. yield '';
  39282. continue;
  39283. }
  39284. $current = array_shift($this->input);
  39285. if ($current instanceof \Iterator) {
  39286. foreach ($current as $cur) {
  39287. yield $cur;
  39288. }
  39289. } else {
  39290. yield $current;
  39291. }
  39292. if (!$this->input && $this->open && null !== $onEmpty = $this->onEmpty) {
  39293. $this->write($onEmpty($this));
  39294. }
  39295. }
  39296. }
  39297. }
  39298. <?php
  39299. namespace Symfony\Component\Process\Pipes;
  39300. interface PipesInterface
  39301. {
  39302. const CHUNK_SIZE = 16384;
  39303. public function getDescriptors();
  39304. public function getFiles();
  39305. public function readAndWrite($blocking, $close = false);
  39306. public function areOpen();
  39307. public function haveReadSupport();
  39308. public function close();
  39309. }
  39310. <?php
  39311. namespace Symfony\Component\Process\Pipes;
  39312. use Symfony\Component\Process\Exception\RuntimeException;
  39313. use Symfony\Component\Process\Process;
  39314. class WindowsPipes extends AbstractPipes
  39315. {
  39316. private $files = [];
  39317. private $fileHandles = [];
  39318. private $lockHandles = [];
  39319. private $readBytes = [
  39320. Process::STDOUT => 0,
  39321. Process::STDERR => 0,
  39322. ];
  39323. private $haveReadSupport;
  39324. public function __construct($input, $haveReadSupport)
  39325. {
  39326. $this->haveReadSupport = (bool) $haveReadSupport;
  39327. if ($this->haveReadSupport) {
  39328. $pipes = [
  39329. Process::STDOUT => Process::OUT,
  39330. Process::STDERR => Process::ERR,
  39331. ];
  39332. $tmpDir = sys_get_temp_dir();
  39333. $lastError = 'unknown reason';
  39334. set_error_handler(function ($type, $msg) use (&$lastError) { $lastError = $msg; });
  39335. for ($i = 0;; ++$i) {
  39336. foreach ($pipes as $pipe => $name) {
  39337. $file = sprintf('%s\\sf_proc_%02X.%s', $tmpDir, $i, $name);
  39338. if (!$h = fopen($file.'.lock', 'w')) {
  39339. restore_error_handler();
  39340. throw new RuntimeException('A temporary file could not be opened to write the process output: '.$lastError);
  39341. }
  39342. if (!flock($h, LOCK_EX | LOCK_NB)) {
  39343. continue 2;
  39344. }
  39345. if (isset($this->lockHandles[$pipe])) {
  39346. flock($this->lockHandles[$pipe], LOCK_UN);
  39347. fclose($this->lockHandles[$pipe]);
  39348. }
  39349. $this->lockHandles[$pipe] = $h;
  39350. if (!fclose(fopen($file, 'w')) || !$h = fopen($file, 'r')) {
  39351. flock($this->lockHandles[$pipe], LOCK_UN);
  39352. fclose($this->lockHandles[$pipe]);
  39353. unset($this->lockHandles[$pipe]);
  39354. continue 2;
  39355. }
  39356. $this->fileHandles[$pipe] = $h;
  39357. $this->files[$pipe] = $file;
  39358. }
  39359. break;
  39360. }
  39361. restore_error_handler();
  39362. }
  39363. parent::__construct($input);
  39364. }
  39365. public function __destruct()
  39366. {
  39367. $this->close();
  39368. }
  39369. public function getDescriptors()
  39370. {
  39371. if (!$this->haveReadSupport) {
  39372. $nullstream = fopen('NUL', 'c');
  39373. return [
  39374. ['pipe', 'r'],
  39375. $nullstream,
  39376. $nullstream,
  39377. ];
  39378. }
  39379. return [
  39380. ['pipe', 'r'],
  39381. ['file', 'NUL', 'w'],
  39382. ['file', 'NUL', 'w'],
  39383. ];
  39384. }
  39385. public function getFiles()
  39386. {
  39387. return $this->files;
  39388. }
  39389. public function readAndWrite($blocking, $close = false)
  39390. {
  39391. $this->unblock();
  39392. $w = $this->write();
  39393. $read = $r = $e = [];
  39394. if ($blocking) {
  39395. if ($w) {
  39396. @stream_select($r, $w, $e, 0, Process::TIMEOUT_PRECISION * 1E6);
  39397. } elseif ($this->fileHandles) {
  39398. usleep(Process::TIMEOUT_PRECISION * 1E6);
  39399. }
  39400. }
  39401. foreach ($this->fileHandles as $type => $fileHandle) {
  39402. $data = stream_get_contents($fileHandle, -1, $this->readBytes[$type]);
  39403. if (isset($data[0])) {
  39404. $this->readBytes[$type] += \strlen($data);
  39405. $read[$type] = $data;
  39406. }
  39407. if ($close) {
  39408. ftruncate($fileHandle, 0);
  39409. fclose($fileHandle);
  39410. flock($this->lockHandles[$type], LOCK_UN);
  39411. fclose($this->lockHandles[$type]);
  39412. unset($this->fileHandles[$type], $this->lockHandles[$type]);
  39413. }
  39414. }
  39415. return $read;
  39416. }
  39417. public function haveReadSupport()
  39418. {
  39419. return $this->haveReadSupport;
  39420. }
  39421. public function areOpen()
  39422. {
  39423. return $this->pipes && $this->fileHandles;
  39424. }
  39425. public function close()
  39426. {
  39427. parent::close();
  39428. foreach ($this->fileHandles as $type => $handle) {
  39429. ftruncate($handle, 0);
  39430. fclose($handle);
  39431. flock($this->lockHandles[$type], LOCK_UN);
  39432. fclose($this->lockHandles[$type]);
  39433. }
  39434. $this->fileHandles = $this->lockHandles = [];
  39435. }
  39436. }
  39437. <?php
  39438. namespace Symfony\Component\Process\Pipes;
  39439. use Symfony\Component\Process\Exception\InvalidArgumentException;
  39440. abstract class AbstractPipes implements PipesInterface
  39441. {
  39442. public $pipes = [];
  39443. private $inputBuffer = '';
  39444. private $input;
  39445. private $blocked = true;
  39446. private $lastError;
  39447. public function __construct($input)
  39448. {
  39449. if (\is_resource($input) || $input instanceof \Iterator) {
  39450. $this->input = $input;
  39451. } elseif (\is_string($input)) {
  39452. $this->inputBuffer = $input;
  39453. } else {
  39454. $this->inputBuffer = (string) $input;
  39455. }
  39456. }
  39457. public function close()
  39458. {
  39459. foreach ($this->pipes as $pipe) {
  39460. fclose($pipe);
  39461. }
  39462. $this->pipes = [];
  39463. }
  39464. protected function hasSystemCallBeenInterrupted()
  39465. {
  39466. $lastError = $this->lastError;
  39467. $this->lastError = null;
  39468. return null !== $lastError && false !== stripos($lastError, 'interrupted system call');
  39469. }
  39470. protected function unblock()
  39471. {
  39472. if (!$this->blocked) {
  39473. return;
  39474. }
  39475. foreach ($this->pipes as $pipe) {
  39476. stream_set_blocking($pipe, 0);
  39477. }
  39478. if (\is_resource($this->input)) {
  39479. stream_set_blocking($this->input, 0);
  39480. }
  39481. $this->blocked = false;
  39482. }
  39483. protected function write()
  39484. {
  39485. if (!isset($this->pipes[0])) {
  39486. return null;
  39487. }
  39488. $input = $this->input;
  39489. if ($input instanceof \Iterator) {
  39490. if (!$input->valid()) {
  39491. $input = null;
  39492. } elseif (\is_resource($input = $input->current())) {
  39493. stream_set_blocking($input, 0);
  39494. } elseif (!isset($this->inputBuffer[0])) {
  39495. if (!\is_string($input)) {
  39496. if (!is_scalar($input)) {
  39497. throw new InvalidArgumentException(sprintf('"%s" yielded a value of type "%s", but only scalars and stream resources are supported.', \get_class($this->input), \gettype($input)));
  39498. }
  39499. $input = (string) $input;
  39500. }
  39501. $this->inputBuffer = $input;
  39502. $this->input->next();
  39503. $input = null;
  39504. } else {
  39505. $input = null;
  39506. }
  39507. }
  39508. $r = $e = [];
  39509. $w = [$this->pipes[0]];
  39510. if (false === @stream_select($r, $w, $e, 0, 0)) {
  39511. return null;
  39512. }
  39513. foreach ($w as $stdin) {
  39514. if (isset($this->inputBuffer[0])) {
  39515. $written = fwrite($stdin, $this->inputBuffer);
  39516. $this->inputBuffer = substr($this->inputBuffer, $written);
  39517. if (isset($this->inputBuffer[0])) {
  39518. return [$this->pipes[0]];
  39519. }
  39520. }
  39521. if ($input) {
  39522. for (;;) {
  39523. $data = fread($input, self::CHUNK_SIZE);
  39524. if (!isset($data[0])) {
  39525. break;
  39526. }
  39527. $written = fwrite($stdin, $data);
  39528. $data = substr($data, $written);
  39529. if (isset($data[0])) {
  39530. $this->inputBuffer = $data;
  39531. return [$this->pipes[0]];
  39532. }
  39533. }
  39534. if (feof($input)) {
  39535. if ($this->input instanceof \Iterator) {
  39536. $this->input->next();
  39537. } else {
  39538. $this->input = null;
  39539. }
  39540. }
  39541. }
  39542. }
  39543. if (!isset($this->inputBuffer[0]) && !($this->input instanceof \Iterator ? $this->input->valid() : $this->input)) {
  39544. $this->input = null;
  39545. fclose($this->pipes[0]);
  39546. unset($this->pipes[0]);
  39547. } elseif (!$w) {
  39548. return [$this->pipes[0]];
  39549. }
  39550. return null;
  39551. }
  39552. public function handleError($type, $msg)
  39553. {
  39554. $this->lastError = $msg;
  39555. }
  39556. }
  39557. <?php
  39558. namespace Symfony\Component\Process\Pipes;
  39559. use Symfony\Component\Process\Process;
  39560. class UnixPipes extends AbstractPipes
  39561. {
  39562. private $ttyMode;
  39563. private $ptyMode;
  39564. private $haveReadSupport;
  39565. public function __construct($ttyMode, $ptyMode, $input, $haveReadSupport)
  39566. {
  39567. $this->ttyMode = (bool) $ttyMode;
  39568. $this->ptyMode = (bool) $ptyMode;
  39569. $this->haveReadSupport = (bool) $haveReadSupport;
  39570. parent::__construct($input);
  39571. }
  39572. public function __destruct()
  39573. {
  39574. $this->close();
  39575. }
  39576. public function getDescriptors()
  39577. {
  39578. if (!$this->haveReadSupport) {
  39579. $nullstream = fopen('/dev/null', 'c');
  39580. return [
  39581. ['pipe', 'r'],
  39582. $nullstream,
  39583. $nullstream,
  39584. ];
  39585. }
  39586. if ($this->ttyMode) {
  39587. return [
  39588. ['file', '/dev/tty', 'r'],
  39589. ['file', '/dev/tty', 'w'],
  39590. ['file', '/dev/tty', 'w'],
  39591. ];
  39592. }
  39593. if ($this->ptyMode && Process::isPtySupported()) {
  39594. return [
  39595. ['pty'],
  39596. ['pty'],
  39597. ['pty'],
  39598. ];
  39599. }
  39600. return [
  39601. ['pipe', 'r'],
  39602. ['pipe', 'w'],
  39603. ['pipe', 'w'],
  39604. ];
  39605. }
  39606. public function getFiles()
  39607. {
  39608. return [];
  39609. }
  39610. public function readAndWrite($blocking, $close = false)
  39611. {
  39612. $this->unblock();
  39613. $w = $this->write();
  39614. $read = $e = [];
  39615. $r = $this->pipes;
  39616. unset($r[0]);
  39617. set_error_handler([$this, 'handleError']);
  39618. if (($r || $w) && false === stream_select($r, $w, $e, 0, $blocking ? Process::TIMEOUT_PRECISION * 1E6 : 0)) {
  39619. restore_error_handler();
  39620. if (!$this->hasSystemCallBeenInterrupted()) {
  39621. $this->pipes = [];
  39622. }
  39623. return $read;
  39624. }
  39625. restore_error_handler();
  39626. foreach ($r as $pipe) {
  39627. $read[$type = array_search($pipe, $this->pipes, true)] = '';
  39628. do {
  39629. $data = @fread($pipe, self::CHUNK_SIZE);
  39630. $read[$type] .= $data;
  39631. } while (isset($data[0]) && ($close || isset($data[self::CHUNK_SIZE - 1])));
  39632. if (!isset($read[$type][0])) {
  39633. unset($read[$type]);
  39634. }
  39635. if ($close && feof($pipe)) {
  39636. fclose($pipe);
  39637. unset($this->pipes[$type]);
  39638. }
  39639. }
  39640. return $read;
  39641. }
  39642. public function haveReadSupport()
  39643. {
  39644. return $this->haveReadSupport;
  39645. }
  39646. public function areOpen()
  39647. {
  39648. return (bool) $this->pipes;
  39649. }
  39650. }
  39651. <?php
  39652. namespace Symfony\Component\Process;
  39653. use Symfony\Component\Process\Exception\RuntimeException;
  39654. class PhpProcess extends Process
  39655. {
  39656. public function __construct($script, $cwd = null, array $env = null, $timeout = 60, array $options = null)
  39657. {
  39658. $executableFinder = new PhpExecutableFinder();
  39659. if (false === $php = $executableFinder->find(false)) {
  39660. $php = null;
  39661. } else {
  39662. $php = array_merge([$php], $executableFinder->findArguments());
  39663. }
  39664. if ('phpdbg' === \PHP_SAPI) {
  39665. $file = tempnam(sys_get_temp_dir(), 'dbg');
  39666. file_put_contents($file, $script);
  39667. register_shutdown_function('unlink', $file);
  39668. $php[] = $file;
  39669. $script = null;
  39670. }
  39671. if (null !== $options) {
  39672. @trigger_error(sprintf('The $options parameter of the %s constructor is deprecated since Symfony 3.3 and will be removed in 4.0.', __CLASS__), E_USER_DEPRECATED);
  39673. }
  39674. parent::__construct($php, $cwd, $env, $script, $timeout, $options);
  39675. }
  39676. public function setPhpBinary($php)
  39677. {
  39678. $this->setCommandLine($php);
  39679. }
  39680. public function start(callable $callback = null)
  39681. {
  39682. if (null === $this->getCommandLine()) {
  39683. throw new RuntimeException('Unable to find the PHP executable.');
  39684. }
  39685. $env = 1 < \func_num_args() ? func_get_arg(1) : null;
  39686. parent::start($callback, $env);
  39687. }
  39688. }
  39689. <?php
  39690. namespace Symfony\Component\Process\Exception;
  39691. use Symfony\Component\Process\Process;
  39692. class ProcessTimedOutException extends RuntimeException
  39693. {
  39694. const TYPE_GENERAL = 1;
  39695. const TYPE_IDLE = 2;
  39696. private $process;
  39697. private $timeoutType;
  39698. public function __construct(Process $process, $timeoutType)
  39699. {
  39700. $this->process = $process;
  39701. $this->timeoutType = $timeoutType;
  39702. parent::__construct(sprintf(
  39703. 'The process "%s" exceeded the timeout of %s seconds.',
  39704. $process->getCommandLine(),
  39705. $this->getExceededTimeout()
  39706. ));
  39707. }
  39708. public function getProcess()
  39709. {
  39710. return $this->process;
  39711. }
  39712. public function isGeneralTimeout()
  39713. {
  39714. return self::TYPE_GENERAL === $this->timeoutType;
  39715. }
  39716. public function isIdleTimeout()
  39717. {
  39718. return self::TYPE_IDLE === $this->timeoutType;
  39719. }
  39720. public function getExceededTimeout()
  39721. {
  39722. switch ($this->timeoutType) {
  39723. case self::TYPE_GENERAL:
  39724. return $this->process->getTimeout();
  39725. case self::TYPE_IDLE:
  39726. return $this->process->getIdleTimeout();
  39727. default:
  39728. throw new \LogicException(sprintf('Unknown timeout type "%d".', $this->timeoutType));
  39729. }
  39730. }
  39731. }
  39732. <?php
  39733. namespace Symfony\Component\Process\Exception;
  39734. use Symfony\Component\Process\Process;
  39735. class ProcessFailedException extends RuntimeException
  39736. {
  39737. private $process;
  39738. public function __construct(Process $process)
  39739. {
  39740. if ($process->isSuccessful()) {
  39741. throw new InvalidArgumentException('Expected a failed process, but the given process was successful.');
  39742. }
  39743. $error = sprintf('The command "%s" failed.'."\n\nExit Code: %s(%s)\n\nWorking directory: %s",
  39744. $process->getCommandLine(),
  39745. $process->getExitCode(),
  39746. $process->getExitCodeText(),
  39747. $process->getWorkingDirectory()
  39748. );
  39749. if (!$process->isOutputDisabled()) {
  39750. $error .= sprintf("\n\nOutput:\n================\n%s\n\nError Output:\n================\n%s",
  39751. $process->getOutput(),
  39752. $process->getErrorOutput()
  39753. );
  39754. }
  39755. parent::__construct($error);
  39756. $this->process = $process;
  39757. }
  39758. public function getProcess()
  39759. {
  39760. return $this->process;
  39761. }
  39762. }
  39763. <?php
  39764. namespace Symfony\Component\Process\Exception;
  39765. interface ExceptionInterface
  39766. {
  39767. }
  39768. <?php
  39769. namespace Symfony\Component\Process\Exception;
  39770. class RuntimeException extends \RuntimeException implements ExceptionInterface
  39771. {
  39772. }
  39773. <?php
  39774. namespace Symfony\Component\Process\Exception;
  39775. class LogicException extends \LogicException implements ExceptionInterface
  39776. {
  39777. }
  39778. <?php
  39779. namespace Symfony\Component\Process\Exception;
  39780. class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface
  39781. {
  39782. }
  39783. <?php
  39784. namespace Symfony\Component\Process;
  39785. use Symfony\Component\Process\Exception\InvalidArgumentException;
  39786. class ProcessUtils
  39787. {
  39788. private function __construct()
  39789. {
  39790. }
  39791. public static function escapeArgument($argument)
  39792. {
  39793. @trigger_error('The '.__METHOD__.'() method is deprecated since Symfony 3.3 and will be removed in 4.0. Use a command line array or give env vars to the Process::start/run() method instead.', E_USER_DEPRECATED);
  39794. if ('\\' === \DIRECTORY_SEPARATOR) {
  39795. if ('' === $argument) {
  39796. return escapeshellarg($argument);
  39797. }
  39798. $escapedArgument = '';
  39799. $quote = false;
  39800. foreach (preg_split('/(")/', $argument, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE) as $part) {
  39801. if ('"' === $part) {
  39802. $escapedArgument .= '\\"';
  39803. } elseif (self::isSurroundedBy($part, '%')) {
  39804. $escapedArgument .= '^%"'.substr($part, 1, -1).'"^%';
  39805. } else {
  39806. if ('\\' === substr($part, -1)) {
  39807. $part .= '\\';
  39808. }
  39809. $quote = true;
  39810. $escapedArgument .= $part;
  39811. }
  39812. }
  39813. if ($quote) {
  39814. $escapedArgument = '"'.$escapedArgument.'"';
  39815. }
  39816. return $escapedArgument;
  39817. }
  39818. return "'".str_replace("'", "'\\''", $argument)."'";
  39819. }
  39820. public static function validateInput($caller, $input)
  39821. {
  39822. if (null !== $input) {
  39823. if (\is_resource($input)) {
  39824. return $input;
  39825. }
  39826. if (\is_string($input)) {
  39827. return $input;
  39828. }
  39829. if (is_scalar($input)) {
  39830. return (string) $input;
  39831. }
  39832. if ($input instanceof Process) {
  39833. return $input->getIterator($input::ITER_SKIP_ERR);
  39834. }
  39835. if ($input instanceof \Iterator) {
  39836. return $input;
  39837. }
  39838. if ($input instanceof \Traversable) {
  39839. return new \IteratorIterator($input);
  39840. }
  39841. throw new InvalidArgumentException(sprintf('"%s" only accepts strings, Traversable objects or stream resources.', $caller));
  39842. }
  39843. return $input;
  39844. }
  39845. private static function isSurroundedBy($arg, $char)
  39846. {
  39847. return 2 < \strlen($arg) && $char === $arg[0] && $char === $arg[\strlen($arg) - 1];
  39848. }
  39849. }
  39850. <?php
  39851. namespace Symfony\Component\Process;
  39852. @trigger_error(sprintf('The %s class is deprecated since Symfony 3.4 and will be removed in 4.0. Use the Process class instead.', ProcessBuilder::class), E_USER_DEPRECATED);
  39853. use Symfony\Component\Process\Exception\InvalidArgumentException;
  39854. use Symfony\Component\Process\Exception\LogicException;
  39855. class ProcessBuilder
  39856. {
  39857. private $arguments;
  39858. private $cwd;
  39859. private $env = [];
  39860. private $input;
  39861. private $timeout = 60;
  39862. private $options;
  39863. private $inheritEnv = true;
  39864. private $prefix = [];
  39865. private $outputDisabled = false;
  39866. public function __construct(array $arguments = [])
  39867. {
  39868. $this->arguments = $arguments;
  39869. }
  39870. public static function create(array $arguments = [])
  39871. {
  39872. return new static($arguments);
  39873. }
  39874. public function add($argument)
  39875. {
  39876. $this->arguments[] = $argument;
  39877. return $this;
  39878. }
  39879. public function setPrefix($prefix)
  39880. {
  39881. $this->prefix = \is_array($prefix) ? $prefix : [$prefix];
  39882. return $this;
  39883. }
  39884. public function setArguments(array $arguments)
  39885. {
  39886. $this->arguments = $arguments;
  39887. return $this;
  39888. }
  39889. public function setWorkingDirectory($cwd)
  39890. {
  39891. $this->cwd = $cwd;
  39892. return $this;
  39893. }
  39894. public function inheritEnvironmentVariables($inheritEnv = true)
  39895. {
  39896. $this->inheritEnv = $inheritEnv;
  39897. return $this;
  39898. }
  39899. public function setEnv($name, $value)
  39900. {
  39901. $this->env[$name] = $value;
  39902. return $this;
  39903. }
  39904. public function addEnvironmentVariables(array $variables)
  39905. {
  39906. $this->env = array_replace($this->env, $variables);
  39907. return $this;
  39908. }
  39909. public function setInput($input)
  39910. {
  39911. $this->input = ProcessUtils::validateInput(__METHOD__, $input);
  39912. return $this;
  39913. }
  39914. public function setTimeout($timeout)
  39915. {
  39916. if (null === $timeout) {
  39917. $this->timeout = null;
  39918. return $this;
  39919. }
  39920. $timeout = (float) $timeout;
  39921. if ($timeout < 0) {
  39922. throw new InvalidArgumentException('The timeout value must be a valid positive integer or float number.');
  39923. }
  39924. $this->timeout = $timeout;
  39925. return $this;
  39926. }
  39927. public function setOption($name, $value)
  39928. {
  39929. $this->options[$name] = $value;
  39930. return $this;
  39931. }
  39932. public function disableOutput()
  39933. {
  39934. $this->outputDisabled = true;
  39935. return $this;
  39936. }
  39937. public function enableOutput()
  39938. {
  39939. $this->outputDisabled = false;
  39940. return $this;
  39941. }
  39942. public function getProcess()
  39943. {
  39944. if (0 === \count($this->prefix) && 0 === \count($this->arguments)) {
  39945. throw new LogicException('You must add() command arguments before calling getProcess().');
  39946. }
  39947. $arguments = array_merge($this->prefix, $this->arguments);
  39948. $process = new Process($arguments, $this->cwd, $this->env, $this->input, $this->timeout, $this->options);
  39949. $process->setCommandLine($process->getCommandLine());
  39950. if ($this->inheritEnv) {
  39951. $process->inheritEnvironmentVariables();
  39952. }
  39953. if ($this->outputDisabled) {
  39954. $process->disableOutput();
  39955. }
  39956. return $process;
  39957. }
  39958. }
  39959. <?php
  39960. namespace Symfony\Component\Process;
  39961. /**
  39962. @gmail
  39963. */
  39964. class PhpExecutableFinder
  39965. {
  39966. private $executableFinder;
  39967. public function __construct()
  39968. {
  39969. $this->executableFinder = new ExecutableFinder();
  39970. }
  39971. public function find($includeArgs = true)
  39972. {
  39973. $args = $this->findArguments();
  39974. $args = $includeArgs && $args ? ' '.implode(' ', $args) : '';
  39975. if (\defined('HHVM_VERSION')) {
  39976. return (getenv('PHP_BINARY') ?: PHP_BINARY).$args;
  39977. }
  39978. if (PHP_BINARY && \in_array(\PHP_SAPI, ['cli', 'cli-server', 'phpdbg'], true)) {
  39979. return PHP_BINARY.$args;
  39980. }
  39981. if ($php = getenv('PHP_PATH')) {
  39982. if (!@is_executable($php)) {
  39983. return false;
  39984. }
  39985. return $php;
  39986. }
  39987. if ($php = getenv('PHP_PEAR_PHP_BIN')) {
  39988. if (@is_executable($php)) {
  39989. return $php;
  39990. }
  39991. }
  39992. if (@is_executable($php = PHP_BINDIR.('\\' === \DIRECTORY_SEPARATOR ? '\\php.exe' : '/php'))) {
  39993. return $php;
  39994. }
  39995. $dirs = [PHP_BINDIR];
  39996. if ('\\' === \DIRECTORY_SEPARATOR) {
  39997. $dirs[] = 'C:\xampp\php\\';
  39998. }
  39999. return $this->executableFinder->find('php', false, $dirs);
  40000. }
  40001. public function findArguments()
  40002. {
  40003. $arguments = [];
  40004. if (\defined('HHVM_VERSION')) {
  40005. $arguments[] = '--php';
  40006. } elseif ('phpdbg' === \PHP_SAPI) {
  40007. $arguments[] = '-qrr';
  40008. }
  40009. return $arguments;
  40010. }
  40011. }
  40012. <?php
  40013. namespace Symfony\Component\Process;
  40014. /**
  40015. @gmail
  40016. */
  40017. class ExecutableFinder
  40018. {
  40019. private $suffixes = ['.exe', '.bat', '.cmd', '.com'];
  40020. public function setSuffixes(array $suffixes)
  40021. {
  40022. $this->suffixes = $suffixes;
  40023. }
  40024. public function addSuffix($suffix)
  40025. {
  40026. $this->suffixes[] = $suffix;
  40027. }
  40028. public function find($name, $default = null, array $extraDirs = [])
  40029. {
  40030. if (ini_get('open_basedir')) {
  40031. $searchPath = array_merge(explode(PATH_SEPARATOR, ini_get('open_basedir')), $extraDirs);
  40032. $dirs = [];
  40033. foreach ($searchPath as $path) {
  40034. if (@is_dir($path)) {
  40035. $dirs[] = $path;
  40036. } else {
  40037. if (basename($path) == $name && @is_executable($path)) {
  40038. return $path;
  40039. }
  40040. }
  40041. }
  40042. } else {
  40043. $dirs = array_merge(
  40044. explode(PATH_SEPARATOR, getenv('PATH') ?: getenv('Path')),
  40045. $extraDirs
  40046. );
  40047. }
  40048. $suffixes = [''];
  40049. if ('\\' === \DIRECTORY_SEPARATOR) {
  40050. $pathExt = getenv('PATHEXT');
  40051. $suffixes = array_merge($pathExt ? explode(PATH_SEPARATOR, $pathExt) : $this->suffixes, $suffixes);
  40052. }
  40053. foreach ($suffixes as $suffix) {
  40054. foreach ($dirs as $dir) {
  40055. if (@is_file($file = $dir.\DIRECTORY_SEPARATOR.$name.$suffix) && ('\\' === \DIRECTORY_SEPARATOR || @is_executable($file))) {
  40056. return $file;
  40057. }
  40058. }
  40059. }
  40060. return $default;
  40061. }
  40062. }
  40063. <?php
  40064. namespace Symfony\Component\Process;
  40065. use Symfony\Component\Process\Exception\InvalidArgumentException;
  40066. use Symfony\Component\Process\Exception\LogicException;
  40067. use Symfony\Component\Process\Exception\ProcessFailedException;
  40068. use Symfony\Component\Process\Exception\ProcessTimedOutException;
  40069. use Symfony\Component\Process\Exception\RuntimeException;
  40070. use Symfony\Component\Process\Pipes\PipesInterface;
  40071. use Symfony\Component\Process\Pipes\UnixPipes;
  40072. use Symfony\Component\Process\Pipes\WindowsPipes;
  40073. /**
  40074. @gmail
  40075. */
  40076. class Process implements \IteratorAggregate
  40077. {
  40078. const ERR = 'err';
  40079. const OUT = 'out';
  40080. const STATUS_READY = 'ready';
  40081. const STATUS_STARTED = 'started';
  40082. const STATUS_TERMINATED = 'terminated';
  40083. const STDIN = 0;
  40084. const STDOUT = 1;
  40085. const STDERR = 2;
  40086. const TIMEOUT_PRECISION = 0.2;
  40087. const ITER_NON_BLOCKING = 1;
  40088. const ITER_KEEP_OUTPUT = 2;
  40089. const ITER_SKIP_OUT = 4;
  40090. const ITER_SKIP_ERR = 8;
  40091. private $callback;
  40092. private $hasCallback = false;
  40093. private $commandline;
  40094. private $cwd;
  40095. private $env;
  40096. private $input;
  40097. private $starttime;
  40098. private $lastOutputTime;
  40099. private $timeout;
  40100. private $idleTimeout;
  40101. private $options = ['suppress_errors' => true];
  40102. private $exitcode;
  40103. private $fallbackStatus = [];
  40104. private $processInformation;
  40105. private $outputDisabled = false;
  40106. private $stdout;
  40107. private $stderr;
  40108. private $enhanceWindowsCompatibility = true;
  40109. private $enhanceSigchildCompatibility;
  40110. private $process;
  40111. private $status = self::STATUS_READY;
  40112. private $incrementalOutputOffset = 0;
  40113. private $incrementalErrorOutputOffset = 0;
  40114. private $tty = false;
  40115. private $pty;
  40116. private $inheritEnv = false;
  40117. private $useFileHandles = false;
  40118. private $processPipes;
  40119. private $latestSignal;
  40120. private static $sigchild;
  40121. public static $exitCodes = [
  40122. 0 => 'OK',
  40123. 1 => 'General error',
  40124. 2 => 'Misuse of shell builtins',
  40125. 126 => 'Invoked command cannot execute',
  40126. 127 => 'Command not found',
  40127. 128 => 'Invalid exit argument',
  40128. 129 => 'Hangup',
  40129. 130 => 'Interrupt',
  40130. 131 => 'Quit and dump core',
  40131. 132 => 'Illegal instruction',
  40132. 133 => 'Trace/breakpoint trap',
  40133. 134 => 'Process aborted',
  40134. 135 => 'Bus error: "access to undefined portion of memory object"',
  40135. 136 => 'Floating point exception: "erroneous arithmetic operation"',
  40136. 137 => 'Kill (terminate immediately)',
  40137. 138 => 'User-defined 1',
  40138. 139 => 'Segmentation violation',
  40139. 140 => 'User-defined 2',
  40140. 141 => 'Write to pipe with no one reading',
  40141. 142 => 'Signal raised by alarm',
  40142. 143 => 'Termination (request to terminate)',
  40143. 145 => 'Child process terminated, stopped (or continued*)',
  40144. 146 => 'Continue if stopped',
  40145. 147 => 'Stop executing temporarily',
  40146. 148 => 'Terminal stop signal',
  40147. 149 => 'Background process attempting to read from tty ("in")',
  40148. 150 => 'Background process attempting to write to tty ("out")',
  40149. 151 => 'Urgent data available on socket',
  40150. 152 => 'CPU time limit exceeded',
  40151. 153 => 'File size limit exceeded',
  40152. 154 => 'Signal raised by timer counting virtual time: "virtual timer expired"',
  40153. 155 => 'Profiling timer expired',
  40154. 157 => 'Pollable event',
  40155. 159 => 'Bad syscall',
  40156. ];
  40157. public function __construct($commandline, $cwd = null, array $env = null, $input = null, $timeout = 60, array $options = null)
  40158. {
  40159. if (!\function_exists('proc_open')) {
  40160. throw new RuntimeException('The Process class relies on proc_open, which is not available on your PHP installation.');
  40161. }
  40162. $this->commandline = $commandline;
  40163. $this->cwd = $cwd;
  40164. if (null === $this->cwd && (\defined('ZEND_THREAD_SAFE') || '\\' === \DIRECTORY_SEPARATOR)) {
  40165. $this->cwd = getcwd();
  40166. }
  40167. if (null !== $env) {
  40168. $this->setEnv($env);
  40169. }
  40170. $this->setInput($input);
  40171. $this->setTimeout($timeout);
  40172. $this->useFileHandles = '\\' === \DIRECTORY_SEPARATOR;
  40173. $this->pty = false;
  40174. $this->enhanceSigchildCompatibility = '\\' !== \DIRECTORY_SEPARATOR && $this->isSigchildEnabled();
  40175. if (null !== $options) {
  40176. @trigger_error(sprintf('The $options parameter of the %s constructor is deprecated since Symfony 3.3 and will be removed in 4.0.', __CLASS__), E_USER_DEPRECATED);
  40177. $this->options = array_replace($this->options, $options);
  40178. }
  40179. }
  40180. public function __destruct()
  40181. {
  40182. $this->stop(0);
  40183. }
  40184. public function __clone()
  40185. {
  40186. $this->resetProcessData();
  40187. }
  40188. public function run($callback = null)
  40189. {
  40190. $env = 1 < \func_num_args() ? func_get_arg(1) : null;
  40191. $this->start($callback, $env);
  40192. return $this->wait();
  40193. }
  40194. public function mustRun(callable $callback = null)
  40195. {
  40196. if (!$this->enhanceSigchildCompatibility && $this->isSigchildEnabled()) {
  40197. throw new RuntimeException('This PHP has been compiled with --enable-sigchild. You must use setEnhanceSigchildCompatibility() to use this method.');
  40198. }
  40199. $env = 1 < \func_num_args() ? func_get_arg(1) : null;
  40200. if (0 !== $this->run($callback, $env)) {
  40201. throw new ProcessFailedException($this);
  40202. }
  40203. return $this;
  40204. }
  40205. public function start(callable $callback = null)
  40206. {
  40207. if ($this->isRunning()) {
  40208. throw new RuntimeException('Process is already running.');
  40209. }
  40210. if (2 <= \func_num_args()) {
  40211. $env = func_get_arg(1);
  40212. } else {
  40213. if (__CLASS__ !== static::class) {
  40214. $r = new \ReflectionMethod($this, __FUNCTION__);
  40215. if (__CLASS__ !== $r->getDeclaringClass()->getName() && (2 > $r->getNumberOfParameters() || 'env' !== $r->getParameters()[1]->name)) {
  40216. @trigger_error(sprintf('The %s::start() method expects a second "$env" argument since Symfony 3.3. It will be made mandatory in 4.0.', static::class), E_USER_DEPRECATED);
  40217. }
  40218. }
  40219. $env = null;
  40220. }
  40221. $this->resetProcessData();
  40222. $this->starttime = $this->lastOutputTime = microtime(true);
  40223. $this->callback = $this->buildCallback($callback);
  40224. $this->hasCallback = null !== $callback;
  40225. $descriptors = $this->getDescriptors();
  40226. $inheritEnv = $this->inheritEnv;
  40227. if (\is_array($commandline = $this->commandline)) {
  40228. $commandline = implode(' ', array_map([$this, 'escapeArgument'], $commandline));
  40229. if ('\\' !== \DIRECTORY_SEPARATOR) {
  40230. $commandline = 'exec '.$commandline;
  40231. }
  40232. }
  40233. if (null === $env) {
  40234. $env = $this->env;
  40235. } else {
  40236. if ($this->env) {
  40237. $env += $this->env;
  40238. }
  40239. $inheritEnv = true;
  40240. }
  40241. if (null !== $env && $inheritEnv) {
  40242. $env += $this->getDefaultEnv();
  40243. } elseif (null !== $env) {
  40244. @trigger_error('Not inheriting environment variables is deprecated since Symfony 3.3 and will always happen in 4.0. Set "Process::inheritEnvironmentVariables()" to true instead.', E_USER_DEPRECATED);
  40245. } else {
  40246. $env = $this->getDefaultEnv();
  40247. }
  40248. if ('\\' === \DIRECTORY_SEPARATOR && $this->enhanceWindowsCompatibility) {
  40249. $this->options['bypass_shell'] = true;
  40250. $commandline = $this->prepareWindowsCommandLine($commandline, $env);
  40251. } elseif (!$this->useFileHandles && $this->enhanceSigchildCompatibility && $this->isSigchildEnabled()) {
  40252. $descriptors[3] = ['pipe', 'w'];
  40253. $commandline = '{ ('.$commandline.') <&3 3<&- 3>/dev/null & } 3<&0;';
  40254. $commandline .= 'pid=$!; echo $pid >&3; wait $pid; code=$?; echo $code >&3; exit $code';
  40255. $ptsWorkaround = fopen(__FILE__, 'r');
  40256. }
  40257. if (\defined('HHVM_VERSION')) {
  40258. $envPairs = $env;
  40259. } else {
  40260. $envPairs = [];
  40261. foreach ($env as $k => $v) {
  40262. if (false !== $v) {
  40263. $envPairs[] = $k.'='.$v;
  40264. }
  40265. }
  40266. }
  40267. if (!is_dir($this->cwd)) {
  40268. @trigger_error('The provided cwd does not exist. Command is currently ran against getcwd(). This behavior is deprecated since Symfony 3.4 and will be removed in 4.0.', E_USER_DEPRECATED);
  40269. }
  40270. $this->process = @proc_open($commandline, $descriptors, $this->processPipes->pipes, $this->cwd, $envPairs, $this->options);
  40271. if (!\is_resource($this->process)) {
  40272. throw new RuntimeException('Unable to launch a new process.');
  40273. }
  40274. $this->status = self::STATUS_STARTED;
  40275. if (isset($descriptors[3])) {
  40276. $this->fallbackStatus['pid'] = (int) fgets($this->processPipes->pipes[3]);
  40277. }
  40278. if ($this->tty) {
  40279. return;
  40280. }
  40281. $this->updateStatus(false);
  40282. $this->checkTimeout();
  40283. }
  40284. public function restart(callable $callback = null)
  40285. {
  40286. if ($this->isRunning()) {
  40287. throw new RuntimeException('Process is already running.');
  40288. }
  40289. $env = 1 < \func_num_args() ? func_get_arg(1) : null;
  40290. $process = clone $this;
  40291. $process->start($callback, $env);
  40292. return $process;
  40293. }
  40294. public function wait(callable $callback = null)
  40295. {
  40296. $this->requireProcessIsStarted(__FUNCTION__);
  40297. $this->updateStatus(false);
  40298. if (null !== $callback) {
  40299. if (!$this->processPipes->haveReadSupport()) {
  40300. $this->stop(0);
  40301. throw new \LogicException('Pass the callback to the Process::start method or enableOutput to use a callback with Process::wait.');
  40302. }
  40303. $this->callback = $this->buildCallback($callback);
  40304. }
  40305. do {
  40306. $this->checkTimeout();
  40307. $running = '\\' === \DIRECTORY_SEPARATOR ? $this->isRunning() : $this->processPipes->areOpen();
  40308. $this->readPipes($running, '\\' !== \DIRECTORY_SEPARATOR || !$running);
  40309. } while ($running);
  40310. while ($this->isRunning()) {
  40311. $this->checkTimeout();
  40312. usleep(1000);
  40313. }
  40314. if ($this->processInformation['signaled'] && $this->processInformation['termsig'] !== $this->latestSignal) {
  40315. throw new RuntimeException(sprintf('The process has been signaled with signal "%s".', $this->processInformation['termsig']));
  40316. }
  40317. return $this->exitcode;
  40318. }
  40319. public function getPid()
  40320. {
  40321. return $this->isRunning() ? $this->processInformation['pid'] : null;
  40322. }
  40323. public function signal($signal)
  40324. {
  40325. $this->doSignal($signal, true);
  40326. return $this;
  40327. }
  40328. public function disableOutput()
  40329. {
  40330. if ($this->isRunning()) {
  40331. throw new RuntimeException('Disabling output while the process is running is not possible.');
  40332. }
  40333. if (null !== $this->idleTimeout) {
  40334. throw new LogicException('Output can not be disabled while an idle timeout is set.');
  40335. }
  40336. $this->outputDisabled = true;
  40337. return $this;
  40338. }
  40339. public function enableOutput()
  40340. {
  40341. if ($this->isRunning()) {
  40342. throw new RuntimeException('Enabling output while the process is running is not possible.');
  40343. }
  40344. $this->outputDisabled = false;
  40345. return $this;
  40346. }
  40347. public function isOutputDisabled()
  40348. {
  40349. return $this->outputDisabled;
  40350. }
  40351. public function getOutput()
  40352. {
  40353. $this->readPipesForOutput(__FUNCTION__);
  40354. if (false === $ret = stream_get_contents($this->stdout, -1, 0)) {
  40355. return '';
  40356. }
  40357. return $ret;
  40358. }
  40359. public function getIncrementalOutput()
  40360. {
  40361. $this->readPipesForOutput(__FUNCTION__);
  40362. $latest = stream_get_contents($this->stdout, -1, $this->incrementalOutputOffset);
  40363. $this->incrementalOutputOffset = ftell($this->stdout);
  40364. if (false === $latest) {
  40365. return '';
  40366. }
  40367. return $latest;
  40368. }
  40369. public function getIterator($flags = 0)
  40370. {
  40371. $this->readPipesForOutput(__FUNCTION__, false);
  40372. $clearOutput = !(self::ITER_KEEP_OUTPUT & $flags);
  40373. $blocking = !(self::ITER_NON_BLOCKING & $flags);
  40374. $yieldOut = !(self::ITER_SKIP_OUT & $flags);
  40375. $yieldErr = !(self::ITER_SKIP_ERR & $flags);
  40376. while (null !== $this->callback || ($yieldOut && !feof($this->stdout)) || ($yieldErr && !feof($this->stderr))) {
  40377. if ($yieldOut) {
  40378. $out = stream_get_contents($this->stdout, -1, $this->incrementalOutputOffset);
  40379. if (isset($out[0])) {
  40380. if ($clearOutput) {
  40381. $this->clearOutput();
  40382. } else {
  40383. $this->incrementalOutputOffset = ftell($this->stdout);
  40384. }
  40385. yield self::OUT => $out;
  40386. }
  40387. }
  40388. if ($yieldErr) {
  40389. $err = stream_get_contents($this->stderr, -1, $this->incrementalErrorOutputOffset);
  40390. if (isset($err[0])) {
  40391. if ($clearOutput) {
  40392. $this->clearErrorOutput();
  40393. } else {
  40394. $this->incrementalErrorOutputOffset = ftell($this->stderr);
  40395. }
  40396. yield self::ERR => $err;
  40397. }
  40398. }
  40399. if (!$blocking && !isset($out[0]) && !isset($err[0])) {
  40400. yield self::OUT => '';
  40401. }
  40402. $this->checkTimeout();
  40403. $this->readPipesForOutput(__FUNCTION__, $blocking);
  40404. }
  40405. }
  40406. public function clearOutput()
  40407. {
  40408. ftruncate($this->stdout, 0);
  40409. fseek($this->stdout, 0);
  40410. $this->incrementalOutputOffset = 0;
  40411. return $this;
  40412. }
  40413. public function getErrorOutput()
  40414. {
  40415. $this->readPipesForOutput(__FUNCTION__);
  40416. if (false === $ret = stream_get_contents($this->stderr, -1, 0)) {
  40417. return '';
  40418. }
  40419. return $ret;
  40420. }
  40421. public function getIncrementalErrorOutput()
  40422. {
  40423. $this->readPipesForOutput(__FUNCTION__);
  40424. $latest = stream_get_contents($this->stderr, -1, $this->incrementalErrorOutputOffset);
  40425. $this->incrementalErrorOutputOffset = ftell($this->stderr);
  40426. if (false === $latest) {
  40427. return '';
  40428. }
  40429. return $latest;
  40430. }
  40431. public function clearErrorOutput()
  40432. {
  40433. ftruncate($this->stderr, 0);
  40434. fseek($this->stderr, 0);
  40435. $this->incrementalErrorOutputOffset = 0;
  40436. return $this;
  40437. }
  40438. public function getExitCode()
  40439. {
  40440. if (!$this->enhanceSigchildCompatibility && $this->isSigchildEnabled()) {
  40441. throw new RuntimeException('This PHP has been compiled with --enable-sigchild. You must use setEnhanceSigchildCompatibility() to use this method.');
  40442. }
  40443. $this->updateStatus(false);
  40444. return $this->exitcode;
  40445. }
  40446. public function getExitCodeText()
  40447. {
  40448. if (null === $exitcode = $this->getExitCode()) {
  40449. return null;
  40450. }
  40451. return isset(self::$exitCodes[$exitcode]) ? self::$exitCodes[$exitcode] : 'Unknown error';
  40452. }
  40453. public function isSuccessful()
  40454. {
  40455. return 0 === $this->getExitCode();
  40456. }
  40457. public function hasBeenSignaled()
  40458. {
  40459. $this->requireProcessIsTerminated(__FUNCTION__);
  40460. if (!$this->enhanceSigchildCompatibility && $this->isSigchildEnabled()) {
  40461. throw new RuntimeException('This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved.');
  40462. }
  40463. return $this->processInformation['signaled'];
  40464. }
  40465. public function getTermSignal()
  40466. {
  40467. $this->requireProcessIsTerminated(__FUNCTION__);
  40468. if ($this->isSigchildEnabled() && (!$this->enhanceSigchildCompatibility || -1 === $this->processInformation['termsig'])) {
  40469. throw new RuntimeException('This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved.');
  40470. }
  40471. return $this->processInformation['termsig'];
  40472. }
  40473. public function hasBeenStopped()
  40474. {
  40475. $this->requireProcessIsTerminated(__FUNCTION__);
  40476. return $this->processInformation['stopped'];
  40477. }
  40478. public function getStopSignal()
  40479. {
  40480. $this->requireProcessIsTerminated(__FUNCTION__);
  40481. return $this->processInformation['stopsig'];
  40482. }
  40483. public function isRunning()
  40484. {
  40485. if (self::STATUS_STARTED !== $this->status) {
  40486. return false;
  40487. }
  40488. $this->updateStatus(false);
  40489. return $this->processInformation['running'];
  40490. }
  40491. public function isStarted()
  40492. {
  40493. return self::STATUS_READY != $this->status;
  40494. }
  40495. public function isTerminated()
  40496. {
  40497. $this->updateStatus(false);
  40498. return self::STATUS_TERMINATED == $this->status;
  40499. }
  40500. public function getStatus()
  40501. {
  40502. $this->updateStatus(false);
  40503. return $this->status;
  40504. }
  40505. public function stop($timeout = 10, $signal = null)
  40506. {
  40507. $timeoutMicro = microtime(true) + $timeout;
  40508. if ($this->isRunning()) {
  40509. $this->doSignal(15, false);
  40510. do {
  40511. usleep(1000);
  40512. } while ($this->isRunning() && microtime(true) < $timeoutMicro);
  40513. if ($this->isRunning()) {
  40514. $this->doSignal($signal ?: 9, false);
  40515. }
  40516. }
  40517. if ($this->isRunning()) {
  40518. if (isset($this->fallbackStatus['pid'])) {
  40519. unset($this->fallbackStatus['pid']);
  40520. return $this->stop(0, $signal);
  40521. }
  40522. $this->close();
  40523. }
  40524. return $this->exitcode;
  40525. }
  40526. public function addOutput($line)
  40527. {
  40528. $this->lastOutputTime = microtime(true);
  40529. fseek($this->stdout, 0, SEEK_END);
  40530. fwrite($this->stdout, $line);
  40531. fseek($this->stdout, $this->incrementalOutputOffset);
  40532. }
  40533. public function addErrorOutput($line)
  40534. {
  40535. $this->lastOutputTime = microtime(true);
  40536. fseek($this->stderr, 0, SEEK_END);
  40537. fwrite($this->stderr, $line);
  40538. fseek($this->stderr, $this->incrementalErrorOutputOffset);
  40539. }
  40540. public function getCommandLine()
  40541. {
  40542. return \is_array($this->commandline) ? implode(' ', array_map([$this, 'escapeArgument'], $this->commandline)) : $this->commandline;
  40543. }
  40544. public function setCommandLine($commandline)
  40545. {
  40546. $this->commandline = $commandline;
  40547. return $this;
  40548. }
  40549. public function getTimeout()
  40550. {
  40551. return $this->timeout;
  40552. }
  40553. public function getIdleTimeout()
  40554. {
  40555. return $this->idleTimeout;
  40556. }
  40557. public function setTimeout($timeout)
  40558. {
  40559. $this->timeout = $this->validateTimeout($timeout);
  40560. return $this;
  40561. }
  40562. public function setIdleTimeout($timeout)
  40563. {
  40564. if (null !== $timeout && $this->outputDisabled) {
  40565. throw new LogicException('Idle timeout can not be set while the output is disabled.');
  40566. }
  40567. $this->idleTimeout = $this->validateTimeout($timeout);
  40568. return $this;
  40569. }
  40570. public function setTty($tty)
  40571. {
  40572. if ('\\' === \DIRECTORY_SEPARATOR && $tty) {
  40573. throw new RuntimeException('TTY mode is not supported on Windows platform.');
  40574. }
  40575. if ($tty) {
  40576. static $isTtySupported;
  40577. if (null === $isTtySupported) {
  40578. $isTtySupported = (bool) @proc_open('echo 1 >/dev/null', [['file', '/dev/tty', 'r'], ['file', '/dev/tty', 'w'], ['file', '/dev/tty', 'w']], $pipes);
  40579. }
  40580. if (!$isTtySupported) {
  40581. throw new RuntimeException('TTY mode requires /dev/tty to be read/writable.');
  40582. }
  40583. }
  40584. $this->tty = (bool) $tty;
  40585. return $this;
  40586. }
  40587. public function isTty()
  40588. {
  40589. return $this->tty;
  40590. }
  40591. public function setPty($bool)
  40592. {
  40593. $this->pty = (bool) $bool;
  40594. return $this;
  40595. }
  40596. public function isPty()
  40597. {
  40598. return $this->pty;
  40599. }
  40600. public function getWorkingDirectory()
  40601. {
  40602. if (null === $this->cwd) {
  40603. return getcwd() ?: null;
  40604. }
  40605. return $this->cwd;
  40606. }
  40607. public function setWorkingDirectory($cwd)
  40608. {
  40609. $this->cwd = $cwd;
  40610. return $this;
  40611. }
  40612. public function getEnv()
  40613. {
  40614. return $this->env;
  40615. }
  40616. public function setEnv(array $env)
  40617. {
  40618. $env = array_filter($env, function ($value) {
  40619. return !\is_array($value);
  40620. });
  40621. $this->env = $env;
  40622. return $this;
  40623. }
  40624. public function getInput()
  40625. {
  40626. return $this->input;
  40627. }
  40628. public function setInput($input)
  40629. {
  40630. if ($this->isRunning()) {
  40631. throw new LogicException('Input can not be set while the process is running.');
  40632. }
  40633. $this->input = ProcessUtils::validateInput(__METHOD__, $input);
  40634. return $this;
  40635. }
  40636. public function getOptions()
  40637. {
  40638. @trigger_error(sprintf('The %s() method is deprecated since Symfony 3.3 and will be removed in 4.0.', __METHOD__), E_USER_DEPRECATED);
  40639. return $this->options;
  40640. }
  40641. public function setOptions(array $options)
  40642. {
  40643. @trigger_error(sprintf('The %s() method is deprecated since Symfony 3.3 and will be removed in 4.0.', __METHOD__), E_USER_DEPRECATED);
  40644. $this->options = $options;
  40645. return $this;
  40646. }
  40647. public function getEnhanceWindowsCompatibility()
  40648. {
  40649. @trigger_error(sprintf('The %s() method is deprecated since Symfony 3.3 and will be removed in 4.0. Enhanced Windows compatibility will always be enabled.', __METHOD__), E_USER_DEPRECATED);
  40650. return $this->enhanceWindowsCompatibility;
  40651. }
  40652. public function setEnhanceWindowsCompatibility($enhance)
  40653. {
  40654. @trigger_error(sprintf('The %s() method is deprecated since Symfony 3.3 and will be removed in 4.0. Enhanced Windows compatibility will always be enabled.', __METHOD__), E_USER_DEPRECATED);
  40655. $this->enhanceWindowsCompatibility = (bool) $enhance;
  40656. return $this;
  40657. }
  40658. public function getEnhanceSigchildCompatibility()
  40659. {
  40660. @trigger_error(sprintf('The %s() method is deprecated since Symfony 3.3 and will be removed in 4.0. Sigchild compatibility will always be enabled.', __METHOD__), E_USER_DEPRECATED);
  40661. return $this->enhanceSigchildCompatibility;
  40662. }
  40663. public function setEnhanceSigchildCompatibility($enhance)
  40664. {
  40665. @trigger_error(sprintf('The %s() method is deprecated since Symfony 3.3 and will be removed in 4.0. Sigchild compatibility will always be enabled.', __METHOD__), E_USER_DEPRECATED);
  40666. $this->enhanceSigchildCompatibility = (bool) $enhance;
  40667. return $this;
  40668. }
  40669. public function inheritEnvironmentVariables($inheritEnv = true)
  40670. {
  40671. if (!$inheritEnv) {
  40672. @trigger_error('Not inheriting environment variables is deprecated since Symfony 3.3 and will always happen in 4.0. Set "Process::inheritEnvironmentVariables()" to true instead.', E_USER_DEPRECATED);
  40673. }
  40674. $this->inheritEnv = (bool) $inheritEnv;
  40675. return $this;
  40676. }
  40677. public function areEnvironmentVariablesInherited()
  40678. {
  40679. @trigger_error(sprintf('The %s() method is deprecated since Symfony 3.3 and will be removed in 4.0. Environment variables will always be inherited.', __METHOD__), E_USER_DEPRECATED);
  40680. return $this->inheritEnv;
  40681. }
  40682. public function checkTimeout()
  40683. {
  40684. if (self::STATUS_STARTED !== $this->status) {
  40685. return;
  40686. }
  40687. if (null !== $this->timeout && $this->timeout < microtime(true) - $this->starttime) {
  40688. $this->stop(0);
  40689. throw new ProcessTimedOutException($this, ProcessTimedOutException::TYPE_GENERAL);
  40690. }
  40691. if (null !== $this->idleTimeout && $this->idleTimeout < microtime(true) - $this->lastOutputTime) {
  40692. $this->stop(0);
  40693. throw new ProcessTimedOutException($this, ProcessTimedOutException::TYPE_IDLE);
  40694. }
  40695. }
  40696. public static function isPtySupported()
  40697. {
  40698. static $result;
  40699. if (null !== $result) {
  40700. return $result;
  40701. }
  40702. if ('\\' === \DIRECTORY_SEPARATOR) {
  40703. return $result = false;
  40704. }
  40705. return $result = (bool) @proc_open('echo 1 >/dev/null', [['pty'], ['pty'], ['pty']], $pipes);
  40706. }
  40707. private function getDescriptors()
  40708. {
  40709. if ($this->input instanceof \Iterator) {
  40710. $this->input->rewind();
  40711. }
  40712. if ('\\' === \DIRECTORY_SEPARATOR) {
  40713. $this->processPipes = new WindowsPipes($this->input, !$this->outputDisabled || $this->hasCallback);
  40714. } else {
  40715. $this->processPipes = new UnixPipes($this->isTty(), $this->isPty(), $this->input, !$this->outputDisabled || $this->hasCallback);
  40716. }
  40717. return $this->processPipes->getDescriptors();
  40718. }
  40719. protected function buildCallback(callable $callback = null)
  40720. {
  40721. if ($this->outputDisabled) {
  40722. return function ($type, $data) use ($callback) {
  40723. if (null !== $callback) {
  40724. \call_user_func($callback, $type, $data);
  40725. }
  40726. };
  40727. }
  40728. $out = self::OUT;
  40729. return function ($type, $data) use ($callback, $out) {
  40730. if ($out == $type) {
  40731. $this->addOutput($data);
  40732. } else {
  40733. $this->addErrorOutput($data);
  40734. }
  40735. if (null !== $callback) {
  40736. \call_user_func($callback, $type, $data);
  40737. }
  40738. };
  40739. }
  40740. protected function updateStatus($blocking)
  40741. {
  40742. if (self::STATUS_STARTED !== $this->status) {
  40743. return;
  40744. }
  40745. $this->processInformation = proc_get_status($this->process);
  40746. $running = $this->processInformation['running'];
  40747. $this->readPipes($running && $blocking, '\\' !== \DIRECTORY_SEPARATOR || !$running);
  40748. if ($this->fallbackStatus && $this->enhanceSigchildCompatibility && $this->isSigchildEnabled()) {
  40749. $this->processInformation = $this->fallbackStatus + $this->processInformation;
  40750. }
  40751. if (!$running) {
  40752. $this->close();
  40753. }
  40754. }
  40755. protected function isSigchildEnabled()
  40756. {
  40757. if (null !== self::$sigchild) {
  40758. return self::$sigchild;
  40759. }
  40760. if (!\function_exists('phpinfo') || \defined('HHVM_VERSION')) {
  40761. return self::$sigchild = false;
  40762. }
  40763. ob_start();
  40764. phpinfo(INFO_GENERAL);
  40765. return self::$sigchild = false !== strpos(ob_get_clean(), '--enable-sigchild');
  40766. }
  40767. private function readPipesForOutput($caller, $blocking = false)
  40768. {
  40769. if ($this->outputDisabled) {
  40770. throw new LogicException('Output has been disabled.');
  40771. }
  40772. $this->requireProcessIsStarted($caller);
  40773. $this->updateStatus($blocking);
  40774. }
  40775. private function validateTimeout($timeout)
  40776. {
  40777. $timeout = (float) $timeout;
  40778. if (0.0 === $timeout) {
  40779. $timeout = null;
  40780. } elseif ($timeout < 0) {
  40781. throw new InvalidArgumentException('The timeout value must be a valid positive integer or float number.');
  40782. }
  40783. return $timeout;
  40784. }
  40785. private function readPipes($blocking, $close)
  40786. {
  40787. $result = $this->processPipes->readAndWrite($blocking, $close);
  40788. $callback = $this->callback;
  40789. foreach ($result as $type => $data) {
  40790. if (3 !== $type) {
  40791. $callback(self::STDOUT === $type ? self::OUT : self::ERR, $data);
  40792. } elseif (!isset($this->fallbackStatus['signaled'])) {
  40793. $this->fallbackStatus['exitcode'] = (int) $data;
  40794. }
  40795. }
  40796. }
  40797. private function close()
  40798. {
  40799. $this->processPipes->close();
  40800. if (\is_resource($this->process)) {
  40801. proc_close($this->process);
  40802. }
  40803. $this->exitcode = $this->processInformation['exitcode'];
  40804. $this->status = self::STATUS_TERMINATED;
  40805. if (-1 === $this->exitcode) {
  40806. if ($this->processInformation['signaled'] && 0 < $this->processInformation['termsig']) {
  40807. $this->exitcode = 128 + $this->processInformation['termsig'];
  40808. } elseif ($this->enhanceSigchildCompatibility && $this->isSigchildEnabled()) {
  40809. $this->processInformation['signaled'] = true;
  40810. $this->processInformation['termsig'] = -1;
  40811. }
  40812. }
  40813. $this->callback = null;
  40814. return $this->exitcode;
  40815. }
  40816. private function resetProcessData()
  40817. {
  40818. $this->starttime = null;
  40819. $this->callback = null;
  40820. $this->exitcode = null;
  40821. $this->fallbackStatus = [];
  40822. $this->processInformation = null;
  40823. $this->stdout = fopen('php://temp/maxmemory:'.(1024 * 1024), 'w+b');
  40824. $this->stderr = fopen('php://temp/maxmemory:'.(1024 * 1024), 'w+b');
  40825. $this->process = null;
  40826. $this->latestSignal = null;
  40827. $this->status = self::STATUS_READY;
  40828. $this->incrementalOutputOffset = 0;
  40829. $this->incrementalErrorOutputOffset = 0;
  40830. }
  40831. private function doSignal($signal, $throwException)
  40832. {
  40833. if (null === $pid = $this->getPid()) {
  40834. if ($throwException) {
  40835. throw new LogicException('Can not send signal on a non running process.');
  40836. }
  40837. return false;
  40838. }
  40839. if ('\\' === \DIRECTORY_SEPARATOR) {
  40840. exec(sprintf('taskkill /F /T /PID %d 2>&1', $pid), $output, $exitCode);
  40841. if ($exitCode && $this->isRunning()) {
  40842. if ($throwException) {
  40843. throw new RuntimeException(sprintf('Unable to kill the process (%s).', implode(' ', $output)));
  40844. }
  40845. return false;
  40846. }
  40847. } else {
  40848. if (!$this->enhanceSigchildCompatibility || !$this->isSigchildEnabled()) {
  40849. $ok = @proc_terminate($this->process, $signal);
  40850. } elseif (\function_exists('posix_kill')) {
  40851. $ok = @posix_kill($pid, $signal);
  40852. } elseif ($ok = proc_open(sprintf('kill -%d %d', $signal, $pid), [2 => ['pipe', 'w']], $pipes)) {
  40853. $ok = false === fgets($pipes[2]);
  40854. }
  40855. if (!$ok) {
  40856. if ($throwException) {
  40857. throw new RuntimeException(sprintf('Error while sending signal `%s`.', $signal));
  40858. }
  40859. return false;
  40860. }
  40861. }
  40862. $this->latestSignal = (int) $signal;
  40863. $this->fallbackStatus['signaled'] = true;
  40864. $this->fallbackStatus['exitcode'] = -1;
  40865. $this->fallbackStatus['termsig'] = $this->latestSignal;
  40866. return true;
  40867. }
  40868. private function prepareWindowsCommandLine($cmd, array &$env)
  40869. {
  40870. $uid = uniqid('', true);
  40871. $varCount = 0;
  40872. $varCache = [];
  40873. $cmd = preg_replace_callback(
  40874. '/"(?:(
  40875. [^"%!^]*+
  40876. (?:
  40877. (?: !LF! | "(?:\^[%!^])?+" )
  40878. [^"%!^]*+
  40879. )++
  40880. ) | [^"]*+ )"/x',
  40881. function ($m) use (&$env, &$varCache, &$varCount, $uid) {
  40882. if (!isset($m[1])) {
  40883. return $m[0];
  40884. }
  40885. if (isset($varCache[$m[0]])) {
  40886. return $varCache[$m[0]];
  40887. }
  40888. if (false !== strpos($value = $m[1], "\0")) {
  40889. $value = str_replace("\0", '?', $value);
  40890. }
  40891. if (false === strpbrk($value, "\"%!\n")) {
  40892. return '"'.$value.'"';
  40893. }
  40894. $value = str_replace(['!LF!', '"^!"', '"^%"', '"^^"', '""'], ["\n", '!', '%', '^', '"'], $value);
  40895. $value = '"'.preg_replace('/(\\\\*)"/', '$1$1\\"', $value).'"';
  40896. $var = $uid.++$varCount;
  40897. $env[$var] = $value;
  40898. return $varCache[$m[0]] = '!'.$var.'!';
  40899. },
  40900. $cmd
  40901. );
  40902. $cmd = 'cmd /V:ON /E:ON /D /C ('.str_replace("\n", ' ', $cmd).')';
  40903. foreach ($this->processPipes->getFiles() as $offset => $filename) {
  40904. $cmd .= ' '.$offset.'>"'.$filename.'"';
  40905. }
  40906. return $cmd;
  40907. }
  40908. private function requireProcessIsStarted($functionName)
  40909. {
  40910. if (!$this->isStarted()) {
  40911. throw new LogicException(sprintf('Process must be started before calling "%s()".', $functionName));
  40912. }
  40913. }
  40914. private function requireProcessIsTerminated($functionName)
  40915. {
  40916. if (!$this->isTerminated()) {
  40917. throw new LogicException(sprintf('Process must be terminated before calling "%s()".', $functionName));
  40918. }
  40919. }
  40920. private function escapeArgument($argument)
  40921. {
  40922. if ('\\' !== \DIRECTORY_SEPARATOR) {
  40923. return "'".str_replace("'", "'\\''", $argument)."'";
  40924. }
  40925. if ('' === $argument = (string) $argument) {
  40926. return '""';
  40927. }
  40928. if (false !== strpos($argument, "\0")) {
  40929. $argument = str_replace("\0", '?', $argument);
  40930. }
  40931. if (!preg_match('/[\/()%!^"<>&|\s]/', $argument)) {
  40932. return $argument;
  40933. }
  40934. $argument = preg_replace('/(\\\\+)$/', '$1$1', $argument);
  40935. return '"'.str_replace(['"', '^', '%', '!', "\n"], ['""', '"^^"', '"^%"', '"^!"', '!LF!'], $argument).'"';
  40936. }
  40937. private function getDefaultEnv()
  40938. {
  40939. $env = [];
  40940. foreach ($_SERVER as $k => $v) {
  40941. if (\is_string($v) && false !== $v = getenv($k)) {
  40942. $env[$k] = $v;
  40943. }
  40944. }
  40945. foreach ($_ENV as $k => $v) {
  40946. if (\is_string($v)) {
  40947. $env[$k] = $v;
  40948. }
  40949. }
  40950. return $env;
  40951. }
  40952. }
  40953. <?php
  40954. use Symfony\Polyfill\Php70 as p;
  40955. if (PHP_VERSION_ID >= 70000) {
  40956. return;
  40957. }
  40958. if (!defined('PHP_INT_MIN')) {
  40959. define('PHP_INT_MIN', ~PHP_INT_MAX);
  40960. }
  40961. if (!function_exists('intdiv')) {
  40962. function intdiv($dividend, $divisor) { return p\Php70::intdiv($dividend, $divisor); }
  40963. }
  40964. if (!function_exists('preg_replace_callback_array')) {
  40965. function preg_replace_callback_array(array $patterns, $subject, $limit = -1, &$count = 0) { return p\Php70::preg_replace_callback_array($patterns, $subject, $limit, $count); }
  40966. }
  40967. if (!function_exists('error_clear_last')) {
  40968. function error_clear_last() { return p\Php70::error_clear_last(); }
  40969. }
  40970. <?php
  40971. namespace Symfony\Polyfill\Php70;
  40972. final class Php70
  40973. {
  40974. public static function intdiv($dividend, $divisor)
  40975. {
  40976. $dividend = self::intArg($dividend, __FUNCTION__, 1);
  40977. $divisor = self::intArg($divisor, __FUNCTION__, 2);
  40978. if (0 === $divisor) {
  40979. throw new \DivisionByZeroError('Division by zero');
  40980. }
  40981. if (-1 === $divisor && ~PHP_INT_MAX === $dividend) {
  40982. throw new \ArithmeticError('Division of PHP_INT_MIN by -1 is not an integer');
  40983. }
  40984. return ($dividend - ($dividend % $divisor)) / $divisor;
  40985. }
  40986. public static function preg_replace_callback_array(array $patterns, $subject, $limit = -1, &$count = 0)
  40987. {
  40988. $count = 0;
  40989. $result = (string) $subject;
  40990. if (0 === $limit = self::intArg($limit, __FUNCTION__, 3)) {
  40991. return $result;
  40992. }
  40993. foreach ($patterns as $pattern => $callback) {
  40994. $result = preg_replace_callback($pattern, $callback, $result, $limit, $c);
  40995. $count += $c;
  40996. }
  40997. return $result;
  40998. }
  40999. public static function error_clear_last()
  41000. {
  41001. static $handler;
  41002. if (!$handler) {
  41003. $handler = function () { return false; };
  41004. }
  41005. set_error_handler($handler);
  41006. @trigger_error('');
  41007. restore_error_handler();
  41008. }
  41009. private static function intArg($value, $caller, $pos)
  41010. {
  41011. if (\is_int($value)) {
  41012. return $value;
  41013. }
  41014. if (!\is_numeric($value) || PHP_INT_MAX <= ($value += 0) || ~PHP_INT_MAX >= $value) {
  41015. throw new \TypeError(sprintf('%s() expects parameter %d to be integer, %s given', $caller, $pos, \gettype($value)));
  41016. }
  41017. return (int) $value;
  41018. }
  41019. }
  41020. <?php
  41021. class DivisionByZeroError extends Error
  41022. {
  41023. }
  41024. <?php
  41025. class ArithmeticError extends Error
  41026. {
  41027. }
  41028. <?php
  41029. class ParseError extends Error
  41030. {
  41031. }
  41032. <?php
  41033. class AssertionError extends Error
  41034. {
  41035. }
  41036. <?php
  41037. interface SessionUpdateTimestampHandlerInterface
  41038. {
  41039. public function validateId($key);
  41040. public function updateTimestamp($key, $val);
  41041. }
  41042. <?php
  41043. class TypeError extends Error
  41044. {
  41045. }
  41046. <?php
  41047. class Error extends Exception
  41048. {
  41049. }
  41050. <?php
  41051. namespace Symfony\Component\Console;
  41052. use Symfony\Component\Console\Command\Command;
  41053. use Symfony\Component\Console\Command\HelpCommand;
  41054. use Symfony\Component\Console\Command\ListCommand;
  41055. use Symfony\Component\Console\CommandLoader\CommandLoaderInterface;
  41056. use Symfony\Component\Console\Event\ConsoleCommandEvent;
  41057. use Symfony\Component\Console\Event\ConsoleErrorEvent;
  41058. use Symfony\Component\Console\Event\ConsoleExceptionEvent;
  41059. use Symfony\Component\Console\Event\ConsoleTerminateEvent;
  41060. use Symfony\Component\Console\Exception\CommandNotFoundException;
  41061. use Symfony\Component\Console\Exception\ExceptionInterface;
  41062. use Symfony\Component\Console\Exception\LogicException;
  41063. use Symfony\Component\Console\Formatter\OutputFormatter;
  41064. use Symfony\Component\Console\Helper\DebugFormatterHelper;
  41065. use Symfony\Component\Console\Helper\FormatterHelper;
  41066. use Symfony\Component\Console\Helper\Helper;
  41067. use Symfony\Component\Console\Helper\HelperSet;
  41068. use Symfony\Component\Console\Helper\ProcessHelper;
  41069. use Symfony\Component\Console\Helper\QuestionHelper;
  41070. use Symfony\Component\Console\Input\ArgvInput;
  41071. use Symfony\Component\Console\Input\ArrayInput;
  41072. use Symfony\Component\Console\Input\InputArgument;
  41073. use Symfony\Component\Console\Input\InputAwareInterface;
  41074. use Symfony\Component\Console\Input\InputDefinition;
  41075. use Symfony\Component\Console\Input\InputInterface;
  41076. use Symfony\Component\Console\Input\InputOption;
  41077. use Symfony\Component\Console\Input\StreamableInputInterface;
  41078. use Symfony\Component\Console\Output\ConsoleOutput;
  41079. use Symfony\Component\Console\Output\ConsoleOutputInterface;
  41080. use Symfony\Component\Console\Output\OutputInterface;
  41081. use Symfony\Component\Debug\ErrorHandler;
  41082. use Symfony\Component\Debug\Exception\FatalThrowableError;
  41083. use Symfony\Component\EventDispatcher\EventDispatcherInterface;
  41084. class Application
  41085. {
  41086. private $commands = [];
  41087. private $wantHelps = false;
  41088. private $runningCommand;
  41089. private $name;
  41090. private $version;
  41091. private $commandLoader;
  41092. private $catchExceptions = true;
  41093. private $autoExit = true;
  41094. private $definition;
  41095. private $helperSet;
  41096. private $dispatcher;
  41097. private $terminal;
  41098. private $defaultCommand;
  41099. private $singleCommand = false;
  41100. private $initialized;
  41101. public function __construct($name = 'UNKNOWN', $version = 'UNKNOWN')
  41102. {
  41103. $this->name = $name;
  41104. $this->version = $version;
  41105. $this->terminal = new Terminal();
  41106. $this->defaultCommand = 'list';
  41107. }
  41108. public function setDispatcher(EventDispatcherInterface $dispatcher)
  41109. {
  41110. $this->dispatcher = $dispatcher;
  41111. }
  41112. public function setCommandLoader(CommandLoaderInterface $commandLoader)
  41113. {
  41114. $this->commandLoader = $commandLoader;
  41115. }
  41116. public function run(InputInterface $input = null, OutputInterface $output = null)
  41117. {
  41118. putenv('LINES='.$this->terminal->getHeight());
  41119. putenv('COLUMNS='.$this->terminal->getWidth());
  41120. if (null === $input) {
  41121. $input = new ArgvInput();
  41122. }
  41123. if (null === $output) {
  41124. $output = new ConsoleOutput();
  41125. }
  41126. $renderException = function ($e) use ($output) {
  41127. if (!$e instanceof \Exception) {
  41128. $e = class_exists(FatalThrowableError::class) ? new FatalThrowableError($e) : new \ErrorException($e->getMessage(), $e->getCode(), E_ERROR, $e->getFile(), $e->getLine());
  41129. }
  41130. if ($output instanceof ConsoleOutputInterface) {
  41131. $this->renderException($e, $output->getErrorOutput());
  41132. } else {
  41133. $this->renderException($e, $output);
  41134. }
  41135. };
  41136. if ($phpHandler = set_exception_handler($renderException)) {
  41137. restore_exception_handler();
  41138. if (!\is_array($phpHandler) || !$phpHandler[0] instanceof ErrorHandler) {
  41139. $debugHandler = true;
  41140. } elseif ($debugHandler = $phpHandler[0]->setExceptionHandler($renderException)) {
  41141. $phpHandler[0]->setExceptionHandler($debugHandler);
  41142. }
  41143. }
  41144. if (null !== $this->dispatcher && $this->dispatcher->hasListeners(ConsoleEvents::EXCEPTION)) {
  41145. @trigger_error(sprintf('The "ConsoleEvents::EXCEPTION" event is deprecated since Symfony 3.3 and will be removed in 4.0. Listen to the "ConsoleEvents::ERROR" event instead.'), E_USER_DEPRECATED);
  41146. }
  41147. $this->configureIO($input, $output);
  41148. try {
  41149. $exitCode = $this->doRun($input, $output);
  41150. } catch (\Exception $e) {
  41151. if (!$this->catchExceptions) {
  41152. throw $e;
  41153. }
  41154. $renderException($e);
  41155. $exitCode = $e->getCode();
  41156. if (is_numeric($exitCode)) {
  41157. $exitCode = (int) $exitCode;
  41158. if (0 === $exitCode) {
  41159. $exitCode = 1;
  41160. }
  41161. } else {
  41162. $exitCode = 1;
  41163. }
  41164. } finally {
  41165. if (!$phpHandler) {
  41166. if (set_exception_handler($renderException) === $renderException) {
  41167. restore_exception_handler();
  41168. }
  41169. restore_exception_handler();
  41170. } elseif (!$debugHandler) {
  41171. $finalHandler = $phpHandler[0]->setExceptionHandler(null);
  41172. if ($finalHandler !== $renderException) {
  41173. $phpHandler[0]->setExceptionHandler($finalHandler);
  41174. }
  41175. }
  41176. }
  41177. if ($this->autoExit) {
  41178. if ($exitCode > 255) {
  41179. $exitCode = 255;
  41180. }
  41181. exit($exitCode);
  41182. }
  41183. return $exitCode;
  41184. }
  41185. public function doRun(InputInterface $input, OutputInterface $output)
  41186. {
  41187. if (true === $input->hasParameterOption(['--version', '-V'], true)) {
  41188. $output->writeln($this->getLongVersion());
  41189. return 0;
  41190. }
  41191. try {
  41192. $input->bind($this->getDefinition());
  41193. } catch (ExceptionInterface $e) {
  41194. }
  41195. $name = $this->getCommandName($input);
  41196. if (true === $input->hasParameterOption(['--help', '-h'], true)) {
  41197. if (!$name) {
  41198. $name = 'help';
  41199. $input = new ArrayInput(['command_name' => $this->defaultCommand]);
  41200. } else {
  41201. $this->wantHelps = true;
  41202. }
  41203. }
  41204. if (!$name) {
  41205. $name = $this->defaultCommand;
  41206. $definition = $this->getDefinition();
  41207. $definition->setArguments(array_merge(
  41208. $definition->getArguments(),
  41209. [
  41210. 'command' => new InputArgument('command', InputArgument::OPTIONAL, $definition->getArgument('command')->getDescription(), $name),
  41211. ]
  41212. ));
  41213. }
  41214. try {
  41215. $e = $this->runningCommand = null;
  41216. $command = $this->find($name);
  41217. } catch (\Exception $e) {
  41218. } catch (\Throwable $e) {
  41219. }
  41220. if (null !== $e) {
  41221. if (null !== $this->dispatcher) {
  41222. $event = new ConsoleErrorEvent($input, $output, $e);
  41223. $this->dispatcher->dispatch(ConsoleEvents::ERROR, $event);
  41224. $e = $event->getError();
  41225. if (0 === $event->getExitCode()) {
  41226. return 0;
  41227. }
  41228. }
  41229. throw $e;
  41230. }
  41231. $this->runningCommand = $command;
  41232. $exitCode = $this->doRunCommand($command, $input, $output);
  41233. $this->runningCommand = null;
  41234. return $exitCode;
  41235. }
  41236. public function setHelperSet(HelperSet $helperSet)
  41237. {
  41238. $this->helperSet = $helperSet;
  41239. }
  41240. public function getHelperSet()
  41241. {
  41242. if (!$this->helperSet) {
  41243. $this->helperSet = $this->getDefaultHelperSet();
  41244. }
  41245. return $this->helperSet;
  41246. }
  41247. public function setDefinition(InputDefinition $definition)
  41248. {
  41249. $this->definition = $definition;
  41250. }
  41251. public function getDefinition()
  41252. {
  41253. if (!$this->definition) {
  41254. $this->definition = $this->getDefaultInputDefinition();
  41255. }
  41256. if ($this->singleCommand) {
  41257. $inputDefinition = $this->definition;
  41258. $inputDefinition->setArguments();
  41259. return $inputDefinition;
  41260. }
  41261. return $this->definition;
  41262. }
  41263. public function getHelp()
  41264. {
  41265. return $this->getLongVersion();
  41266. }
  41267. public function areExceptionsCaught()
  41268. {
  41269. return $this->catchExceptions;
  41270. }
  41271. public function setCatchExceptions($boolean)
  41272. {
  41273. $this->catchExceptions = (bool) $boolean;
  41274. }
  41275. public function isAutoExitEnabled()
  41276. {
  41277. return $this->autoExit;
  41278. }
  41279. public function setAutoExit($boolean)
  41280. {
  41281. $this->autoExit = (bool) $boolean;
  41282. }
  41283. public function getName()
  41284. {
  41285. return $this->name;
  41286. }
  41287. public function setName($name)
  41288. {
  41289. $this->name = $name;
  41290. }
  41291. public function getVersion()
  41292. {
  41293. return $this->version;
  41294. }
  41295. public function setVersion($version)
  41296. {
  41297. $this->version = $version;
  41298. }
  41299. public function getLongVersion()
  41300. {
  41301. if ('UNKNOWN' !== $this->getName()) {
  41302. if ('UNKNOWN' !== $this->getVersion()) {
  41303. return sprintf('%s <info>%s</info>', $this->getName(), $this->getVersion());
  41304. }
  41305. return $this->getName();
  41306. }
  41307. return 'Console Tool';
  41308. }
  41309. public function register($name)
  41310. {
  41311. return $this->add(new Command($name));
  41312. }
  41313. public function addCommands(array $commands)
  41314. {
  41315. foreach ($commands as $command) {
  41316. $this->add($command);
  41317. }
  41318. }
  41319. public function add(Command $command)
  41320. {
  41321. $this->init();
  41322. $command->setApplication($this);
  41323. if (!$command->isEnabled()) {
  41324. $command->setApplication(null);
  41325. return null;
  41326. }
  41327. $command->getDefinition();
  41328. if (!$command->getName()) {
  41329. throw new LogicException(sprintf('The command defined in "%s" cannot have an empty name.', \get_class($command)));
  41330. }
  41331. $this->commands[$command->getName()] = $command;
  41332. foreach ($command->getAliases() as $alias) {
  41333. $this->commands[$alias] = $command;
  41334. }
  41335. return $command;
  41336. }
  41337. public function get($name)
  41338. {
  41339. $this->init();
  41340. if (!$this->has($name)) {
  41341. throw new CommandNotFoundException(sprintf('The command "%s" does not exist.', $name));
  41342. }
  41343. $command = $this->commands[$name];
  41344. if ($this->wantHelps) {
  41345. $this->wantHelps = false;
  41346. $helpCommand = $this->get('help');
  41347. $helpCommand->setCommand($command);
  41348. return $helpCommand;
  41349. }
  41350. return $command;
  41351. }
  41352. public function has($name)
  41353. {
  41354. $this->init();
  41355. return isset($this->commands[$name]) || ($this->commandLoader && $this->commandLoader->has($name) && $this->add($this->commandLoader->get($name)));
  41356. }
  41357. public function getNamespaces()
  41358. {
  41359. $namespaces = [];
  41360. foreach ($this->all() as $command) {
  41361. if ($command->isHidden()) {
  41362. continue;
  41363. }
  41364. $namespaces = array_merge($namespaces, $this->extractAllNamespaces($command->getName()));
  41365. foreach ($command->getAliases() as $alias) {
  41366. $namespaces = array_merge($namespaces, $this->extractAllNamespaces($alias));
  41367. }
  41368. }
  41369. return array_values(array_unique(array_filter($namespaces)));
  41370. }
  41371. public function findNamespace($namespace)
  41372. {
  41373. $allNamespaces = $this->getNamespaces();
  41374. $expr = preg_replace_callback('{([^:]+|)}', function ($matches) { return preg_quote($matches[1]).'[^:]*'; }, $namespace);
  41375. $namespaces = preg_grep('{^'.$expr.'}', $allNamespaces);
  41376. if (empty($namespaces)) {
  41377. $message = sprintf('There are no commands defined in the "%s" namespace.', $namespace);
  41378. if ($alternatives = $this->findAlternatives($namespace, $allNamespaces)) {
  41379. if (1 == \count($alternatives)) {
  41380. $message .= "\n\nDid you mean this?\n ";
  41381. } else {
  41382. $message .= "\n\nDid you mean one of these?\n ";
  41383. }
  41384. $message .= implode("\n ", $alternatives);
  41385. }
  41386. throw new CommandNotFoundException($message, $alternatives);
  41387. }
  41388. $exact = \in_array($namespace, $namespaces, true);
  41389. if (\count($namespaces) > 1 && !$exact) {
  41390. throw new CommandNotFoundException(sprintf("The namespace \"%s\" is ambiguous.\nDid you mean one of these?\n%s.", $namespace, $this->getAbbreviationSuggestions(array_values($namespaces))), array_values($namespaces));
  41391. }
  41392. return $exact ? $namespace : reset($namespaces);
  41393. }
  41394. public function find($name)
  41395. {
  41396. $this->init();
  41397. $aliases = [];
  41398. foreach ($this->commands as $command) {
  41399. foreach ($command->getAliases() as $alias) {
  41400. if (!$this->has($alias)) {
  41401. $this->commands[$alias] = $command;
  41402. }
  41403. }
  41404. }
  41405. if ($this->has($name)) {
  41406. return $this->get($name);
  41407. }
  41408. $allCommands = $this->commandLoader ? array_merge($this->commandLoader->getNames(), array_keys($this->commands)) : array_keys($this->commands);
  41409. $expr = preg_replace_callback('{([^:]+|)}', function ($matches) { return preg_quote($matches[1]).'[^:]*'; }, $name);
  41410. $commands = preg_grep('{^'.$expr.'}', $allCommands);
  41411. if (empty($commands)) {
  41412. $commands = preg_grep('{^'.$expr.'}i', $allCommands);
  41413. }
  41414. if (empty($commands) || \count(preg_grep('{^'.$expr.'$}i', $commands)) < 1) {
  41415. if (false !== $pos = strrpos($name, ':')) {
  41416. $this->findNamespace(substr($name, 0, $pos));
  41417. }
  41418. $message = sprintf('Command "%s" is not defined.', $name);
  41419. if ($alternatives = $this->findAlternatives($name, $allCommands)) {
  41420. $alternatives = array_filter($alternatives, function ($name) {
  41421. return !$this->get($name)->isHidden();
  41422. });
  41423. if (1 == \count($alternatives)) {
  41424. $message .= "\n\nDid you mean this?\n ";
  41425. } else {
  41426. $message .= "\n\nDid you mean one of these?\n ";
  41427. }
  41428. $message .= implode("\n ", $alternatives);
  41429. }
  41430. throw new CommandNotFoundException($message, array_values($alternatives));
  41431. }
  41432. if (\count($commands) > 1) {
  41433. $commandList = $this->commandLoader ? array_merge(array_flip($this->commandLoader->getNames()), $this->commands) : $this->commands;
  41434. $commands = array_unique(array_filter($commands, function ($nameOrAlias) use (&$commandList, $commands, &$aliases) {
  41435. if (!$commandList[$nameOrAlias] instanceof Command) {
  41436. $commandList[$nameOrAlias] = $this->commandLoader->get($nameOrAlias);
  41437. }
  41438. $commandName = $commandList[$nameOrAlias]->getName();
  41439. $aliases[$nameOrAlias] = $commandName;
  41440. return $commandName === $nameOrAlias || !\in_array($commandName, $commands);
  41441. }));
  41442. }
  41443. $exact = \in_array($name, $commands, true) || isset($aliases[$name]);
  41444. if (\count($commands) > 1 && !$exact) {
  41445. $usableWidth = $this->terminal->getWidth() - 10;
  41446. $abbrevs = array_values($commands);
  41447. $maxLen = 0;
  41448. foreach ($abbrevs as $abbrev) {
  41449. $maxLen = max(Helper::strlen($abbrev), $maxLen);
  41450. }
  41451. $abbrevs = array_map(function ($cmd) use ($commandList, $usableWidth, $maxLen) {
  41452. if ($commandList[$cmd]->isHidden()) {
  41453. return false;
  41454. }
  41455. $abbrev = str_pad($cmd, $maxLen, ' ').' '.$commandList[$cmd]->getDescription();
  41456. return Helper::strlen($abbrev) > $usableWidth ? Helper::substr($abbrev, 0, $usableWidth - 3).'...' : $abbrev;
  41457. }, array_values($commands));
  41458. $suggestions = $this->getAbbreviationSuggestions(array_filter($abbrevs));
  41459. throw new CommandNotFoundException(sprintf("Command \"%s\" is ambiguous.\nDid you mean one of these?\n%s.", $name, $suggestions), array_values($commands));
  41460. }
  41461. return $this->get($exact ? $name : reset($commands));
  41462. }
  41463. public function all($namespace = null)
  41464. {
  41465. $this->init();
  41466. if (null === $namespace) {
  41467. if (!$this->commandLoader) {
  41468. return $this->commands;
  41469. }
  41470. $commands = $this->commands;
  41471. foreach ($this->commandLoader->getNames() as $name) {
  41472. if (!isset($commands[$name]) && $this->has($name)) {
  41473. $commands[$name] = $this->get($name);
  41474. }
  41475. }
  41476. return $commands;
  41477. }
  41478. $commands = [];
  41479. foreach ($this->commands as $name => $command) {
  41480. if ($namespace === $this->extractNamespace($name, substr_count($namespace, ':') + 1)) {
  41481. $commands[$name] = $command;
  41482. }
  41483. }
  41484. if ($this->commandLoader) {
  41485. foreach ($this->commandLoader->getNames() as $name) {
  41486. if (!isset($commands[$name]) && $namespace === $this->extractNamespace($name, substr_count($namespace, ':') + 1) && $this->has($name)) {
  41487. $commands[$name] = $this->get($name);
  41488. }
  41489. }
  41490. }
  41491. return $commands;
  41492. }
  41493. public static function getAbbreviations($names)
  41494. {
  41495. $abbrevs = [];
  41496. foreach ($names as $name) {
  41497. for ($len = \strlen($name); $len > 0; --$len) {
  41498. $abbrev = substr($name, 0, $len);
  41499. $abbrevs[$abbrev][] = $name;
  41500. }
  41501. }
  41502. return $abbrevs;
  41503. }
  41504. public function renderException(\Exception $e, OutputInterface $output)
  41505. {
  41506. $output->writeln('', OutputInterface::VERBOSITY_QUIET);
  41507. $this->doRenderException($e, $output);
  41508. if (null !== $this->runningCommand) {
  41509. $output->writeln(sprintf('<info>%s</info>', sprintf($this->runningCommand->getSynopsis(), $this->getName())), OutputInterface::VERBOSITY_QUIET);
  41510. $output->writeln('', OutputInterface::VERBOSITY_QUIET);
  41511. }
  41512. }
  41513. protected function doRenderException(\Exception $e, OutputInterface $output)
  41514. {
  41515. do {
  41516. $message = trim($e->getMessage());
  41517. if ('' === $message || OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) {
  41518. $title = sprintf(' [%s%s] ', \get_class($e), 0 !== ($code = $e->getCode()) ? ' ('.$code.')' : '');
  41519. $len = Helper::strlen($title);
  41520. } else {
  41521. $len = 0;
  41522. }
  41523. $width = $this->terminal->getWidth() ? $this->terminal->getWidth() - 1 : PHP_INT_MAX;
  41524. if (\defined('HHVM_VERSION') && $width > 1 << 31) {
  41525. $width = 1 << 31;
  41526. }
  41527. $lines = [];
  41528. foreach ('' !== $message ? preg_split('/\r?\n/', $message) : [] as $line) {
  41529. foreach ($this->splitStringByWidth($line, $width - 4) as $line) {
  41530. $lineLength = Helper::strlen($line) + 4;
  41531. $lines[] = [$line, $lineLength];
  41532. $len = max($lineLength, $len);
  41533. }
  41534. }
  41535. $messages = [];
  41536. if (!$e instanceof ExceptionInterface || OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) {
  41537. $messages[] = sprintf('<comment>%s</comment>', OutputFormatter::escape(sprintf('In %s line %s:', basename($e->getFile()) ?: 'n/a', $e->getLine() ?: 'n/a')));
  41538. }
  41539. $messages[] = $emptyLine = sprintf('<error>%s</error>', str_repeat(' ', $len));
  41540. if ('' === $message || OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) {
  41541. $messages[] = sprintf('<error>%s%s</error>', $title, str_repeat(' ', max(0, $len - Helper::strlen($title))));
  41542. }
  41543. foreach ($lines as $line) {
  41544. $messages[] = sprintf('<error> %s %s</error>', OutputFormatter::escape($line[0]), str_repeat(' ', $len - $line[1]));
  41545. }
  41546. $messages[] = $emptyLine;
  41547. $messages[] = '';
  41548. $output->writeln($messages, OutputInterface::VERBOSITY_QUIET);
  41549. if (OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) {
  41550. $output->writeln('<comment>Exception trace:</comment>', OutputInterface::VERBOSITY_QUIET);
  41551. $trace = $e->getTrace();
  41552. array_unshift($trace, [
  41553. 'function' => '',
  41554. 'file' => $e->getFile() ?: 'n/a',
  41555. 'line' => $e->getLine() ?: 'n/a',
  41556. 'args' => [],
  41557. ]);
  41558. for ($i = 0, $count = \count($trace); $i < $count; ++$i) {
  41559. $class = isset($trace[$i]['class']) ? $trace[$i]['class'] : '';
  41560. $type = isset($trace[$i]['type']) ? $trace[$i]['type'] : '';
  41561. $function = isset($trace[$i]['function']) ? $trace[$i]['function'] : '';
  41562. $file = isset($trace[$i]['file']) ? $trace[$i]['file'] : 'n/a';
  41563. $line = isset($trace[$i]['line']) ? $trace[$i]['line'] : 'n/a';
  41564. $output->writeln(sprintf(' %s%s at <info>%s:%s</info>', $class, $function ? $type.$function.'()' : '', $file, $line), OutputInterface::VERBOSITY_QUIET);
  41565. }
  41566. $output->writeln('', OutputInterface::VERBOSITY_QUIET);
  41567. }
  41568. } while ($e = $e->getPrevious());
  41569. }
  41570. protected function getTerminalWidth()
  41571. {
  41572. @trigger_error(sprintf('The "%s()" method is deprecated as of 3.2 and will be removed in 4.0. Create a Terminal instance instead.', __METHOD__), E_USER_DEPRECATED);
  41573. return $this->terminal->getWidth();
  41574. }
  41575. protected function getTerminalHeight()
  41576. {
  41577. @trigger_error(sprintf('The "%s()" method is deprecated as of 3.2 and will be removed in 4.0. Create a Terminal instance instead.', __METHOD__), E_USER_DEPRECATED);
  41578. return $this->terminal->getHeight();
  41579. }
  41580. public function getTerminalDimensions()
  41581. {
  41582. @trigger_error(sprintf('The "%s()" method is deprecated as of 3.2 and will be removed in 4.0. Create a Terminal instance instead.', __METHOD__), E_USER_DEPRECATED);
  41583. return [$this->terminal->getWidth(), $this->terminal->getHeight()];
  41584. }
  41585. public function setTerminalDimensions($width, $height)
  41586. {
  41587. @trigger_error(sprintf('The "%s()" method is deprecated as of 3.2 and will be removed in 4.0. Set the COLUMNS and LINES env vars instead.', __METHOD__), E_USER_DEPRECATED);
  41588. putenv('COLUMNS='.$width);
  41589. putenv('LINES='.$height);
  41590. return $this;
  41591. }
  41592. protected function configureIO(InputInterface $input, OutputInterface $output)
  41593. {
  41594. if (true === $input->hasParameterOption(['--ansi'], true)) {
  41595. $output->setDecorated(true);
  41596. } elseif (true === $input->hasParameterOption(['--no-ansi'], true)) {
  41597. $output->setDecorated(false);
  41598. }
  41599. if (true === $input->hasParameterOption(['--no-interaction', '-n'], true)) {
  41600. $input->setInteractive(false);
  41601. } elseif (\function_exists('posix_isatty')) {
  41602. $inputStream = null;
  41603. if ($input instanceof StreamableInputInterface) {
  41604. $inputStream = $input->getStream();
  41605. }
  41606. if (!$inputStream && $this->getHelperSet()->has('question')) {
  41607. $inputStream = $this->getHelperSet()->get('question')->getInputStream(false);
  41608. }
  41609. if (!@posix_isatty($inputStream) && false === getenv('SHELL_INTERACTIVE')) {
  41610. $input->setInteractive(false);
  41611. }
  41612. }
  41613. switch ($shellVerbosity = (int) getenv('SHELL_VERBOSITY')) {
  41614. case -1: $output->setVerbosity(OutputInterface::VERBOSITY_QUIET); break;
  41615. case 1: $output->setVerbosity(OutputInterface::VERBOSITY_VERBOSE); break;
  41616. case 2: $output->setVerbosity(OutputInterface::VERBOSITY_VERY_VERBOSE); break;
  41617. case 3: $output->setVerbosity(OutputInterface::VERBOSITY_DEBUG); break;
  41618. default: $shellVerbosity = 0; break;
  41619. }
  41620. if (true === $input->hasParameterOption(['--quiet', '-q'], true)) {
  41621. $output->setVerbosity(OutputInterface::VERBOSITY_QUIET);
  41622. $shellVerbosity = -1;
  41623. } else {
  41624. if ($input->hasParameterOption('-vvv', true) || $input->hasParameterOption('--verbose=3', true) || 3 === $input->getParameterOption('--verbose', false, true)) {
  41625. $output->setVerbosity(OutputInterface::VERBOSITY_DEBUG);
  41626. $shellVerbosity = 3;
  41627. } elseif ($input->hasParameterOption('-vv', true) || $input->hasParameterOption('--verbose=2', true) || 2 === $input->getParameterOption('--verbose', false, true)) {
  41628. $output->setVerbosity(OutputInterface::VERBOSITY_VERY_VERBOSE);
  41629. $shellVerbosity = 2;
  41630. } elseif ($input->hasParameterOption('-v', true) || $input->hasParameterOption('--verbose=1', true) || $input->hasParameterOption('--verbose', true) || $input->getParameterOption('--verbose', false, true)) {
  41631. $output->setVerbosity(OutputInterface::VERBOSITY_VERBOSE);
  41632. $shellVerbosity = 1;
  41633. }
  41634. }
  41635. if (-1 === $shellVerbosity) {
  41636. $input->setInteractive(false);
  41637. }
  41638. putenv('SHELL_VERBOSITY='.$shellVerbosity);
  41639. $_ENV['SHELL_VERBOSITY'] = $shellVerbosity;
  41640. $_SERVER['SHELL_VERBOSITY'] = $shellVerbosity;
  41641. }
  41642. protected function doRunCommand(Command $command, InputInterface $input, OutputInterface $output)
  41643. {
  41644. foreach ($command->getHelperSet() as $helper) {
  41645. if ($helper instanceof InputAwareInterface) {
  41646. $helper->setInput($input);
  41647. }
  41648. }
  41649. if (null === $this->dispatcher) {
  41650. return $command->run($input, $output);
  41651. }
  41652. try {
  41653. $command->mergeApplicationDefinition();
  41654. $input->bind($command->getDefinition());
  41655. } catch (ExceptionInterface $e) {
  41656. }
  41657. $event = new ConsoleCommandEvent($command, $input, $output);
  41658. $e = null;
  41659. try {
  41660. $this->dispatcher->dispatch(ConsoleEvents::COMMAND, $event);
  41661. if ($event->commandShouldRun()) {
  41662. $exitCode = $command->run($input, $output);
  41663. } else {
  41664. $exitCode = ConsoleCommandEvent::RETURN_CODE_DISABLED;
  41665. }
  41666. } catch (\Exception $e) {
  41667. } catch (\Throwable $e) {
  41668. }
  41669. if (null !== $e) {
  41670. if ($this->dispatcher->hasListeners(ConsoleEvents::EXCEPTION)) {
  41671. $x = $e instanceof \Exception ? $e : new FatalThrowableError($e);
  41672. $event = new ConsoleExceptionEvent($command, $input, $output, $x, $x->getCode());
  41673. $this->dispatcher->dispatch(ConsoleEvents::EXCEPTION, $event);
  41674. if ($x !== $event->getException()) {
  41675. $e = $event->getException();
  41676. }
  41677. }
  41678. $event = new ConsoleErrorEvent($input, $output, $e, $command);
  41679. $this->dispatcher->dispatch(ConsoleEvents::ERROR, $event);
  41680. $e = $event->getError();
  41681. if (0 === $exitCode = $event->getExitCode()) {
  41682. $e = null;
  41683. }
  41684. }
  41685. $event = new ConsoleTerminateEvent($command, $input, $output, $exitCode);
  41686. $this->dispatcher->dispatch(ConsoleEvents::TERMINATE, $event);
  41687. if (null !== $e) {
  41688. throw $e;
  41689. }
  41690. return $event->getExitCode();
  41691. }
  41692. protected function getCommandName(InputInterface $input)
  41693. {
  41694. return $this->singleCommand ? $this->defaultCommand : $input->getFirstArgument();
  41695. }
  41696. protected function getDefaultInputDefinition()
  41697. {
  41698. return new InputDefinition([
  41699. new InputArgument('command', InputArgument::REQUIRED, 'The command to execute'),
  41700. new InputOption('--help', '-h', InputOption::VALUE_NONE, 'Display this help message'),
  41701. new InputOption('--quiet', '-q', InputOption::VALUE_NONE, 'Do not output any message'),
  41702. 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'),
  41703. new InputOption('--version', '-V', InputOption::VALUE_NONE, 'Display this application version'),
  41704. new InputOption('--ansi', '', InputOption::VALUE_NONE, 'Force ANSI output'),
  41705. new InputOption('--no-ansi', '', InputOption::VALUE_NONE, 'Disable ANSI output'),
  41706. new InputOption('--no-interaction', '-n', InputOption::VALUE_NONE, 'Do not ask any interactive question'),
  41707. ]);
  41708. }
  41709. protected function getDefaultCommands()
  41710. {
  41711. return [new HelpCommand(), new ListCommand()];
  41712. }
  41713. protected function getDefaultHelperSet()
  41714. {
  41715. return new HelperSet([
  41716. new FormatterHelper(),
  41717. new DebugFormatterHelper(),
  41718. new ProcessHelper(),
  41719. new QuestionHelper(),
  41720. ]);
  41721. }
  41722. private function getAbbreviationSuggestions($abbrevs)
  41723. {
  41724. return ' '.implode("\n ", $abbrevs);
  41725. }
  41726. public function extractNamespace($name, $limit = null)
  41727. {
  41728. $parts = explode(':', $name, -1);
  41729. return implode(':', null === $limit ? $parts : \array_slice($parts, 0, $limit));
  41730. }
  41731. private function findAlternatives($name, $collection)
  41732. {
  41733. $threshold = 1e3;
  41734. $alternatives = [];
  41735. $collectionParts = [];
  41736. foreach ($collection as $item) {
  41737. $collectionParts[$item] = explode(':', $item);
  41738. }
  41739. foreach (explode(':', $name) as $i => $subname) {
  41740. foreach ($collectionParts as $collectionName => $parts) {
  41741. $exists = isset($alternatives[$collectionName]);
  41742. if (!isset($parts[$i]) && $exists) {
  41743. $alternatives[$collectionName] += $threshold;
  41744. continue;
  41745. } elseif (!isset($parts[$i])) {
  41746. continue;
  41747. }
  41748. $lev = levenshtein($subname, $parts[$i]);
  41749. if ($lev <= \strlen($subname) / 3 || '' !== $subname && false !== strpos($parts[$i], $subname)) {
  41750. $alternatives[$collectionName] = $exists ? $alternatives[$collectionName] + $lev : $lev;
  41751. } elseif ($exists) {
  41752. $alternatives[$collectionName] += $threshold;
  41753. }
  41754. }
  41755. }
  41756. foreach ($collection as $item) {
  41757. $lev = levenshtein($name, $item);
  41758. if ($lev <= \strlen($name) / 3 || false !== strpos($item, $name)) {
  41759. $alternatives[$item] = isset($alternatives[$item]) ? $alternatives[$item] - $lev : $lev;
  41760. }
  41761. }
  41762. $alternatives = array_filter($alternatives, function ($lev) use ($threshold) { return $lev < 2 * $threshold; });
  41763. ksort($alternatives, SORT_NATURAL | SORT_FLAG_CASE);
  41764. return array_keys($alternatives);
  41765. }
  41766. public function setDefaultCommand($commandName, $isSingleCommand = false)
  41767. {
  41768. $this->defaultCommand = $commandName;
  41769. if ($isSingleCommand) {
  41770. $this->find($commandName);
  41771. $this->singleCommand = true;
  41772. }
  41773. return $this;
  41774. }
  41775. public function isSingleCommand()
  41776. {
  41777. return $this->singleCommand;
  41778. }
  41779. private function splitStringByWidth($string, $width)
  41780. {
  41781. if (false === $encoding = mb_detect_encoding($string, null, true)) {
  41782. return str_split($string, $width);
  41783. }
  41784. $utf8String = mb_convert_encoding($string, 'utf8', $encoding);
  41785. $lines = [];
  41786. $line = '';
  41787. foreach (preg_split('//u', $utf8String) as $char) {
  41788. if (mb_strwidth($line.$char, 'utf8') <= $width) {
  41789. $line .= $char;
  41790. continue;
  41791. }
  41792. $lines[] = str_pad($line, $width);
  41793. $line = $char;
  41794. }
  41795. $lines[] = \count($lines) ? str_pad($line, $width) : $line;
  41796. mb_convert_variables($encoding, 'utf8', $lines);
  41797. return $lines;
  41798. }
  41799. private function extractAllNamespaces($name)
  41800. {
  41801. $parts = explode(':', $name, -1);
  41802. $namespaces = [];
  41803. foreach ($parts as $part) {
  41804. if (\count($namespaces)) {
  41805. $namespaces[] = end($namespaces).':'.$part;
  41806. } else {
  41807. $namespaces[] = $part;
  41808. }
  41809. }
  41810. return $namespaces;
  41811. }
  41812. private function init()
  41813. {
  41814. if ($this->initialized) {
  41815. return;
  41816. }
  41817. $this->initialized = true;
  41818. foreach ($this->getDefaultCommands() as $command) {
  41819. $this->add($command);
  41820. }
  41821. }
  41822. }
  41823. <?php
  41824. namespace Symfony\Component\Console\Formatter;
  41825. use Symfony\Component\Console\Exception\InvalidArgumentException;
  41826. class OutputFormatterStyleStack
  41827. {
  41828. private $styles;
  41829. private $emptyStyle;
  41830. public function __construct(OutputFormatterStyleInterface $emptyStyle = null)
  41831. {
  41832. $this->emptyStyle = $emptyStyle ?: new OutputFormatterStyle();
  41833. $this->reset();
  41834. }
  41835. public function reset()
  41836. {
  41837. $this->styles = [];
  41838. }
  41839. public function push(OutputFormatterStyleInterface $style)
  41840. {
  41841. $this->styles[] = $style;
  41842. }
  41843. public function pop(OutputFormatterStyleInterface $style = null)
  41844. {
  41845. if (empty($this->styles)) {
  41846. return $this->emptyStyle;
  41847. }
  41848. if (null === $style) {
  41849. return array_pop($this->styles);
  41850. }
  41851. foreach (array_reverse($this->styles, true) as $index => $stackedStyle) {
  41852. if ($style->apply('') === $stackedStyle->apply('')) {
  41853. $this->styles = \array_slice($this->styles, 0, $index);
  41854. return $stackedStyle;
  41855. }
  41856. }
  41857. throw new InvalidArgumentException('Incorrectly nested style tag found.');
  41858. }
  41859. public function getCurrent()
  41860. {
  41861. if (empty($this->styles)) {
  41862. return $this->emptyStyle;
  41863. }
  41864. return $this->styles[\count($this->styles) - 1];
  41865. }
  41866. public function setEmptyStyle(OutputFormatterStyleInterface $emptyStyle)
  41867. {
  41868. $this->emptyStyle = $emptyStyle;
  41869. return $this;
  41870. }
  41871. public function getEmptyStyle()
  41872. {
  41873. return $this->emptyStyle;
  41874. }
  41875. }
  41876. <?php
  41877. namespace Symfony\Component\Console\Formatter;
  41878. use Symfony\Component\Console\Exception\InvalidArgumentException;
  41879. class OutputFormatterStyle implements OutputFormatterStyleInterface
  41880. {
  41881. private static $availableForegroundColors = [
  41882. 'black' => ['set' => 30, 'unset' => 39],
  41883. 'red' => ['set' => 31, 'unset' => 39],
  41884. 'green' => ['set' => 32, 'unset' => 39],
  41885. 'yellow' => ['set' => 33, 'unset' => 39],
  41886. 'blue' => ['set' => 34, 'unset' => 39],
  41887. 'magenta' => ['set' => 35, 'unset' => 39],
  41888. 'cyan' => ['set' => 36, 'unset' => 39],
  41889. 'white' => ['set' => 37, 'unset' => 39],
  41890. 'default' => ['set' => 39, 'unset' => 39],
  41891. ];
  41892. private static $availableBackgroundColors = [
  41893. 'black' => ['set' => 40, 'unset' => 49],
  41894. 'red' => ['set' => 41, 'unset' => 49],
  41895. 'green' => ['set' => 42, 'unset' => 49],
  41896. 'yellow' => ['set' => 43, 'unset' => 49],
  41897. 'blue' => ['set' => 44, 'unset' => 49],
  41898. 'magenta' => ['set' => 45, 'unset' => 49],
  41899. 'cyan' => ['set' => 46, 'unset' => 49],
  41900. 'white' => ['set' => 47, 'unset' => 49],
  41901. 'default' => ['set' => 49, 'unset' => 49],
  41902. ];
  41903. private static $availableOptions = [
  41904. 'bold' => ['set' => 1, 'unset' => 22],
  41905. 'underscore' => ['set' => 4, 'unset' => 24],
  41906. 'blink' => ['set' => 5, 'unset' => 25],
  41907. 'reverse' => ['set' => 7, 'unset' => 27],
  41908. 'conceal' => ['set' => 8, 'unset' => 28],
  41909. ];
  41910. private $foreground;
  41911. private $background;
  41912. private $options = [];
  41913. public function __construct($foreground = null, $background = null, array $options = [])
  41914. {
  41915. if (null !== $foreground) {
  41916. $this->setForeground($foreground);
  41917. }
  41918. if (null !== $background) {
  41919. $this->setBackground($background);
  41920. }
  41921. if (\count($options)) {
  41922. $this->setOptions($options);
  41923. }
  41924. }
  41925. public function setForeground($color = null)
  41926. {
  41927. if (null === $color) {
  41928. $this->foreground = null;
  41929. return;
  41930. }
  41931. if (!isset(static::$availableForegroundColors[$color])) {
  41932. throw new InvalidArgumentException(sprintf('Invalid foreground color specified: "%s". Expected one of (%s).', $color, implode(', ', array_keys(static::$availableForegroundColors))));
  41933. }
  41934. $this->foreground = static::$availableForegroundColors[$color];
  41935. }
  41936. public function setBackground($color = null)
  41937. {
  41938. if (null === $color) {
  41939. $this->background = null;
  41940. return;
  41941. }
  41942. if (!isset(static::$availableBackgroundColors[$color])) {
  41943. throw new InvalidArgumentException(sprintf('Invalid background color specified: "%s". Expected one of (%s).', $color, implode(', ', array_keys(static::$availableBackgroundColors))));
  41944. }
  41945. $this->background = static::$availableBackgroundColors[$color];
  41946. }
  41947. public function setOption($option)
  41948. {
  41949. if (!isset(static::$availableOptions[$option])) {
  41950. throw new InvalidArgumentException(sprintf('Invalid option specified: "%s". Expected one of (%s).', $option, implode(', ', array_keys(static::$availableOptions))));
  41951. }
  41952. if (!\in_array(static::$availableOptions[$option], $this->options)) {
  41953. $this->options[] = static::$availableOptions[$option];
  41954. }
  41955. }
  41956. public function unsetOption($option)
  41957. {
  41958. if (!isset(static::$availableOptions[$option])) {
  41959. throw new InvalidArgumentException(sprintf('Invalid option specified: "%s". Expected one of (%s).', $option, implode(', ', array_keys(static::$availableOptions))));
  41960. }
  41961. $pos = array_search(static::$availableOptions[$option], $this->options);
  41962. if (false !== $pos) {
  41963. unset($this->options[$pos]);
  41964. }
  41965. }
  41966. public function setOptions(array $options)
  41967. {
  41968. $this->options = [];
  41969. foreach ($options as $option) {
  41970. $this->setOption($option);
  41971. }
  41972. }
  41973. public function apply($text)
  41974. {
  41975. $setCodes = [];
  41976. $unsetCodes = [];
  41977. if (null !== $this->foreground) {
  41978. $setCodes[] = $this->foreground['set'];
  41979. $unsetCodes[] = $this->foreground['unset'];
  41980. }
  41981. if (null !== $this->background) {
  41982. $setCodes[] = $this->background['set'];
  41983. $unsetCodes[] = $this->background['unset'];
  41984. }
  41985. if (\count($this->options)) {
  41986. foreach ($this->options as $option) {
  41987. $setCodes[] = $option['set'];
  41988. $unsetCodes[] = $option['unset'];
  41989. }
  41990. }
  41991. if (0 === \count($setCodes)) {
  41992. return $text;
  41993. }
  41994. return sprintf("\033[%sm%s\033[%sm", implode(';', $setCodes), $text, implode(';', $unsetCodes));
  41995. }
  41996. }
  41997. <?php
  41998. namespace Symfony\Component\Console\Formatter;
  41999. use Symfony\Component\Console\Exception\InvalidArgumentException;
  42000. class OutputFormatter implements OutputFormatterInterface
  42001. {
  42002. private $decorated;
  42003. private $styles = [];
  42004. private $styleStack;
  42005. public static function escape($text)
  42006. {
  42007. $text = preg_replace('/([^\\\\]?)</', '$1\\<', $text);
  42008. return self::escapeTrailingBackslash($text);
  42009. }
  42010. public static function escapeTrailingBackslash($text)
  42011. {
  42012. if ('\\' === substr($text, -1)) {
  42013. $len = \strlen($text);
  42014. $text = rtrim($text, '\\');
  42015. $text = str_replace("\0", '', $text);
  42016. $text .= str_repeat("\0", $len - \strlen($text));
  42017. }
  42018. return $text;
  42019. }
  42020. public function __construct($decorated = false, array $styles = [])
  42021. {
  42022. $this->decorated = (bool) $decorated;
  42023. $this->setStyle('error', new OutputFormatterStyle('white', 'red'));
  42024. $this->setStyle('info', new OutputFormatterStyle('green'));
  42025. $this->setStyle('comment', new OutputFormatterStyle('yellow'));
  42026. $this->setStyle('question', new OutputFormatterStyle('black', 'cyan'));
  42027. foreach ($styles as $name => $style) {
  42028. $this->setStyle($name, $style);
  42029. }
  42030. $this->styleStack = new OutputFormatterStyleStack();
  42031. }
  42032. public function setDecorated($decorated)
  42033. {
  42034. $this->decorated = (bool) $decorated;
  42035. }
  42036. public function isDecorated()
  42037. {
  42038. return $this->decorated;
  42039. }
  42040. public function setStyle($name, OutputFormatterStyleInterface $style)
  42041. {
  42042. $this->styles[strtolower($name)] = $style;
  42043. }
  42044. public function hasStyle($name)
  42045. {
  42046. return isset($this->styles[strtolower($name)]);
  42047. }
  42048. public function getStyle($name)
  42049. {
  42050. if (!$this->hasStyle($name)) {
  42051. throw new InvalidArgumentException(sprintf('Undefined style: "%s".', $name));
  42052. }
  42053. return $this->styles[strtolower($name)];
  42054. }
  42055. public function format($message)
  42056. {
  42057. $message = (string) $message;
  42058. $offset = 0;
  42059. $output = '';
  42060. $tagRegex = '[a-z][a-z0-9,_=;-]*+';
  42061. preg_match_all("#<(($tagRegex) | /($tagRegex)?)>#ix", $message, $matches, PREG_OFFSET_CAPTURE);
  42062. foreach ($matches[0] as $i => $match) {
  42063. $pos = $match[1];
  42064. $text = $match[0];
  42065. if (0 != $pos && '\\' == $message[$pos - 1]) {
  42066. continue;
  42067. }
  42068. $output .= $this->applyCurrentStyle(substr($message, $offset, $pos - $offset));
  42069. $offset = $pos + \strlen($text);
  42070. if ($open = '/' != $text[1]) {
  42071. $tag = $matches[1][$i][0];
  42072. } else {
  42073. $tag = isset($matches[3][$i][0]) ? $matches[3][$i][0] : '';
  42074. }
  42075. if (!$open && !$tag) {
  42076. $this->styleStack->pop();
  42077. } elseif (false === $style = $this->createStyleFromString($tag)) {
  42078. $output .= $this->applyCurrentStyle($text);
  42079. } elseif ($open) {
  42080. $this->styleStack->push($style);
  42081. } else {
  42082. $this->styleStack->pop($style);
  42083. }
  42084. }
  42085. $output .= $this->applyCurrentStyle(substr($message, $offset));
  42086. if (false !== strpos($output, "\0")) {
  42087. return strtr($output, ["\0" => '\\', '\\<' => '<']);
  42088. }
  42089. return str_replace('\\<', '<', $output);
  42090. }
  42091. public function getStyleStack()
  42092. {
  42093. return $this->styleStack;
  42094. }
  42095. private function createStyleFromString($string)
  42096. {
  42097. if (isset($this->styles[$string])) {
  42098. return $this->styles[$string];
  42099. }
  42100. if (!preg_match_all('/([^=]+)=([^;]+)(;|$)/', $string, $matches, PREG_SET_ORDER)) {
  42101. return false;
  42102. }
  42103. $style = new OutputFormatterStyle();
  42104. foreach ($matches as $match) {
  42105. array_shift($match);
  42106. $match[0] = strtolower($match[0]);
  42107. if ('fg' == $match[0]) {
  42108. $style->setForeground(strtolower($match[1]));
  42109. } elseif ('bg' == $match[0]) {
  42110. $style->setBackground(strtolower($match[1]));
  42111. } elseif ('options' === $match[0]) {
  42112. preg_match_all('([^,;]+)', strtolower($match[1]), $options);
  42113. $options = array_shift($options);
  42114. foreach ($options as $option) {
  42115. try {
  42116. $style->setOption($option);
  42117. } catch (\InvalidArgumentException $e) {
  42118. @trigger_error(sprintf('Unknown style options are deprecated since Symfony 3.2 and will be removed in 4.0. Exception "%s".', $e->getMessage()), E_USER_DEPRECATED);
  42119. return false;
  42120. }
  42121. }
  42122. } else {
  42123. return false;
  42124. }
  42125. }
  42126. return $style;
  42127. }
  42128. private function applyCurrentStyle($text)
  42129. {
  42130. return $this->isDecorated() && \strlen($text) > 0 ? $this->styleStack->getCurrent()->apply($text) : $text;
  42131. }
  42132. }
  42133. <?php
  42134. namespace Symfony\Component\Console\Formatter;
  42135. interface OutputFormatterInterface
  42136. {
  42137. public function setDecorated($decorated);
  42138. public function isDecorated();
  42139. public function setStyle($name, OutputFormatterStyleInterface $style);
  42140. public function hasStyle($name);
  42141. public function getStyle($name);
  42142. public function format($message);
  42143. }
  42144. <?php
  42145. namespace Symfony\Component\Console\Formatter;
  42146. interface OutputFormatterStyleInterface
  42147. {
  42148. public function setForeground($color = null);
  42149. public function setBackground($color = null);
  42150. public function setOption($option);
  42151. public function unsetOption($option);
  42152. public function setOptions(array $options);
  42153. public function apply($text);
  42154. }
  42155. <?php
  42156. namespace Symfony\Component\Console\Question;
  42157. class ConfirmationQuestion extends Question
  42158. {
  42159. private $trueAnswerRegex;
  42160. public function __construct($question, $default = true, $trueAnswerRegex = '/^y/i')
  42161. {
  42162. parent::__construct($question, (bool) $default);
  42163. $this->trueAnswerRegex = $trueAnswerRegex;
  42164. $this->setNormalizer($this->getDefaultNormalizer());
  42165. }
  42166. private function getDefaultNormalizer()
  42167. {
  42168. $default = $this->getDefault();
  42169. $regex = $this->trueAnswerRegex;
  42170. return function ($answer) use ($default, $regex) {
  42171. if (\is_bool($answer)) {
  42172. return $answer;
  42173. }
  42174. $answerIsTrue = (bool) preg_match($regex, $answer);
  42175. if (false === $default) {
  42176. return $answer && $answerIsTrue;
  42177. }
  42178. return '' === $answer || $answerIsTrue;
  42179. };
  42180. }
  42181. }
  42182. <?php
  42183. namespace Symfony\Component\Console\Question;
  42184. use Symfony\Component\Console\Exception\InvalidArgumentException;
  42185. use Symfony\Component\Console\Exception\LogicException;
  42186. class Question
  42187. {
  42188. private $question;
  42189. private $attempts;
  42190. private $hidden = false;
  42191. private $hiddenFallback = true;
  42192. private $autocompleterValues;
  42193. private $validator;
  42194. private $default;
  42195. private $normalizer;
  42196. public function __construct($question, $default = null)
  42197. {
  42198. $this->question = $question;
  42199. $this->default = $default;
  42200. }
  42201. public function getQuestion()
  42202. {
  42203. return $this->question;
  42204. }
  42205. public function getDefault()
  42206. {
  42207. return $this->default;
  42208. }
  42209. public function isHidden()
  42210. {
  42211. return $this->hidden;
  42212. }
  42213. public function setHidden($hidden)
  42214. {
  42215. if ($this->autocompleterValues) {
  42216. throw new LogicException('A hidden question cannot use the autocompleter.');
  42217. }
  42218. $this->hidden = (bool) $hidden;
  42219. return $this;
  42220. }
  42221. public function isHiddenFallback()
  42222. {
  42223. return $this->hiddenFallback;
  42224. }
  42225. public function setHiddenFallback($fallback)
  42226. {
  42227. $this->hiddenFallback = (bool) $fallback;
  42228. return $this;
  42229. }
  42230. public function getAutocompleterValues()
  42231. {
  42232. return $this->autocompleterValues;
  42233. }
  42234. public function setAutocompleterValues($values)
  42235. {
  42236. if (\is_array($values)) {
  42237. $values = $this->isAssoc($values) ? array_merge(array_keys($values), array_values($values)) : array_values($values);
  42238. }
  42239. if (null !== $values && !\is_array($values) && !$values instanceof \Traversable) {
  42240. throw new InvalidArgumentException('Autocompleter values can be either an array, `null` or a `Traversable` object.');
  42241. }
  42242. if ($this->hidden) {
  42243. throw new LogicException('A hidden question cannot use the autocompleter.');
  42244. }
  42245. $this->autocompleterValues = $values;
  42246. return $this;
  42247. }
  42248. public function setValidator(callable $validator = null)
  42249. {
  42250. $this->validator = $validator;
  42251. return $this;
  42252. }
  42253. public function getValidator()
  42254. {
  42255. return $this->validator;
  42256. }
  42257. public function setMaxAttempts($attempts)
  42258. {
  42259. if (null !== $attempts && $attempts < 1) {
  42260. throw new InvalidArgumentException('Maximum number of attempts must be a positive value.');
  42261. }
  42262. $this->attempts = $attempts;
  42263. return $this;
  42264. }
  42265. public function getMaxAttempts()
  42266. {
  42267. return $this->attempts;
  42268. }
  42269. public function setNormalizer(callable $normalizer)
  42270. {
  42271. $this->normalizer = $normalizer;
  42272. return $this;
  42273. }
  42274. public function getNormalizer()
  42275. {
  42276. return $this->normalizer;
  42277. }
  42278. protected function isAssoc($array)
  42279. {
  42280. return (bool) \count(array_filter(array_keys($array), 'is_string'));
  42281. }
  42282. }
  42283. <?php
  42284. namespace Symfony\Component\Console\Question;
  42285. use Symfony\Component\Console\Exception\InvalidArgumentException;
  42286. class ChoiceQuestion extends Question
  42287. {
  42288. private $choices;
  42289. private $multiselect = false;
  42290. private $prompt = ' > ';
  42291. private $errorMessage = 'Value "%s" is invalid';
  42292. public function __construct($question, array $choices, $default = null)
  42293. {
  42294. if (!$choices) {
  42295. throw new \LogicException('Choice question must have at least 1 choice available.');
  42296. }
  42297. parent::__construct($question, $default);
  42298. $this->choices = $choices;
  42299. $this->setValidator($this->getDefaultValidator());
  42300. $this->setAutocompleterValues($choices);
  42301. }
  42302. public function getChoices()
  42303. {
  42304. return $this->choices;
  42305. }
  42306. public function setMultiselect($multiselect)
  42307. {
  42308. $this->multiselect = $multiselect;
  42309. $this->setValidator($this->getDefaultValidator());
  42310. return $this;
  42311. }
  42312. public function isMultiselect()
  42313. {
  42314. return $this->multiselect;
  42315. }
  42316. public function getPrompt()
  42317. {
  42318. return $this->prompt;
  42319. }
  42320. public function setPrompt($prompt)
  42321. {
  42322. $this->prompt = $prompt;
  42323. return $this;
  42324. }
  42325. public function setErrorMessage($errorMessage)
  42326. {
  42327. $this->errorMessage = $errorMessage;
  42328. $this->setValidator($this->getDefaultValidator());
  42329. return $this;
  42330. }
  42331. private function getDefaultValidator()
  42332. {
  42333. $choices = $this->choices;
  42334. $errorMessage = $this->errorMessage;
  42335. $multiselect = $this->multiselect;
  42336. $isAssoc = $this->isAssoc($choices);
  42337. return function ($selected) use ($choices, $errorMessage, $multiselect, $isAssoc) {
  42338. if ($multiselect) {
  42339. if (!preg_match('/^[^,]+(?:,[^,]+)*$/', $selected, $matches)) {
  42340. throw new InvalidArgumentException(sprintf($errorMessage, $selected));
  42341. }
  42342. $selectedChoices = array_map('trim', explode(',', $selected));
  42343. } else {
  42344. $selectedChoices = [trim($selected)];
  42345. }
  42346. $multiselectChoices = [];
  42347. foreach ($selectedChoices as $value) {
  42348. $results = [];
  42349. foreach ($choices as $key => $choice) {
  42350. if ($choice === $value) {
  42351. $results[] = $key;
  42352. }
  42353. }
  42354. if (\count($results) > 1) {
  42355. throw new InvalidArgumentException(sprintf('The provided answer is ambiguous. Value should be one of "%s".', implode('" or "', $results)));
  42356. }
  42357. $result = array_search($value, $choices);
  42358. if (!$isAssoc) {
  42359. if (false !== $result) {
  42360. $result = $choices[$result];
  42361. } elseif (isset($choices[$value])) {
  42362. $result = $choices[$value];
  42363. }
  42364. } elseif (false === $result && isset($choices[$value])) {
  42365. $result = $value;
  42366. }
  42367. if (false === $result) {
  42368. throw new InvalidArgumentException(sprintf($errorMessage, $value));
  42369. }
  42370. $multiselectChoices[] = (string) $result;
  42371. }
  42372. if ($multiselect) {
  42373. return $multiselectChoices;
  42374. }
  42375. return current($multiselectChoices);
  42376. };
  42377. }
  42378. }
  42379. <?php
  42380. namespace Symfony\Component\Console\DependencyInjection;
  42381. use Symfony\Component\Console\Command\Command;
  42382. use Symfony\Component\Console\CommandLoader\ContainerCommandLoader;
  42383. use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
  42384. use Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass;
  42385. use Symfony\Component\DependencyInjection\ContainerBuilder;
  42386. use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
  42387. use Symfony\Component\DependencyInjection\TypedReference;
  42388. class AddConsoleCommandPass implements CompilerPassInterface
  42389. {
  42390. private $commandLoaderServiceId;
  42391. private $commandTag;
  42392. public function __construct($commandLoaderServiceId = 'console.command_loader', $commandTag = 'console.command')
  42393. {
  42394. $this->commandLoaderServiceId = $commandLoaderServiceId;
  42395. $this->commandTag = $commandTag;
  42396. }
  42397. public function process(ContainerBuilder $container)
  42398. {
  42399. $commandServices = $container->findTaggedServiceIds($this->commandTag, true);
  42400. $lazyCommandMap = [];
  42401. $lazyCommandRefs = [];
  42402. $serviceIds = [];
  42403. $lazyServiceIds = [];
  42404. foreach ($commandServices as $id => $tags) {
  42405. $definition = $container->getDefinition($id);
  42406. $class = $container->getParameterBag()->resolveValue($definition->getClass());
  42407. $commandId = 'console.command.'.strtolower(str_replace('\\', '_', $class));
  42408. if (isset($tags[0]['command'])) {
  42409. $commandName = $tags[0]['command'];
  42410. } else {
  42411. if (!$r = $container->getReflectionClass($class)) {
  42412. throw new InvalidArgumentException(sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id));
  42413. }
  42414. if (!$r->isSubclassOf(Command::class)) {
  42415. throw new InvalidArgumentException(sprintf('The service "%s" tagged "%s" must be a subclass of "%s".', $id, $this->commandTag, Command::class));
  42416. }
  42417. $commandName = $class::getDefaultName();
  42418. }
  42419. if (null === $commandName) {
  42420. if (isset($serviceIds[$commandId]) || $container->hasAlias($commandId)) {
  42421. $commandId = $commandId.'_'.$id;
  42422. }
  42423. if (!$definition->isPublic() || $definition->isPrivate()) {
  42424. $container->setAlias($commandId, $id)->setPublic(true);
  42425. $id = $commandId;
  42426. }
  42427. $serviceIds[$commandId] = $id;
  42428. continue;
  42429. }
  42430. $serviceIds[$commandId] = $id;
  42431. $lazyServiceIds[$id] = true;
  42432. unset($tags[0]);
  42433. $lazyCommandMap[$commandName] = $id;
  42434. $lazyCommandRefs[$id] = new TypedReference($id, $class);
  42435. $aliases = [];
  42436. foreach ($tags as $tag) {
  42437. if (isset($tag['command'])) {
  42438. $aliases[] = $tag['command'];
  42439. $lazyCommandMap[$tag['command']] = $id;
  42440. }
  42441. }
  42442. $definition->addMethodCall('setName', [$commandName]);
  42443. if ($aliases) {
  42444. $definition->addMethodCall('setAliases', [$aliases]);
  42445. }
  42446. }
  42447. $container
  42448. ->register($this->commandLoaderServiceId, ContainerCommandLoader::class)
  42449. ->setPublic(true)
  42450. ->setArguments([ServiceLocatorTagPass::register($container, $lazyCommandRefs), $lazyCommandMap]);
  42451. $container->setParameter('console.command.ids', $serviceIds);
  42452. $container->setParameter('console.lazy_command.ids', $lazyServiceIds);
  42453. }
  42454. }
  42455. <?php
  42456. namespace Symfony\Component\Console;
  42457. class Terminal
  42458. {
  42459. private static $width;
  42460. private static $height;
  42461. private static $stty;
  42462. public function getWidth()
  42463. {
  42464. $width = getenv('COLUMNS');
  42465. if (false !== $width) {
  42466. return (int) trim($width);
  42467. }
  42468. if (null === self::$width) {
  42469. self::initDimensions();
  42470. }
  42471. return self::$width ?: 80;
  42472. }
  42473. public function getHeight()
  42474. {
  42475. $height = getenv('LINES');
  42476. if (false !== $height) {
  42477. return (int) trim($height);
  42478. }
  42479. if (null === self::$height) {
  42480. self::initDimensions();
  42481. }
  42482. return self::$height ?: 50;
  42483. }
  42484. public static function hasSttyAvailable()
  42485. {
  42486. if (null !== self::$stty) {
  42487. return self::$stty;
  42488. }
  42489. exec('stty 2>&1', $output, $exitcode);
  42490. return self::$stty = 0 === $exitcode;
  42491. }
  42492. private static function initDimensions()
  42493. {
  42494. if ('\\' === \DIRECTORY_SEPARATOR) {
  42495. if (preg_match('/^(\d+)x(\d+)(?: \((\d+)x(\d+)\))?$/', trim(getenv('ANSICON')), $matches)) {
  42496. self::$width = (int) $matches[1];
  42497. self::$height = isset($matches[4]) ? (int) $matches[4] : (int) $matches[2];
  42498. } elseif (!self::hasVt100Support() && self::hasSttyAvailable()) {
  42499. self::initDimensionsUsingStty();
  42500. } elseif (null !== $dimensions = self::getConsoleMode()) {
  42501. self::$width = (int) $dimensions[0];
  42502. self::$height = (int) $dimensions[1];
  42503. }
  42504. } else {
  42505. self::initDimensionsUsingStty();
  42506. }
  42507. }
  42508. private static function hasVt100Support()
  42509. {
  42510. return \function_exists('sapi_windows_vt100_support') && sapi_windows_vt100_support(fopen('php://stdout', 'w'));
  42511. }
  42512. private static function initDimensionsUsingStty()
  42513. {
  42514. if ($sttyString = self::getSttyColumns()) {
  42515. if (preg_match('/rows.(\d+);.columns.(\d+);/i', $sttyString, $matches)) {
  42516. self::$width = (int) $matches[2];
  42517. self::$height = (int) $matches[1];
  42518. } elseif (preg_match('/;.(\d+).rows;.(\d+).columns/i', $sttyString, $matches)) {
  42519. self::$width = (int) $matches[2];
  42520. self::$height = (int) $matches[1];
  42521. }
  42522. }
  42523. }
  42524. private static function getConsoleMode()
  42525. {
  42526. $info = self::readFromProcess('mode CON');
  42527. if (null === $info || !preg_match('/--------+\r?\n.+?(\d+)\r?\n.+?(\d+)\r?\n/', $info, $matches)) {
  42528. return null;
  42529. }
  42530. return [(int) $matches[2], (int) $matches[1]];
  42531. }
  42532. private static function getSttyColumns()
  42533. {
  42534. return self::readFromProcess('stty -a | grep columns');
  42535. }
  42536. private static function readFromProcess($command)
  42537. {
  42538. if (!\function_exists('proc_open')) {
  42539. return null;
  42540. }
  42541. $descriptorspec = [
  42542. 1 => ['pipe', 'w'],
  42543. 2 => ['pipe', 'w'],
  42544. ];
  42545. $process = proc_open($command, $descriptorspec, $pipes, null, null, ['suppress_errors' => true]);
  42546. if (!\is_resource($process)) {
  42547. return null;
  42548. }
  42549. $info = stream_get_contents($pipes[1]);
  42550. fclose($pipes[1]);
  42551. fclose($pipes[2]);
  42552. proc_close($process);
  42553. return $info;
  42554. }
  42555. }
  42556. <?php
  42557. namespace Symfony\Component\Console\Output;
  42558. class BufferedOutput extends Output
  42559. {
  42560. private $buffer = '';
  42561. public function fetch()
  42562. {
  42563. $content = $this->buffer;
  42564. $this->buffer = '';
  42565. return $content;
  42566. }
  42567. protected function doWrite($message, $newline)
  42568. {
  42569. $this->buffer .= $message;
  42570. if ($newline) {
  42571. $this->buffer .= PHP_EOL;
  42572. }
  42573. }
  42574. }
  42575. <?php
  42576. namespace Symfony\Component\Console\Output;
  42577. use Symfony\Component\Console\Formatter\OutputFormatter;
  42578. use Symfony\Component\Console\Formatter\OutputFormatterInterface;
  42579. abstract class Output implements OutputInterface
  42580. {
  42581. private $verbosity;
  42582. private $formatter;
  42583. public function __construct($verbosity = self::VERBOSITY_NORMAL, $decorated = false, OutputFormatterInterface $formatter = null)
  42584. {
  42585. $this->verbosity = null === $verbosity ? self::VERBOSITY_NORMAL : $verbosity;
  42586. $this->formatter = $formatter ?: new OutputFormatter();
  42587. $this->formatter->setDecorated($decorated);
  42588. }
  42589. public function setFormatter(OutputFormatterInterface $formatter)
  42590. {
  42591. $this->formatter = $formatter;
  42592. }
  42593. public function getFormatter()
  42594. {
  42595. return $this->formatter;
  42596. }
  42597. public function setDecorated($decorated)
  42598. {
  42599. $this->formatter->setDecorated($decorated);
  42600. }
  42601. public function isDecorated()
  42602. {
  42603. return $this->formatter->isDecorated();
  42604. }
  42605. public function setVerbosity($level)
  42606. {
  42607. $this->verbosity = (int) $level;
  42608. }
  42609. public function getVerbosity()
  42610. {
  42611. return $this->verbosity;
  42612. }
  42613. public function isQuiet()
  42614. {
  42615. return self::VERBOSITY_QUIET === $this->verbosity;
  42616. }
  42617. public function isVerbose()
  42618. {
  42619. return self::VERBOSITY_VERBOSE <= $this->verbosity;
  42620. }
  42621. public function isVeryVerbose()
  42622. {
  42623. return self::VERBOSITY_VERY_VERBOSE <= $this->verbosity;
  42624. }
  42625. public function isDebug()
  42626. {
  42627. return self::VERBOSITY_DEBUG <= $this->verbosity;
  42628. }
  42629. public function writeln($messages, $options = self::OUTPUT_NORMAL)
  42630. {
  42631. $this->write($messages, true, $options);
  42632. }
  42633. public function write($messages, $newline = false, $options = self::OUTPUT_NORMAL)
  42634. {
  42635. $messages = (array) $messages;
  42636. $types = self::OUTPUT_NORMAL | self::OUTPUT_RAW | self::OUTPUT_PLAIN;
  42637. $type = $types & $options ?: self::OUTPUT_NORMAL;
  42638. $verbosities = self::VERBOSITY_QUIET | self::VERBOSITY_NORMAL | self::VERBOSITY_VERBOSE | self::VERBOSITY_VERY_VERBOSE | self::VERBOSITY_DEBUG;
  42639. $verbosity = $verbosities & $options ?: self::VERBOSITY_NORMAL;
  42640. if ($verbosity > $this->getVerbosity()) {
  42641. return;
  42642. }
  42643. foreach ($messages as $message) {
  42644. switch ($type) {
  42645. case OutputInterface::OUTPUT_NORMAL:
  42646. $message = $this->formatter->format($message);
  42647. break;
  42648. case OutputInterface::OUTPUT_RAW:
  42649. break;
  42650. case OutputInterface::OUTPUT_PLAIN:
  42651. $message = strip_tags($this->formatter->format($message));
  42652. break;
  42653. }
  42654. $this->doWrite($message, $newline);
  42655. }
  42656. }
  42657. abstract protected function doWrite($message, $newline);
  42658. }
  42659. <?php
  42660. namespace Symfony\Component\Console\Output;
  42661. use Symfony\Component\Console\Formatter\OutputFormatterInterface;
  42662. class ConsoleOutput extends StreamOutput implements ConsoleOutputInterface
  42663. {
  42664. private $stderr;
  42665. public function __construct($verbosity = self::VERBOSITY_NORMAL, $decorated = null, OutputFormatterInterface $formatter = null)
  42666. {
  42667. parent::__construct($this->openOutputStream(), $verbosity, $decorated, $formatter);
  42668. $actualDecorated = $this->isDecorated();
  42669. $this->stderr = new StreamOutput($this->openErrorStream(), $verbosity, $decorated, $this->getFormatter());
  42670. if (null === $decorated) {
  42671. $this->setDecorated($actualDecorated && $this->stderr->isDecorated());
  42672. }
  42673. }
  42674. public function setDecorated($decorated)
  42675. {
  42676. parent::setDecorated($decorated);
  42677. $this->stderr->setDecorated($decorated);
  42678. }
  42679. public function setFormatter(OutputFormatterInterface $formatter)
  42680. {
  42681. parent::setFormatter($formatter);
  42682. $this->stderr->setFormatter($formatter);
  42683. }
  42684. public function setVerbosity($level)
  42685. {
  42686. parent::setVerbosity($level);
  42687. $this->stderr->setVerbosity($level);
  42688. }
  42689. public function getErrorOutput()
  42690. {
  42691. return $this->stderr;
  42692. }
  42693. public function setErrorOutput(OutputInterface $error)
  42694. {
  42695. $this->stderr = $error;
  42696. }
  42697. protected function hasStdoutSupport()
  42698. {
  42699. return false === $this->isRunningOS400();
  42700. }
  42701. protected function hasStderrSupport()
  42702. {
  42703. return false === $this->isRunningOS400();
  42704. }
  42705. private function isRunningOS400()
  42706. {
  42707. $checks = [
  42708. \function_exists('php_uname') ? php_uname('s') : '',
  42709. getenv('OSTYPE'),
  42710. PHP_OS,
  42711. ];
  42712. return false !== stripos(implode(';', $checks), 'OS400');
  42713. }
  42714. private function openOutputStream()
  42715. {
  42716. if (!$this->hasStdoutSupport()) {
  42717. return fopen('php://output', 'w');
  42718. }
  42719. return @fopen('php://stdout', 'w') ?: fopen('php://output', 'w');
  42720. }
  42721. private function openErrorStream()
  42722. {
  42723. return fopen($this->hasStderrSupport() ? 'php://stderr' : 'php://output', 'w');
  42724. }
  42725. }
  42726. <?php
  42727. namespace Symfony\Component\Console\Output;
  42728. interface ConsoleOutputInterface extends OutputInterface
  42729. {
  42730. public function getErrorOutput();
  42731. public function setErrorOutput(OutputInterface $error);
  42732. }
  42733. <?php
  42734. namespace Symfony\Component\Console\Output;
  42735. use Symfony\Component\Console\Exception\InvalidArgumentException;
  42736. use Symfony\Component\Console\Formatter\OutputFormatterInterface;
  42737. class StreamOutput extends Output
  42738. {
  42739. private $stream;
  42740. public function __construct($stream, $verbosity = self::VERBOSITY_NORMAL, $decorated = null, OutputFormatterInterface $formatter = null)
  42741. {
  42742. if (!\is_resource($stream) || 'stream' !== get_resource_type($stream)) {
  42743. throw new InvalidArgumentException('The StreamOutput class needs a stream as its first argument.');
  42744. }
  42745. $this->stream = $stream;
  42746. if (null === $decorated) {
  42747. $decorated = $this->hasColorSupport();
  42748. }
  42749. parent::__construct($verbosity, $decorated, $formatter);
  42750. }
  42751. public function getStream()
  42752. {
  42753. return $this->stream;
  42754. }
  42755. protected function doWrite($message, $newline)
  42756. {
  42757. if ($newline) {
  42758. $message .= PHP_EOL;
  42759. }
  42760. @fwrite($this->stream, $message);
  42761. fflush($this->stream);
  42762. }
  42763. protected function hasColorSupport()
  42764. {
  42765. if ('Hyper' === getenv('TERM_PROGRAM')) {
  42766. return true;
  42767. }
  42768. if (\DIRECTORY_SEPARATOR === '\\') {
  42769. return (\function_exists('sapi_windows_vt100_support')
  42770. && @sapi_windows_vt100_support($this->stream))
  42771. || false !== getenv('ANSICON')
  42772. || 'ON' === getenv('ConEmuANSI')
  42773. || 'xterm' === getenv('TERM');
  42774. }
  42775. if (\function_exists('stream_isatty')) {
  42776. return @stream_isatty($this->stream);
  42777. }
  42778. if (\function_exists('posix_isatty')) {
  42779. return @posix_isatty($this->stream);
  42780. }
  42781. $stat = @fstat($this->stream);
  42782. return $stat ? 0020000 === ($stat['mode'] & 0170000) : false;
  42783. }
  42784. }
  42785. <?php
  42786. namespace Symfony\Component\Console\Output;
  42787. use Symfony\Component\Console\Formatter\OutputFormatterInterface;
  42788. interface OutputInterface
  42789. {
  42790. const VERBOSITY_QUIET = 16;
  42791. const VERBOSITY_NORMAL = 32;
  42792. const VERBOSITY_VERBOSE = 64;
  42793. const VERBOSITY_VERY_VERBOSE = 128;
  42794. const VERBOSITY_DEBUG = 256;
  42795. const OUTPUT_NORMAL = 1;
  42796. const OUTPUT_RAW = 2;
  42797. const OUTPUT_PLAIN = 4;
  42798. public function write($messages, $newline = false, $options = 0);
  42799. public function writeln($messages, $options = 0);
  42800. public function setVerbosity($level);
  42801. public function getVerbosity();
  42802. public function isQuiet();
  42803. public function isVerbose();
  42804. public function isVeryVerbose();
  42805. public function isDebug();
  42806. public function setDecorated($decorated);
  42807. public function isDecorated();
  42808. public function setFormatter(OutputFormatterInterface $formatter);
  42809. public function getFormatter();
  42810. }
  42811. <?php
  42812. namespace Symfony\Component\Console\Output;
  42813. use Symfony\Component\Console\Formatter\OutputFormatter;
  42814. use Symfony\Component\Console\Formatter\OutputFormatterInterface;
  42815. class NullOutput implements OutputInterface
  42816. {
  42817. public function setFormatter(OutputFormatterInterface $formatter)
  42818. {
  42819. }
  42820. public function getFormatter()
  42821. {
  42822. return new OutputFormatter();
  42823. }
  42824. public function setDecorated($decorated)
  42825. {
  42826. }
  42827. public function isDecorated()
  42828. {
  42829. return false;
  42830. }
  42831. public function setVerbosity($level)
  42832. {
  42833. }
  42834. public function getVerbosity()
  42835. {
  42836. return self::VERBOSITY_QUIET;
  42837. }
  42838. public function isQuiet()
  42839. {
  42840. return true;
  42841. }
  42842. public function isVerbose()
  42843. {
  42844. return false;
  42845. }
  42846. public function isVeryVerbose()
  42847. {
  42848. return false;
  42849. }
  42850. public function isDebug()
  42851. {
  42852. return false;
  42853. }
  42854. public function writeln($messages, $options = self::OUTPUT_NORMAL)
  42855. {
  42856. }
  42857. public function write($messages, $newline = false, $options = self::OUTPUT_NORMAL)
  42858. {
  42859. }
  42860. }
  42861. <?php
  42862. namespace Symfony\Component\Console\Event;
  42863. @trigger_error(sprintf('The "%s" class is deprecated since Symfony 3.3 and will be removed in 4.0. Use the ConsoleErrorEvent instead.', ConsoleExceptionEvent::class), E_USER_DEPRECATED);
  42864. use Symfony\Component\Console\Command\Command;
  42865. use Symfony\Component\Console\Input\InputInterface;
  42866. use Symfony\Component\Console\Output\OutputInterface;
  42867. class ConsoleExceptionEvent extends ConsoleEvent
  42868. {
  42869. private $exception;
  42870. private $exitCode;
  42871. public function __construct(Command $command, InputInterface $input, OutputInterface $output, \Exception $exception, $exitCode)
  42872. {
  42873. parent::__construct($command, $input, $output);
  42874. $this->setException($exception);
  42875. $this->exitCode = (int) $exitCode;
  42876. }
  42877. public function getException()
  42878. {
  42879. return $this->exception;
  42880. }
  42881. public function setException(\Exception $exception)
  42882. {
  42883. $this->exception = $exception;
  42884. }
  42885. public function getExitCode()
  42886. {
  42887. return $this->exitCode;
  42888. }
  42889. }
  42890. <?php
  42891. namespace Symfony\Component\Console\Event;
  42892. class ConsoleCommandEvent extends ConsoleEvent
  42893. {
  42894. const RETURN_CODE_DISABLED = 113;
  42895. private $commandShouldRun = true;
  42896. public function disableCommand()
  42897. {
  42898. return $this->commandShouldRun = false;
  42899. }
  42900. public function enableCommand()
  42901. {
  42902. return $this->commandShouldRun = true;
  42903. }
  42904. public function commandShouldRun()
  42905. {
  42906. return $this->commandShouldRun;
  42907. }
  42908. }
  42909. <?php
  42910. namespace Symfony\Component\Console\Event;
  42911. use Symfony\Component\Console\Command\Command;
  42912. use Symfony\Component\Console\Input\InputInterface;
  42913. use Symfony\Component\Console\Output\OutputInterface;
  42914. class ConsoleTerminateEvent extends ConsoleEvent
  42915. {
  42916. private $exitCode;
  42917. public function __construct(Command $command, InputInterface $input, OutputInterface $output, $exitCode)
  42918. {
  42919. parent::__construct($command, $input, $output);
  42920. $this->setExitCode($exitCode);
  42921. }
  42922. public function setExitCode($exitCode)
  42923. {
  42924. $this->exitCode = (int) $exitCode;
  42925. }
  42926. public function getExitCode()
  42927. {
  42928. return $this->exitCode;
  42929. }
  42930. }
  42931. <?php
  42932. namespace Symfony\Component\Console\Event;
  42933. use Symfony\Component\Console\Command\Command;
  42934. use Symfony\Component\Console\Input\InputInterface;
  42935. use Symfony\Component\Console\Output\OutputInterface;
  42936. use Symfony\Component\EventDispatcher\Event;
  42937. class ConsoleEvent extends Event
  42938. {
  42939. protected $command;
  42940. private $input;
  42941. private $output;
  42942. public function __construct(Command $command = null, InputInterface $input, OutputInterface $output)
  42943. {
  42944. $this->command = $command;
  42945. $this->input = $input;
  42946. $this->output = $output;
  42947. }
  42948. public function getCommand()
  42949. {
  42950. return $this->command;
  42951. }
  42952. public function getInput()
  42953. {
  42954. return $this->input;
  42955. }
  42956. public function getOutput()
  42957. {
  42958. return $this->output;
  42959. }
  42960. }
  42961. <?php
  42962. namespace Symfony\Component\Console\Event;
  42963. use Symfony\Component\Console\Command\Command;
  42964. use Symfony\Component\Console\Exception\InvalidArgumentException;
  42965. use Symfony\Component\Console\Input\InputInterface;
  42966. use Symfony\Component\Console\Output\OutputInterface;
  42967. final class ConsoleErrorEvent extends ConsoleEvent
  42968. {
  42969. private $error;
  42970. private $exitCode;
  42971. public function __construct(InputInterface $input, OutputInterface $output, $error, Command $command = null)
  42972. {
  42973. parent::__construct($command, $input, $output);
  42974. $this->setError($error);
  42975. }
  42976. public function getError()
  42977. {
  42978. return $this->error;
  42979. }
  42980. public function setError($error)
  42981. {
  42982. if (!$error instanceof \Throwable && !$error instanceof \Exception) {
  42983. throw new InvalidArgumentException(sprintf('The error passed to ConsoleErrorEvent must be an instance of \Throwable or \Exception, "%s" was passed instead.', \is_object($error) ? \get_class($error) : \gettype($error)));
  42984. }
  42985. $this->error = $error;
  42986. }
  42987. public function setExitCode($exitCode)
  42988. {
  42989. $this->exitCode = (int) $exitCode;
  42990. $r = new \ReflectionProperty($this->error, 'code');
  42991. $r->setAccessible(true);
  42992. $r->setValue($this->error, $this->exitCode);
  42993. }
  42994. public function getExitCode()
  42995. {
  42996. return null !== $this->exitCode ? $this->exitCode : (\is_int($this->error->getCode()) && 0 !== $this->error->getCode() ? $this->error->getCode() : 1);
  42997. }
  42998. }
  42999. <?php
  43000. namespace Symfony\Component\Console\Input;
  43001. use Symfony\Component\Console\Exception\InvalidArgumentException;
  43002. use Symfony\Component\Console\Exception\LogicException;
  43003. class InputArgument
  43004. {
  43005. const REQUIRED = 1;
  43006. const OPTIONAL = 2;
  43007. const IS_ARRAY = 4;
  43008. private $name;
  43009. private $mode;
  43010. private $default;
  43011. private $description;
  43012. public function __construct($name, $mode = null, $description = '', $default = null)
  43013. {
  43014. if (null === $mode) {
  43015. $mode = self::OPTIONAL;
  43016. } elseif (!\is_int($mode) || $mode > 7 || $mode < 1) {
  43017. throw new InvalidArgumentException(sprintf('Argument mode "%s" is not valid.', $mode));
  43018. }
  43019. $this->name = $name;
  43020. $this->mode = $mode;
  43021. $this->description = $description;
  43022. $this->setDefault($default);
  43023. }
  43024. public function getName()
  43025. {
  43026. return $this->name;
  43027. }
  43028. public function isRequired()
  43029. {
  43030. return self::REQUIRED === (self::REQUIRED & $this->mode);
  43031. }
  43032. public function isArray()
  43033. {
  43034. return self::IS_ARRAY === (self::IS_ARRAY & $this->mode);
  43035. }
  43036. public function setDefault($default = null)
  43037. {
  43038. if (self::REQUIRED === $this->mode && null !== $default) {
  43039. throw new LogicException('Cannot set a default value except for InputArgument::OPTIONAL mode.');
  43040. }
  43041. if ($this->isArray()) {
  43042. if (null === $default) {
  43043. $default = [];
  43044. } elseif (!\is_array($default)) {
  43045. throw new LogicException('A default value for an array argument must be an array.');
  43046. }
  43047. }
  43048. $this->default = $default;
  43049. }
  43050. public function getDefault()
  43051. {
  43052. return $this->default;
  43053. }
  43054. public function getDescription()
  43055. {
  43056. return $this->description;
  43057. }
  43058. }
  43059. <?php
  43060. namespace Symfony\Component\Console\Input;
  43061. use Symfony\Component\Console\Exception\InvalidArgumentException;
  43062. use Symfony\Component\Console\Exception\LogicException;
  43063. class InputDefinition
  43064. {
  43065. private $arguments;
  43066. private $requiredCount;
  43067. private $hasAnArrayArgument = false;
  43068. private $hasOptional;
  43069. private $options;
  43070. private $shortcuts;
  43071. public function __construct(array $definition = [])
  43072. {
  43073. $this->setDefinition($definition);
  43074. }
  43075. public function setDefinition(array $definition)
  43076. {
  43077. $arguments = [];
  43078. $options = [];
  43079. foreach ($definition as $item) {
  43080. if ($item instanceof InputOption) {
  43081. $options[] = $item;
  43082. } else {
  43083. $arguments[] = $item;
  43084. }
  43085. }
  43086. $this->setArguments($arguments);
  43087. $this->setOptions($options);
  43088. }
  43089. public function setArguments($arguments = [])
  43090. {
  43091. $this->arguments = [];
  43092. $this->requiredCount = 0;
  43093. $this->hasOptional = false;
  43094. $this->hasAnArrayArgument = false;
  43095. $this->addArguments($arguments);
  43096. }
  43097. public function addArguments($arguments = [])
  43098. {
  43099. if (null !== $arguments) {
  43100. foreach ($arguments as $argument) {
  43101. $this->addArgument($argument);
  43102. }
  43103. }
  43104. }
  43105. public function addArgument(InputArgument $argument)
  43106. {
  43107. if (isset($this->arguments[$argument->getName()])) {
  43108. throw new LogicException(sprintf('An argument with name "%s" already exists.', $argument->getName()));
  43109. }
  43110. if ($this->hasAnArrayArgument) {
  43111. throw new LogicException('Cannot add an argument after an array argument.');
  43112. }
  43113. if ($argument->isRequired() && $this->hasOptional) {
  43114. throw new LogicException('Cannot add a required argument after an optional one.');
  43115. }
  43116. if ($argument->isArray()) {
  43117. $this->hasAnArrayArgument = true;
  43118. }
  43119. if ($argument->isRequired()) {
  43120. ++$this->requiredCount;
  43121. } else {
  43122. $this->hasOptional = true;
  43123. }
  43124. $this->arguments[$argument->getName()] = $argument;
  43125. }
  43126. public function getArgument($name)
  43127. {
  43128. if (!$this->hasArgument($name)) {
  43129. throw new InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name));
  43130. }
  43131. $arguments = \is_int($name) ? array_values($this->arguments) : $this->arguments;
  43132. return $arguments[$name];
  43133. }
  43134. public function hasArgument($name)
  43135. {
  43136. $arguments = \is_int($name) ? array_values($this->arguments) : $this->arguments;
  43137. return isset($arguments[$name]);
  43138. }
  43139. public function getArguments()
  43140. {
  43141. return $this->arguments;
  43142. }
  43143. public function getArgumentCount()
  43144. {
  43145. return $this->hasAnArrayArgument ? PHP_INT_MAX : \count($this->arguments);
  43146. }
  43147. public function getArgumentRequiredCount()
  43148. {
  43149. return $this->requiredCount;
  43150. }
  43151. public function getArgumentDefaults()
  43152. {
  43153. $values = [];
  43154. foreach ($this->arguments as $argument) {
  43155. $values[$argument->getName()] = $argument->getDefault();
  43156. }
  43157. return $values;
  43158. }
  43159. public function setOptions($options = [])
  43160. {
  43161. $this->options = [];
  43162. $this->shortcuts = [];
  43163. $this->addOptions($options);
  43164. }
  43165. public function addOptions($options = [])
  43166. {
  43167. foreach ($options as $option) {
  43168. $this->addOption($option);
  43169. }
  43170. }
  43171. public function addOption(InputOption $option)
  43172. {
  43173. if (isset($this->options[$option->getName()]) && !$option->equals($this->options[$option->getName()])) {
  43174. throw new LogicException(sprintf('An option named "%s" already exists.', $option->getName()));
  43175. }
  43176. if ($option->getShortcut()) {
  43177. foreach (explode('|', $option->getShortcut()) as $shortcut) {
  43178. if (isset($this->shortcuts[$shortcut]) && !$option->equals($this->options[$this->shortcuts[$shortcut]])) {
  43179. throw new LogicException(sprintf('An option with shortcut "%s" already exists.', $shortcut));
  43180. }
  43181. }
  43182. }
  43183. $this->options[$option->getName()] = $option;
  43184. if ($option->getShortcut()) {
  43185. foreach (explode('|', $option->getShortcut()) as $shortcut) {
  43186. $this->shortcuts[$shortcut] = $option->getName();
  43187. }
  43188. }
  43189. }
  43190. public function getOption($name)
  43191. {
  43192. if (!$this->hasOption($name)) {
  43193. throw new InvalidArgumentException(sprintf('The "--%s" option does not exist.', $name));
  43194. }
  43195. return $this->options[$name];
  43196. }
  43197. public function hasOption($name)
  43198. {
  43199. return isset($this->options[$name]);
  43200. }
  43201. public function getOptions()
  43202. {
  43203. return $this->options;
  43204. }
  43205. public function hasShortcut($name)
  43206. {
  43207. return isset($this->shortcuts[$name]);
  43208. }
  43209. public function getOptionForShortcut($shortcut)
  43210. {
  43211. return $this->getOption($this->shortcutToName($shortcut));
  43212. }
  43213. public function getOptionDefaults()
  43214. {
  43215. $values = [];
  43216. foreach ($this->options as $option) {
  43217. $values[$option->getName()] = $option->getDefault();
  43218. }
  43219. return $values;
  43220. }
  43221. public function shortcutToName($shortcut)
  43222. {
  43223. if (!isset($this->shortcuts[$shortcut])) {
  43224. throw new InvalidArgumentException(sprintf('The "-%s" option does not exist.', $shortcut));
  43225. }
  43226. return $this->shortcuts[$shortcut];
  43227. }
  43228. public function getSynopsis($short = false)
  43229. {
  43230. $elements = [];
  43231. if ($short && $this->getOptions()) {
  43232. $elements[] = '[options]';
  43233. } elseif (!$short) {
  43234. foreach ($this->getOptions() as $option) {
  43235. $value = '';
  43236. if ($option->acceptValue()) {
  43237. $value = sprintf(
  43238. ' %s%s%s',
  43239. $option->isValueOptional() ? '[' : '',
  43240. strtoupper($option->getName()),
  43241. $option->isValueOptional() ? ']' : ''
  43242. );
  43243. }
  43244. $shortcut = $option->getShortcut() ? sprintf('-%s|', $option->getShortcut()) : '';
  43245. $elements[] = sprintf('[%s--%s%s]', $shortcut, $option->getName(), $value);
  43246. }
  43247. }
  43248. if (\count($elements) && $this->getArguments()) {
  43249. $elements[] = '[--]';
  43250. }
  43251. foreach ($this->getArguments() as $argument) {
  43252. $element = '<'.$argument->getName().'>';
  43253. if (!$argument->isRequired()) {
  43254. $element = '['.$element.']';
  43255. } elseif ($argument->isArray()) {
  43256. $element .= ' ('.$element.')';
  43257. }
  43258. if ($argument->isArray()) {
  43259. $element .= '...';
  43260. }
  43261. $elements[] = $element;
  43262. }
  43263. return implode(' ', $elements);
  43264. }
  43265. }
  43266. <?php
  43267. namespace Symfony\Component\Console\Input;
  43268. use Symfony\Component\Console\Exception\InvalidArgumentException;
  43269. use Symfony\Component\Console\Exception\RuntimeException;
  43270. abstract class Input implements InputInterface, StreamableInputInterface
  43271. {
  43272. protected $definition;
  43273. protected $stream;
  43274. protected $options = [];
  43275. protected $arguments = [];
  43276. protected $interactive = true;
  43277. public function __construct(InputDefinition $definition = null)
  43278. {
  43279. if (null === $definition) {
  43280. $this->definition = new InputDefinition();
  43281. } else {
  43282. $this->bind($definition);
  43283. $this->validate();
  43284. }
  43285. }
  43286. public function bind(InputDefinition $definition)
  43287. {
  43288. $this->arguments = [];
  43289. $this->options = [];
  43290. $this->definition = $definition;
  43291. $this->parse();
  43292. }
  43293. abstract protected function parse();
  43294. public function validate()
  43295. {
  43296. $definition = $this->definition;
  43297. $givenArguments = $this->arguments;
  43298. $missingArguments = array_filter(array_keys($definition->getArguments()), function ($argument) use ($definition, $givenArguments) {
  43299. return !\array_key_exists($argument, $givenArguments) && $definition->getArgument($argument)->isRequired();
  43300. });
  43301. if (\count($missingArguments) > 0) {
  43302. throw new RuntimeException(sprintf('Not enough arguments (missing: "%s").', implode(', ', $missingArguments)));
  43303. }
  43304. }
  43305. public function isInteractive()
  43306. {
  43307. return $this->interactive;
  43308. }
  43309. public function setInteractive($interactive)
  43310. {
  43311. $this->interactive = (bool) $interactive;
  43312. }
  43313. public function getArguments()
  43314. {
  43315. return array_merge($this->definition->getArgumentDefaults(), $this->arguments);
  43316. }
  43317. public function getArgument($name)
  43318. {
  43319. if (!$this->definition->hasArgument($name)) {
  43320. throw new InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name));
  43321. }
  43322. return isset($this->arguments[$name]) ? $this->arguments[$name] : $this->definition->getArgument($name)->getDefault();
  43323. }
  43324. public function setArgument($name, $value)
  43325. {
  43326. if (!$this->definition->hasArgument($name)) {
  43327. throw new InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name));
  43328. }
  43329. $this->arguments[$name] = $value;
  43330. }
  43331. public function hasArgument($name)
  43332. {
  43333. return $this->definition->hasArgument($name);
  43334. }
  43335. public function getOptions()
  43336. {
  43337. return array_merge($this->definition->getOptionDefaults(), $this->options);
  43338. }
  43339. public function getOption($name)
  43340. {
  43341. if (!$this->definition->hasOption($name)) {
  43342. throw new InvalidArgumentException(sprintf('The "%s" option does not exist.', $name));
  43343. }
  43344. return \array_key_exists($name, $this->options) ? $this->options[$name] : $this->definition->getOption($name)->getDefault();
  43345. }
  43346. public function setOption($name, $value)
  43347. {
  43348. if (!$this->definition->hasOption($name)) {
  43349. throw new InvalidArgumentException(sprintf('The "%s" option does not exist.', $name));
  43350. }
  43351. $this->options[$name] = $value;
  43352. }
  43353. public function hasOption($name)
  43354. {
  43355. return $this->definition->hasOption($name);
  43356. }
  43357. public function escapeToken($token)
  43358. {
  43359. return preg_match('{^[\w-]+$}', $token) ? $token : escapeshellarg($token);
  43360. }
  43361. public function setStream($stream)
  43362. {
  43363. $this->stream = $stream;
  43364. }
  43365. public function getStream()
  43366. {
  43367. return $this->stream;
  43368. }
  43369. }
  43370. <?php
  43371. namespace Symfony\Component\Console\Input;
  43372. use Symfony\Component\Console\Exception\InvalidArgumentException;
  43373. class StringInput extends ArgvInput
  43374. {
  43375. const REGEX_STRING = '([^\s]+?)(?:\s|(?<!\\\\)"|(?<!\\\\)\'|$)';
  43376. const REGEX_QUOTED_STRING = '(?:"([^"\\\\]*(?:\\\\.[^"\\\\]*)*)"|\'([^\'\\\\]*(?:\\\\.[^\'\\\\]*)*)\')';
  43377. public function __construct($input)
  43378. {
  43379. parent::__construct([]);
  43380. $this->setTokens($this->tokenize($input));
  43381. }
  43382. private function tokenize($input)
  43383. {
  43384. $tokens = [];
  43385. $length = \strlen($input);
  43386. $cursor = 0;
  43387. while ($cursor < $length) {
  43388. if (preg_match('/\s+/A', $input, $match, null, $cursor)) {
  43389. } elseif (preg_match('/([^="\'\s]+?)(=?)('.self::REGEX_QUOTED_STRING.'+)/A', $input, $match, null, $cursor)) {
  43390. $tokens[] = $match[1].$match[2].stripcslashes(str_replace(['"\'', '\'"', '\'\'', '""'], '', substr($match[3], 1, \strlen($match[3]) - 2)));
  43391. } elseif (preg_match('/'.self::REGEX_QUOTED_STRING.'/A', $input, $match, null, $cursor)) {
  43392. $tokens[] = stripcslashes(substr($match[0], 1, \strlen($match[0]) - 2));
  43393. } elseif (preg_match('/'.self::REGEX_STRING.'/A', $input, $match, null, $cursor)) {
  43394. $tokens[] = stripcslashes($match[1]);
  43395. } else {
  43396. throw new InvalidArgumentException(sprintf('Unable to parse input near "... %s ...".', substr($input, $cursor, 10)));
  43397. }
  43398. $cursor += \strlen($match[0]);
  43399. }
  43400. return $tokens;
  43401. }
  43402. }
  43403. <?php
  43404. namespace Symfony\Component\Console\Input;
  43405. use Symfony\Component\Console\Exception\RuntimeException;
  43406. class ArgvInput extends Input
  43407. {
  43408. private $tokens;
  43409. private $parsed;
  43410. public function __construct(array $argv = null, InputDefinition $definition = null)
  43411. {
  43412. if (null === $argv) {
  43413. $argv = $_SERVER['argv'];
  43414. }
  43415. array_shift($argv);
  43416. $this->tokens = $argv;
  43417. parent::__construct($definition);
  43418. }
  43419. protected function setTokens(array $tokens)
  43420. {
  43421. $this->tokens = $tokens;
  43422. }
  43423. protected function parse()
  43424. {
  43425. $parseOptions = true;
  43426. $this->parsed = $this->tokens;
  43427. while (null !== $token = array_shift($this->parsed)) {
  43428. if ($parseOptions && '' == $token) {
  43429. $this->parseArgument($token);
  43430. } elseif ($parseOptions && '--' == $token) {
  43431. $parseOptions = false;
  43432. } elseif ($parseOptions && 0 === strpos($token, '--')) {
  43433. $this->parseLongOption($token);
  43434. } elseif ($parseOptions && '-' === $token[0] && '-' !== $token) {
  43435. $this->parseShortOption($token);
  43436. } else {
  43437. $this->parseArgument($token);
  43438. }
  43439. }
  43440. }
  43441. private function parseShortOption($token)
  43442. {
  43443. $name = substr($token, 1);
  43444. if (\strlen($name) > 1) {
  43445. if ($this->definition->hasShortcut($name[0]) && $this->definition->getOptionForShortcut($name[0])->acceptValue()) {
  43446. $this->addShortOption($name[0], substr($name, 1));
  43447. } else {
  43448. $this->parseShortOptionSet($name);
  43449. }
  43450. } else {
  43451. $this->addShortOption($name, null);
  43452. }
  43453. }
  43454. private function parseShortOptionSet($name)
  43455. {
  43456. $len = \strlen($name);
  43457. for ($i = 0; $i < $len; ++$i) {
  43458. if (!$this->definition->hasShortcut($name[$i])) {
  43459. $encoding = mb_detect_encoding($name, null, true);
  43460. throw new RuntimeException(sprintf('The "-%s" option does not exist.', false === $encoding ? $name[$i] : mb_substr($name, $i, 1, $encoding)));
  43461. }
  43462. $option = $this->definition->getOptionForShortcut($name[$i]);
  43463. if ($option->acceptValue()) {
  43464. $this->addLongOption($option->getName(), $i === $len - 1 ? null : substr($name, $i + 1));
  43465. break;
  43466. } else {
  43467. $this->addLongOption($option->getName(), null);
  43468. }
  43469. }
  43470. }
  43471. private function parseLongOption($token)
  43472. {
  43473. $name = substr($token, 2);
  43474. if (false !== $pos = strpos($name, '=')) {
  43475. if (0 === \strlen($value = substr($name, $pos + 1))) {
  43476. if (\PHP_VERSION_ID < 70000 && false === $value) {
  43477. $value = '';
  43478. }
  43479. array_unshift($this->parsed, $value);
  43480. }
  43481. $this->addLongOption(substr($name, 0, $pos), $value);
  43482. } else {
  43483. $this->addLongOption($name, null);
  43484. }
  43485. }
  43486. private function parseArgument($token)
  43487. {
  43488. $c = \count($this->arguments);
  43489. if ($this->definition->hasArgument($c)) {
  43490. $arg = $this->definition->getArgument($c);
  43491. $this->arguments[$arg->getName()] = $arg->isArray() ? [$token] : $token;
  43492. } elseif ($this->definition->hasArgument($c - 1) && $this->definition->getArgument($c - 1)->isArray()) {
  43493. $arg = $this->definition->getArgument($c - 1);
  43494. $this->arguments[$arg->getName()][] = $token;
  43495. } else {
  43496. $all = $this->definition->getArguments();
  43497. if (\count($all)) {
  43498. throw new RuntimeException(sprintf('Too many arguments, expected arguments "%s".', implode('" "', array_keys($all))));
  43499. }
  43500. throw new RuntimeException(sprintf('No arguments expected, got "%s".', $token));
  43501. }
  43502. }
  43503. private function addShortOption($shortcut, $value)
  43504. {
  43505. if (!$this->definition->hasShortcut($shortcut)) {
  43506. throw new RuntimeException(sprintf('The "-%s" option does not exist.', $shortcut));
  43507. }
  43508. $this->addLongOption($this->definition->getOptionForShortcut($shortcut)->getName(), $value);
  43509. }
  43510. private function addLongOption($name, $value)
  43511. {
  43512. if (!$this->definition->hasOption($name)) {
  43513. throw new RuntimeException(sprintf('The "--%s" option does not exist.', $name));
  43514. }
  43515. $option = $this->definition->getOption($name);
  43516. if (null !== $value && !$option->acceptValue()) {
  43517. throw new RuntimeException(sprintf('The "--%s" option does not accept a value.', $name));
  43518. }
  43519. if (\in_array($value, ['', null], true) && $option->acceptValue() && \count($this->parsed)) {
  43520. $next = array_shift($this->parsed);
  43521. if ((isset($next[0]) && '-' !== $next[0]) || \in_array($next, ['', null], true)) {
  43522. $value = $next;
  43523. } else {
  43524. array_unshift($this->parsed, $next);
  43525. }
  43526. }
  43527. if (null === $value) {
  43528. if ($option->isValueRequired()) {
  43529. throw new RuntimeException(sprintf('The "--%s" option requires a value.', $name));
  43530. }
  43531. if (!$option->isArray() && !$option->isValueOptional()) {
  43532. $value = true;
  43533. }
  43534. }
  43535. if ($option->isArray()) {
  43536. $this->options[$name][] = $value;
  43537. } else {
  43538. $this->options[$name] = $value;
  43539. }
  43540. }
  43541. public function getFirstArgument()
  43542. {
  43543. $isOption = false;
  43544. foreach ($this->tokens as $i => $token) {
  43545. if ($token && '-' === $token[0]) {
  43546. if (false !== strpos($token, '=') || !isset($this->tokens[$i + 1])) {
  43547. continue;
  43548. }
  43549. $name = '-' === $token[1] ? substr($token, 2) : substr($token, -1);
  43550. if (!isset($this->options[$name]) && !$this->definition->hasShortcut($name)) {
  43551. } elseif ((isset($this->options[$name]) || isset($this->options[$name = $this->definition->shortcutToName($name)])) && $this->tokens[$i + 1] === $this->options[$name]) {
  43552. $isOption = true;
  43553. }
  43554. continue;
  43555. }
  43556. if ($isOption) {
  43557. $isOption = false;
  43558. continue;
  43559. }
  43560. return $token;
  43561. }
  43562. return null;
  43563. }
  43564. public function hasParameterOption($values, $onlyParams = false)
  43565. {
  43566. $values = (array) $values;
  43567. foreach ($this->tokens as $token) {
  43568. if ($onlyParams && '--' === $token) {
  43569. return false;
  43570. }
  43571. foreach ($values as $value) {
  43572. $leading = 0 === strpos($value, '--') ? $value.'=' : $value;
  43573. if ($token === $value || '' !== $leading && 0 === strpos($token, $leading)) {
  43574. return true;
  43575. }
  43576. }
  43577. }
  43578. return false;
  43579. }
  43580. public function getParameterOption($values, $default = false, $onlyParams = false)
  43581. {
  43582. $values = (array) $values;
  43583. $tokens = $this->tokens;
  43584. while (0 < \count($tokens)) {
  43585. $token = array_shift($tokens);
  43586. if ($onlyParams && '--' === $token) {
  43587. return $default;
  43588. }
  43589. foreach ($values as $value) {
  43590. if ($token === $value) {
  43591. return array_shift($tokens);
  43592. }
  43593. $leading = 0 === strpos($value, '--') ? $value.'=' : $value;
  43594. if ('' !== $leading && 0 === strpos($token, $leading)) {
  43595. return substr($token, \strlen($leading));
  43596. }
  43597. }
  43598. }
  43599. return $default;
  43600. }
  43601. public function __toString()
  43602. {
  43603. $tokens = array_map(function ($token) {
  43604. if (preg_match('{^(-[^=]+=)(.+)}', $token, $match)) {
  43605. return $match[1].$this->escapeToken($match[2]);
  43606. }
  43607. if ($token && '-' !== $token[0]) {
  43608. return $this->escapeToken($token);
  43609. }
  43610. return $token;
  43611. }, $this->tokens);
  43612. return implode(' ', $tokens);
  43613. }
  43614. }
  43615. <?php
  43616. namespace Symfony\Component\Console\Input;
  43617. use Symfony\Component\Console\Exception\InvalidArgumentException;
  43618. use Symfony\Component\Console\Exception\RuntimeException;
  43619. interface InputInterface
  43620. {
  43621. public function getFirstArgument();
  43622. public function hasParameterOption($values, $onlyParams = false);
  43623. public function getParameterOption($values, $default = false, $onlyParams = false);
  43624. public function bind(InputDefinition $definition);
  43625. public function validate();
  43626. public function getArguments();
  43627. public function getArgument($name);
  43628. public function setArgument($name, $value);
  43629. public function hasArgument($name);
  43630. public function getOptions();
  43631. public function getOption($name);
  43632. public function setOption($name, $value);
  43633. public function hasOption($name);
  43634. public function isInteractive();
  43635. public function setInteractive($interactive);
  43636. }
  43637. <?php
  43638. namespace Symfony\Component\Console\Input;
  43639. use Symfony\Component\Console\Exception\InvalidArgumentException;
  43640. use Symfony\Component\Console\Exception\LogicException;
  43641. class InputOption
  43642. {
  43643. const VALUE_NONE = 1;
  43644. const VALUE_REQUIRED = 2;
  43645. const VALUE_OPTIONAL = 4;
  43646. const VALUE_IS_ARRAY = 8;
  43647. private $name;
  43648. private $shortcut;
  43649. private $mode;
  43650. private $default;
  43651. private $description;
  43652. public function __construct($name, $shortcut = null, $mode = null, $description = '', $default = null)
  43653. {
  43654. if (0 === strpos($name, '--')) {
  43655. $name = substr($name, 2);
  43656. }
  43657. if (empty($name)) {
  43658. throw new InvalidArgumentException('An option name cannot be empty.');
  43659. }
  43660. if (empty($shortcut)) {
  43661. $shortcut = null;
  43662. }
  43663. if (null !== $shortcut) {
  43664. if (\is_array($shortcut)) {
  43665. $shortcut = implode('|', $shortcut);
  43666. }
  43667. $shortcuts = preg_split('{(\|)-?}', ltrim($shortcut, '-'));
  43668. $shortcuts = array_filter($shortcuts);
  43669. $shortcut = implode('|', $shortcuts);
  43670. if (empty($shortcut)) {
  43671. throw new InvalidArgumentException('An option shortcut cannot be empty.');
  43672. }
  43673. }
  43674. if (null === $mode) {
  43675. $mode = self::VALUE_NONE;
  43676. } elseif (!\is_int($mode) || $mode > 15 || $mode < 1) {
  43677. throw new InvalidArgumentException(sprintf('Option mode "%s" is not valid.', $mode));
  43678. }
  43679. $this->name = $name;
  43680. $this->shortcut = $shortcut;
  43681. $this->mode = $mode;
  43682. $this->description = $description;
  43683. if ($this->isArray() && !$this->acceptValue()) {
  43684. throw new InvalidArgumentException('Impossible to have an option mode VALUE_IS_ARRAY if the option does not accept a value.');
  43685. }
  43686. $this->setDefault($default);
  43687. }
  43688. public function getShortcut()
  43689. {
  43690. return $this->shortcut;
  43691. }
  43692. public function getName()
  43693. {
  43694. return $this->name;
  43695. }
  43696. public function acceptValue()
  43697. {
  43698. return $this->isValueRequired() || $this->isValueOptional();
  43699. }
  43700. public function isValueRequired()
  43701. {
  43702. return self::VALUE_REQUIRED === (self::VALUE_REQUIRED & $this->mode);
  43703. }
  43704. public function isValueOptional()
  43705. {
  43706. return self::VALUE_OPTIONAL === (self::VALUE_OPTIONAL & $this->mode);
  43707. }
  43708. public function isArray()
  43709. {
  43710. return self::VALUE_IS_ARRAY === (self::VALUE_IS_ARRAY & $this->mode);
  43711. }
  43712. public function setDefault($default = null)
  43713. {
  43714. if (self::VALUE_NONE === (self::VALUE_NONE & $this->mode) && null !== $default) {
  43715. throw new LogicException('Cannot set a default value when using InputOption::VALUE_NONE mode.');
  43716. }
  43717. if ($this->isArray()) {
  43718. if (null === $default) {
  43719. $default = [];
  43720. } elseif (!\is_array($default)) {
  43721. throw new LogicException('A default value for an array option must be an array.');
  43722. }
  43723. }
  43724. $this->default = $this->acceptValue() ? $default : false;
  43725. }
  43726. public function getDefault()
  43727. {
  43728. return $this->default;
  43729. }
  43730. public function getDescription()
  43731. {
  43732. return $this->description;
  43733. }
  43734. public function equals(self $option)
  43735. {
  43736. return $option->getName() === $this->getName()
  43737. && $option->getShortcut() === $this->getShortcut()
  43738. && $option->getDefault() === $this->getDefault()
  43739. && $option->isArray() === $this->isArray()
  43740. && $option->isValueRequired() === $this->isValueRequired()
  43741. && $option->isValueOptional() === $this->isValueOptional()
  43742. ;
  43743. }
  43744. }
  43745. <?php
  43746. namespace Symfony\Component\Console\Input;
  43747. interface InputAwareInterface
  43748. {
  43749. public function setInput(InputInterface $input);
  43750. }
  43751. <?php
  43752. namespace Symfony\Component\Console\Input;
  43753. interface StreamableInputInterface extends InputInterface
  43754. {
  43755. public function setStream($stream);
  43756. public function getStream();
  43757. }
  43758. <?php
  43759. namespace Symfony\Component\Console\Input;
  43760. use Symfony\Component\Console\Exception\InvalidArgumentException;
  43761. use Symfony\Component\Console\Exception\InvalidOptionException;
  43762. class ArrayInput extends Input
  43763. {
  43764. private $parameters;
  43765. public function __construct(array $parameters, InputDefinition $definition = null)
  43766. {
  43767. $this->parameters = $parameters;
  43768. parent::__construct($definition);
  43769. }
  43770. public function getFirstArgument()
  43771. {
  43772. foreach ($this->parameters as $param => $value) {
  43773. if ($param && \is_string($param) && '-' === $param[0]) {
  43774. continue;
  43775. }
  43776. return $value;
  43777. }
  43778. return null;
  43779. }
  43780. public function hasParameterOption($values, $onlyParams = false)
  43781. {
  43782. $values = (array) $values;
  43783. foreach ($this->parameters as $k => $v) {
  43784. if (!\is_int($k)) {
  43785. $v = $k;
  43786. }
  43787. if ($onlyParams && '--' === $v) {
  43788. return false;
  43789. }
  43790. if (\in_array($v, $values)) {
  43791. return true;
  43792. }
  43793. }
  43794. return false;
  43795. }
  43796. public function getParameterOption($values, $default = false, $onlyParams = false)
  43797. {
  43798. $values = (array) $values;
  43799. foreach ($this->parameters as $k => $v) {
  43800. if ($onlyParams && ('--' === $k || (\is_int($k) && '--' === $v))) {
  43801. return $default;
  43802. }
  43803. if (\is_int($k)) {
  43804. if (\in_array($v, $values)) {
  43805. return true;
  43806. }
  43807. } elseif (\in_array($k, $values)) {
  43808. return $v;
  43809. }
  43810. }
  43811. return $default;
  43812. }
  43813. public function __toString()
  43814. {
  43815. $params = [];
  43816. foreach ($this->parameters as $param => $val) {
  43817. if ($param && \is_string($param) && '-' === $param[0]) {
  43818. if (\is_array($val)) {
  43819. foreach ($val as $v) {
  43820. $params[] = $param.('' != $v ? '='.$this->escapeToken($v) : '');
  43821. }
  43822. } else {
  43823. $params[] = $param.('' != $val ? '='.$this->escapeToken($val) : '');
  43824. }
  43825. } else {
  43826. $params[] = \is_array($val) ? implode(' ', array_map([$this, 'escapeToken'], $val)) : $this->escapeToken($val);
  43827. }
  43828. }
  43829. return implode(' ', $params);
  43830. }
  43831. protected function parse()
  43832. {
  43833. foreach ($this->parameters as $key => $value) {
  43834. if ('--' === $key) {
  43835. return;
  43836. }
  43837. if (0 === strpos($key, '--')) {
  43838. $this->addLongOption(substr($key, 2), $value);
  43839. } elseif (0 === strpos($key, '-')) {
  43840. $this->addShortOption(substr($key, 1), $value);
  43841. } else {
  43842. $this->addArgument($key, $value);
  43843. }
  43844. }
  43845. }
  43846. private function addShortOption($shortcut, $value)
  43847. {
  43848. if (!$this->definition->hasShortcut($shortcut)) {
  43849. throw new InvalidOptionException(sprintf('The "-%s" option does not exist.', $shortcut));
  43850. }
  43851. $this->addLongOption($this->definition->getOptionForShortcut($shortcut)->getName(), $value);
  43852. }
  43853. private function addLongOption($name, $value)
  43854. {
  43855. if (!$this->definition->hasOption($name)) {
  43856. throw new InvalidOptionException(sprintf('The "--%s" option does not exist.', $name));
  43857. }
  43858. $option = $this->definition->getOption($name);
  43859. if (null === $value) {
  43860. if ($option->isValueRequired()) {
  43861. throw new InvalidOptionException(sprintf('The "--%s" option requires a value.', $name));
  43862. }
  43863. if (!$option->isValueOptional()) {
  43864. $value = true;
  43865. }
  43866. }
  43867. $this->options[$name] = $value;
  43868. }
  43869. private function addArgument($name, $value)
  43870. {
  43871. if (!$this->definition->hasArgument($name)) {
  43872. throw new InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name));
  43873. }
  43874. $this->arguments[$name] = $value;
  43875. }
  43876. }
  43877. <?php
  43878. namespace Symfony\Component\Console\Exception;
  43879. class CommandNotFoundException extends \InvalidArgumentException implements ExceptionInterface
  43880. {
  43881. private $alternatives;
  43882. public function __construct($message, array $alternatives = [], $code = 0, \Exception $previous = null)
  43883. {
  43884. parent::__construct($message, $code, $previous);
  43885. $this->alternatives = $alternatives;
  43886. }
  43887. public function getAlternatives()
  43888. {
  43889. return $this->alternatives;
  43890. }
  43891. }
  43892. <?php
  43893. namespace Symfony\Component\Console\Exception;
  43894. class InvalidOptionException extends \InvalidArgumentException implements ExceptionInterface
  43895. {
  43896. }
  43897. <?php
  43898. namespace Symfony\Component\Console\Exception;
  43899. interface ExceptionInterface
  43900. {
  43901. }
  43902. <?php
  43903. namespace Symfony\Component\Console\Exception;
  43904. class RuntimeException extends \RuntimeException implements ExceptionInterface
  43905. {
  43906. }
  43907. <?php
  43908. namespace Symfony\Component\Console\Exception;
  43909. class LogicException extends \LogicException implements ExceptionInterface
  43910. {
  43911. }
  43912. <?php
  43913. namespace Symfony\Component\Console\Exception;
  43914. class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface
  43915. {
  43916. }
  43917. <?php
  43918. namespace Symfony\Component\Console\Descriptor;
  43919. use Symfony\Component\Console\Application;
  43920. use Symfony\Component\Console\Command\Command;
  43921. use Symfony\Component\Console\Helper\Helper;
  43922. use Symfony\Component\Console\Input\InputArgument;
  43923. use Symfony\Component\Console\Input\InputDefinition;
  43924. use Symfony\Component\Console\Input\InputOption;
  43925. use Symfony\Component\Console\Output\OutputInterface;
  43926. class MarkdownDescriptor extends Descriptor
  43927. {
  43928. public function describe(OutputInterface $output, $object, array $options = [])
  43929. {
  43930. $decorated = $output->isDecorated();
  43931. $output->setDecorated(false);
  43932. parent::describe($output, $object, $options);
  43933. $output->setDecorated($decorated);
  43934. }
  43935. protected function write($content, $decorated = true)
  43936. {
  43937. parent::write($content, $decorated);
  43938. }
  43939. protected function describeInputArgument(InputArgument $argument, array $options = [])
  43940. {
  43941. $this->write(
  43942. '#### `'.($argument->getName() ?: '<none>')."`\n\n"
  43943. .($argument->getDescription() ? preg_replace('/\s*[\r\n]\s*/', "\n", $argument->getDescription())."\n\n" : '')
  43944. .'* Is required: '.($argument->isRequired() ? 'yes' : 'no')."\n"
  43945. .'* Is array: '.($argument->isArray() ? 'yes' : 'no')."\n"
  43946. .'* Default: `'.str_replace("\n", '', var_export($argument->getDefault(), true)).'`'
  43947. );
  43948. }
  43949. protected function describeInputOption(InputOption $option, array $options = [])
  43950. {
  43951. $name = '--'.$option->getName();
  43952. if ($option->getShortcut()) {
  43953. $name .= '|-'.str_replace('|', '|-', $option->getShortcut()).'';
  43954. }
  43955. $this->write(
  43956. '#### `'.$name.'`'."\n\n"
  43957. .($option->getDescription() ? preg_replace('/\s*[\r\n]\s*/', "\n", $option->getDescription())."\n\n" : '')
  43958. .'* Accept value: '.($option->acceptValue() ? 'yes' : 'no')."\n"
  43959. .'* Is value required: '.($option->isValueRequired() ? 'yes' : 'no')."\n"
  43960. .'* Is multiple: '.($option->isArray() ? 'yes' : 'no')."\n"
  43961. .'* Default: `'.str_replace("\n", '', var_export($option->getDefault(), true)).'`'
  43962. );
  43963. }
  43964. protected function describeInputDefinition(InputDefinition $definition, array $options = [])
  43965. {
  43966. if ($showArguments = \count($definition->getArguments()) > 0) {
  43967. $this->write('### Arguments');
  43968. foreach ($definition->getArguments() as $argument) {
  43969. $this->write("\n\n");
  43970. $this->write($this->describeInputArgument($argument));
  43971. }
  43972. }
  43973. if (\count($definition->getOptions()) > 0) {
  43974. if ($showArguments) {
  43975. $this->write("\n\n");
  43976. }
  43977. $this->write('### Options');
  43978. foreach ($definition->getOptions() as $option) {
  43979. $this->write("\n\n");
  43980. $this->write($this->describeInputOption($option));
  43981. }
  43982. }
  43983. }
  43984. protected function describeCommand(Command $command, array $options = [])
  43985. {
  43986. $command->getSynopsis();
  43987. $command->mergeApplicationDefinition(false);
  43988. $this->write(
  43989. '`'.$command->getName()."`\n"
  43990. .str_repeat('-', Helper::strlen($command->getName()) + 2)."\n\n"
  43991. .($command->getDescription() ? $command->getDescription()."\n\n" : '')
  43992. .'### Usage'."\n\n"
  43993. .array_reduce(array_merge([$command->getSynopsis()], $command->getAliases(), $command->getUsages()), function ($carry, $usage) {
  43994. return $carry.'* `'.$usage.'`'."\n";
  43995. })
  43996. );
  43997. if ($help = $command->getProcessedHelp()) {
  43998. $this->write("\n");
  43999. $this->write($help);
  44000. }
  44001. if ($command->getNativeDefinition()) {
  44002. $this->write("\n\n");
  44003. $this->describeInputDefinition($command->getNativeDefinition());
  44004. }
  44005. }
  44006. protected function describeApplication(Application $application, array $options = [])
  44007. {
  44008. $describedNamespace = isset($options['namespace']) ? $options['namespace'] : null;
  44009. $description = new ApplicationDescription($application, $describedNamespace);
  44010. $title = $this->getApplicationTitle($application);
  44011. $this->write($title."\n".str_repeat('=', Helper::strlen($title)));
  44012. foreach ($description->getNamespaces() as $namespace) {
  44013. if (ApplicationDescription::GLOBAL_NAMESPACE !== $namespace['id']) {
  44014. $this->write("\n\n");
  44015. $this->write('**'.$namespace['id'].':**');
  44016. }
  44017. $this->write("\n\n");
  44018. $this->write(implode("\n", array_map(function ($commandName) use ($description) {
  44019. return sprintf('* [`%s`](#%s)', $commandName, str_replace(':', '', $description->getCommand($commandName)->getName()));
  44020. }, $namespace['commands'])));
  44021. }
  44022. foreach ($description->getCommands() as $command) {
  44023. $this->write("\n\n");
  44024. $this->write($this->describeCommand($command));
  44025. }
  44026. }
  44027. private function getApplicationTitle(Application $application)
  44028. {
  44029. if ('UNKNOWN' !== $application->getName()) {
  44030. if ('UNKNOWN' !== $application->getVersion()) {
  44031. return sprintf('%s %s', $application->getName(), $application->getVersion());
  44032. }
  44033. return $application->getName();
  44034. }
  44035. return 'Console Tool';
  44036. }
  44037. }
  44038. <?php
  44039. namespace Symfony\Component\Console\Descriptor;
  44040. use Symfony\Component\Console\Application;
  44041. use Symfony\Component\Console\Command\Command;
  44042. use Symfony\Component\Console\Exception\CommandNotFoundException;
  44043. class ApplicationDescription
  44044. {
  44045. const GLOBAL_NAMESPACE = '_global';
  44046. private $application;
  44047. private $namespace;
  44048. private $showHidden;
  44049. private $namespaces;
  44050. private $commands;
  44051. private $aliases;
  44052. public function __construct(Application $application, $namespace = null, $showHidden = false)
  44053. {
  44054. $this->application = $application;
  44055. $this->namespace = $namespace;
  44056. $this->showHidden = $showHidden;
  44057. }
  44058. public function getNamespaces()
  44059. {
  44060. if (null === $this->namespaces) {
  44061. $this->inspectApplication();
  44062. }
  44063. return $this->namespaces;
  44064. }
  44065. public function getCommands()
  44066. {
  44067. if (null === $this->commands) {
  44068. $this->inspectApplication();
  44069. }
  44070. return $this->commands;
  44071. }
  44072. public function getCommand($name)
  44073. {
  44074. if (!isset($this->commands[$name]) && !isset($this->aliases[$name])) {
  44075. throw new CommandNotFoundException(sprintf('Command "%s" does not exist.', $name));
  44076. }
  44077. return isset($this->commands[$name]) ? $this->commands[$name] : $this->aliases[$name];
  44078. }
  44079. private function inspectApplication()
  44080. {
  44081. $this->commands = [];
  44082. $this->namespaces = [];
  44083. $all = $this->application->all($this->namespace ? $this->application->findNamespace($this->namespace) : null);
  44084. foreach ($this->sortCommands($all) as $namespace => $commands) {
  44085. $names = [];
  44086. foreach ($commands as $name => $command) {
  44087. if (!$command->getName() || (!$this->showHidden && $command->isHidden())) {
  44088. continue;
  44089. }
  44090. if ($command->getName() === $name) {
  44091. $this->commands[$name] = $command;
  44092. } else {
  44093. $this->aliases[$name] = $command;
  44094. }
  44095. $names[] = $name;
  44096. }
  44097. $this->namespaces[$namespace] = ['id' => $namespace, 'commands' => $names];
  44098. }
  44099. }
  44100. private function sortCommands(array $commands)
  44101. {
  44102. $namespacedCommands = [];
  44103. $globalCommands = [];
  44104. $sortedCommands = [];
  44105. foreach ($commands as $name => $command) {
  44106. $key = $this->application->extractNamespace($name, 1);
  44107. if (\in_array($key, ['', self::GLOBAL_NAMESPACE], true)) {
  44108. $globalCommands[$name] = $command;
  44109. } else {
  44110. $namespacedCommands[$key][$name] = $command;
  44111. }
  44112. }
  44113. if ($globalCommands) {
  44114. ksort($globalCommands);
  44115. $sortedCommands[self::GLOBAL_NAMESPACE] = $globalCommands;
  44116. }
  44117. if ($namespacedCommands) {
  44118. ksort($namespacedCommands);
  44119. foreach ($namespacedCommands as $key => $commandsSet) {
  44120. ksort($commandsSet);
  44121. $sortedCommands[$key] = $commandsSet;
  44122. }
  44123. }
  44124. return $sortedCommands;
  44125. }
  44126. }
  44127. <?php
  44128. namespace Symfony\Component\Console\Descriptor;
  44129. use Symfony\Component\Console\Application;
  44130. use Symfony\Component\Console\Command\Command;
  44131. use Symfony\Component\Console\Exception\InvalidArgumentException;
  44132. use Symfony\Component\Console\Input\InputArgument;
  44133. use Symfony\Component\Console\Input\InputDefinition;
  44134. use Symfony\Component\Console\Input\InputOption;
  44135. use Symfony\Component\Console\Output\OutputInterface;
  44136. abstract class Descriptor implements DescriptorInterface
  44137. {
  44138. protected $output;
  44139. public function describe(OutputInterface $output, $object, array $options = [])
  44140. {
  44141. $this->output = $output;
  44142. switch (true) {
  44143. case $object instanceof InputArgument:
  44144. $this->describeInputArgument($object, $options);
  44145. break;
  44146. case $object instanceof InputOption:
  44147. $this->describeInputOption($object, $options);
  44148. break;
  44149. case $object instanceof InputDefinition:
  44150. $this->describeInputDefinition($object, $options);
  44151. break;
  44152. case $object instanceof Command:
  44153. $this->describeCommand($object, $options);
  44154. break;
  44155. case $object instanceof Application:
  44156. $this->describeApplication($object, $options);
  44157. break;
  44158. default:
  44159. throw new InvalidArgumentException(sprintf('Object of type "%s" is not describable.', \get_class($object)));
  44160. }
  44161. }
  44162. protected function write($content, $decorated = false)
  44163. {
  44164. $this->output->write($content, false, $decorated ? OutputInterface::OUTPUT_NORMAL : OutputInterface::OUTPUT_RAW);
  44165. }
  44166. abstract protected function describeInputArgument(InputArgument $argument, array $options = []);
  44167. abstract protected function describeInputOption(InputOption $option, array $options = []);
  44168. abstract protected function describeInputDefinition(InputDefinition $definition, array $options = []);
  44169. abstract protected function describeCommand(Command $command, array $options = []);
  44170. abstract protected function describeApplication(Application $application, array $options = []);
  44171. }
  44172. <?php
  44173. namespace Symfony\Component\Console\Descriptor;
  44174. use Symfony\Component\Console\Application;
  44175. use Symfony\Component\Console\Command\Command;
  44176. use Symfony\Component\Console\Input\InputArgument;
  44177. use Symfony\Component\Console\Input\InputDefinition;
  44178. use Symfony\Component\Console\Input\InputOption;
  44179. class JsonDescriptor extends Descriptor
  44180. {
  44181. protected function describeInputArgument(InputArgument $argument, array $options = [])
  44182. {
  44183. $this->writeData($this->getInputArgumentData($argument), $options);
  44184. }
  44185. protected function describeInputOption(InputOption $option, array $options = [])
  44186. {
  44187. $this->writeData($this->getInputOptionData($option), $options);
  44188. }
  44189. protected function describeInputDefinition(InputDefinition $definition, array $options = [])
  44190. {
  44191. $this->writeData($this->getInputDefinitionData($definition), $options);
  44192. }
  44193. protected function describeCommand(Command $command, array $options = [])
  44194. {
  44195. $this->writeData($this->getCommandData($command), $options);
  44196. }
  44197. protected function describeApplication(Application $application, array $options = [])
  44198. {
  44199. $describedNamespace = isset($options['namespace']) ? $options['namespace'] : null;
  44200. $description = new ApplicationDescription($application, $describedNamespace, true);
  44201. $commands = [];
  44202. foreach ($description->getCommands() as $command) {
  44203. $commands[] = $this->getCommandData($command);
  44204. }
  44205. $data = [];
  44206. if ('UNKNOWN' !== $application->getName()) {
  44207. $data['application']['name'] = $application->getName();
  44208. if ('UNKNOWN' !== $application->getVersion()) {
  44209. $data['application']['version'] = $application->getVersion();
  44210. }
  44211. }
  44212. $data['commands'] = $commands;
  44213. if ($describedNamespace) {
  44214. $data['namespace'] = $describedNamespace;
  44215. } else {
  44216. $data['namespaces'] = array_values($description->getNamespaces());
  44217. }
  44218. $this->writeData($data, $options);
  44219. }
  44220. private function writeData(array $data, array $options)
  44221. {
  44222. $flags = isset($options['json_encoding']) ? $options['json_encoding'] : 0;
  44223. $this->write(json_encode($data, $flags));
  44224. }
  44225. private function getInputArgumentData(InputArgument $argument)
  44226. {
  44227. return [
  44228. 'name' => $argument->getName(),
  44229. 'is_required' => $argument->isRequired(),
  44230. 'is_array' => $argument->isArray(),
  44231. 'description' => preg_replace('/\s*[\r\n]\s*/', ' ', $argument->getDescription()),
  44232. 'default' => INF === $argument->getDefault() ? 'INF' : $argument->getDefault(),
  44233. ];
  44234. }
  44235. private function getInputOptionData(InputOption $option)
  44236. {
  44237. return [
  44238. 'name' => '--'.$option->getName(),
  44239. 'shortcut' => $option->getShortcut() ? '-'.str_replace('|', '|-', $option->getShortcut()) : '',
  44240. 'accept_value' => $option->acceptValue(),
  44241. 'is_value_required' => $option->isValueRequired(),
  44242. 'is_multiple' => $option->isArray(),
  44243. 'description' => preg_replace('/\s*[\r\n]\s*/', ' ', $option->getDescription()),
  44244. 'default' => INF === $option->getDefault() ? 'INF' : $option->getDefault(),
  44245. ];
  44246. }
  44247. private function getInputDefinitionData(InputDefinition $definition)
  44248. {
  44249. $inputArguments = [];
  44250. foreach ($definition->getArguments() as $name => $argument) {
  44251. $inputArguments[$name] = $this->getInputArgumentData($argument);
  44252. }
  44253. $inputOptions = [];
  44254. foreach ($definition->getOptions() as $name => $option) {
  44255. $inputOptions[$name] = $this->getInputOptionData($option);
  44256. }
  44257. return ['arguments' => $inputArguments, 'options' => $inputOptions];
  44258. }
  44259. private function getCommandData(Command $command)
  44260. {
  44261. $command->getSynopsis();
  44262. $command->mergeApplicationDefinition(false);
  44263. return [
  44264. 'name' => $command->getName(),
  44265. 'usage' => array_merge([$command->getSynopsis()], $command->getUsages(), $command->getAliases()),
  44266. 'description' => $command->getDescription(),
  44267. 'help' => $command->getProcessedHelp(),
  44268. 'definition' => $this->getInputDefinitionData($command->getNativeDefinition()),
  44269. 'hidden' => $command->isHidden(),
  44270. ];
  44271. }
  44272. }
  44273. <?php
  44274. namespace Symfony\Component\Console\Descriptor;
  44275. use Symfony\Component\Console\Output\OutputInterface;
  44276. interface DescriptorInterface
  44277. {
  44278. public function describe(OutputInterface $output, $object, array $options = []);
  44279. }
  44280. <?php
  44281. namespace Symfony\Component\Console\Descriptor;
  44282. use Symfony\Component\Console\Application;
  44283. use Symfony\Component\Console\Command\Command;
  44284. use Symfony\Component\Console\Formatter\OutputFormatter;
  44285. use Symfony\Component\Console\Helper\Helper;
  44286. use Symfony\Component\Console\Input\InputArgument;
  44287. use Symfony\Component\Console\Input\InputDefinition;
  44288. use Symfony\Component\Console\Input\InputOption;
  44289. class TextDescriptor extends Descriptor
  44290. {
  44291. protected function describeInputArgument(InputArgument $argument, array $options = [])
  44292. {
  44293. if (null !== $argument->getDefault() && (!\is_array($argument->getDefault()) || \count($argument->getDefault()))) {
  44294. $default = sprintf('<comment> [default: %s]</comment>', $this->formatDefaultValue($argument->getDefault()));
  44295. } else {
  44296. $default = '';
  44297. }
  44298. $totalWidth = isset($options['total_width']) ? $options['total_width'] : Helper::strlen($argument->getName());
  44299. $spacingWidth = $totalWidth - \strlen($argument->getName());
  44300. $this->writeText(sprintf(' <info>%s</info> %s%s%s',
  44301. $argument->getName(),
  44302. str_repeat(' ', $spacingWidth),
  44303. preg_replace('/\s*[\r\n]\s*/', "\n".str_repeat(' ', $totalWidth + 4), $argument->getDescription()),
  44304. $default
  44305. ), $options);
  44306. }
  44307. protected function describeInputOption(InputOption $option, array $options = [])
  44308. {
  44309. if ($option->acceptValue() && null !== $option->getDefault() && (!\is_array($option->getDefault()) || \count($option->getDefault()))) {
  44310. $default = sprintf('<comment> [default: %s]</comment>', $this->formatDefaultValue($option->getDefault()));
  44311. } else {
  44312. $default = '';
  44313. }
  44314. $value = '';
  44315. if ($option->acceptValue()) {
  44316. $value = '='.strtoupper($option->getName());
  44317. if ($option->isValueOptional()) {
  44318. $value = '['.$value.']';
  44319. }
  44320. }
  44321. $totalWidth = isset($options['total_width']) ? $options['total_width'] : $this->calculateTotalWidthForOptions([$option]);
  44322. $synopsis = sprintf('%s%s',
  44323. $option->getShortcut() ? sprintf('-%s, ', $option->getShortcut()) : ' ',
  44324. sprintf('--%s%s', $option->getName(), $value)
  44325. );
  44326. $spacingWidth = $totalWidth - Helper::strlen($synopsis);
  44327. $this->writeText(sprintf(' <info>%s</info> %s%s%s%s',
  44328. $synopsis,
  44329. str_repeat(' ', $spacingWidth),
  44330. preg_replace('/\s*[\r\n]\s*/', "\n".str_repeat(' ', $totalWidth + 4), $option->getDescription()),
  44331. $default,
  44332. $option->isArray() ? '<comment> (multiple values allowed)</comment>' : ''
  44333. ), $options);
  44334. }
  44335. protected function describeInputDefinition(InputDefinition $definition, array $options = [])
  44336. {
  44337. $totalWidth = $this->calculateTotalWidthForOptions($definition->getOptions());
  44338. foreach ($definition->getArguments() as $argument) {
  44339. $totalWidth = max($totalWidth, Helper::strlen($argument->getName()));
  44340. }
  44341. if ($definition->getArguments()) {
  44342. $this->writeText('<comment>Arguments:</comment>', $options);
  44343. $this->writeText("\n");
  44344. foreach ($definition->getArguments() as $argument) {
  44345. $this->describeInputArgument($argument, array_merge($options, ['total_width' => $totalWidth]));
  44346. $this->writeText("\n");
  44347. }
  44348. }
  44349. if ($definition->getArguments() && $definition->getOptions()) {
  44350. $this->writeText("\n");
  44351. }
  44352. if ($definition->getOptions()) {
  44353. $laterOptions = [];
  44354. $this->writeText('<comment>Options:</comment>', $options);
  44355. foreach ($definition->getOptions() as $option) {
  44356. if (\strlen($option->getShortcut()) > 1) {
  44357. $laterOptions[] = $option;
  44358. continue;
  44359. }
  44360. $this->writeText("\n");
  44361. $this->describeInputOption($option, array_merge($options, ['total_width' => $totalWidth]));
  44362. }
  44363. foreach ($laterOptions as $option) {
  44364. $this->writeText("\n");
  44365. $this->describeInputOption($option, array_merge($options, ['total_width' => $totalWidth]));
  44366. }
  44367. }
  44368. }
  44369. protected function describeCommand(Command $command, array $options = [])
  44370. {
  44371. $command->getSynopsis(true);
  44372. $command->getSynopsis(false);
  44373. $command->mergeApplicationDefinition(false);
  44374. $this->writeText('<comment>Usage:</comment>', $options);
  44375. foreach (array_merge([$command->getSynopsis(true)], $command->getAliases(), $command->getUsages()) as $usage) {
  44376. $this->writeText("\n");
  44377. $this->writeText(' '.OutputFormatter::escape($usage), $options);
  44378. }
  44379. $this->writeText("\n");
  44380. $definition = $command->getNativeDefinition();
  44381. if ($definition->getOptions() || $definition->getArguments()) {
  44382. $this->writeText("\n");
  44383. $this->describeInputDefinition($definition, $options);
  44384. $this->writeText("\n");
  44385. }
  44386. if ($help = $command->getProcessedHelp()) {
  44387. $this->writeText("\n");
  44388. $this->writeText('<comment>Help:</comment>', $options);
  44389. $this->writeText("\n");
  44390. $this->writeText(' '.str_replace("\n", "\n ", $help), $options);
  44391. $this->writeText("\n");
  44392. }
  44393. }
  44394. protected function describeApplication(Application $application, array $options = [])
  44395. {
  44396. $describedNamespace = isset($options['namespace']) ? $options['namespace'] : null;
  44397. $description = new ApplicationDescription($application, $describedNamespace);
  44398. if (isset($options['raw_text']) && $options['raw_text']) {
  44399. $width = $this->getColumnWidth($description->getCommands());
  44400. foreach ($description->getCommands() as $command) {
  44401. $this->writeText(sprintf("%-{$width}s %s", $command->getName(), $command->getDescription()), $options);
  44402. $this->writeText("\n");
  44403. }
  44404. } else {
  44405. if ('' != $help = $application->getHelp()) {
  44406. $this->writeText("$help\n\n", $options);
  44407. }
  44408. $this->writeText("<comment>Usage:</comment>\n", $options);
  44409. $this->writeText(" command [options] [arguments]\n\n", $options);
  44410. $this->describeInputDefinition(new InputDefinition($application->getDefinition()->getOptions()), $options);
  44411. $this->writeText("\n");
  44412. $this->writeText("\n");
  44413. $commands = $description->getCommands();
  44414. $namespaces = $description->getNamespaces();
  44415. if ($describedNamespace && $namespaces) {
  44416. $describedNamespaceInfo = reset($namespaces);
  44417. foreach ($describedNamespaceInfo['commands'] as $name) {
  44418. $commands[$name] = $description->getCommand($name);
  44419. }
  44420. }
  44421. $width = $this->getColumnWidth(\call_user_func_array('array_merge', array_map(function ($namespace) use ($commands) {
  44422. return array_intersect($namespace['commands'], array_keys($commands));
  44423. }, $namespaces)));
  44424. if ($describedNamespace) {
  44425. $this->writeText(sprintf('<comment>Available commands for the "%s" namespace:</comment>', $describedNamespace), $options);
  44426. } else {
  44427. $this->writeText('<comment>Available commands:</comment>', $options);
  44428. }
  44429. foreach ($namespaces as $namespace) {
  44430. $namespace['commands'] = array_filter($namespace['commands'], function ($name) use ($commands) {
  44431. return isset($commands[$name]);
  44432. });
  44433. if (!$namespace['commands']) {
  44434. continue;
  44435. }
  44436. if (!$describedNamespace && ApplicationDescription::GLOBAL_NAMESPACE !== $namespace['id']) {
  44437. $this->writeText("\n");
  44438. $this->writeText(' <comment>'.$namespace['id'].'</comment>', $options);
  44439. }
  44440. foreach ($namespace['commands'] as $name) {
  44441. $this->writeText("\n");
  44442. $spacingWidth = $width - Helper::strlen($name);
  44443. $command = $commands[$name];
  44444. $commandAliases = $name === $command->getName() ? $this->getCommandAliasesText($command) : '';
  44445. $this->writeText(sprintf(' <info>%s</info>%s%s', $name, str_repeat(' ', $spacingWidth), $commandAliases.$command->getDescription()), $options);
  44446. }
  44447. }
  44448. $this->writeText("\n");
  44449. }
  44450. }
  44451. private function writeText($content, array $options = [])
  44452. {
  44453. $this->write(
  44454. isset($options['raw_text']) && $options['raw_text'] ? strip_tags($content) : $content,
  44455. isset($options['raw_output']) ? !$options['raw_output'] : true
  44456. );
  44457. }
  44458. private function getCommandAliasesText(Command $command)
  44459. {
  44460. $text = '';
  44461. $aliases = $command->getAliases();
  44462. if ($aliases) {
  44463. $text = '['.implode('|', $aliases).'] ';
  44464. }
  44465. return $text;
  44466. }
  44467. private function formatDefaultValue($default)
  44468. {
  44469. if (INF === $default) {
  44470. return 'INF';
  44471. }
  44472. if (\is_string($default)) {
  44473. $default = OutputFormatter::escape($default);
  44474. } elseif (\is_array($default)) {
  44475. foreach ($default as $key => $value) {
  44476. if (\is_string($value)) {
  44477. $default[$key] = OutputFormatter::escape($value);
  44478. }
  44479. }
  44480. }
  44481. return str_replace('\\\\', '\\', json_encode($default, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE));
  44482. }
  44483. private function getColumnWidth(array $commands)
  44484. {
  44485. $widths = [];
  44486. foreach ($commands as $command) {
  44487. if ($command instanceof Command) {
  44488. $widths[] = Helper::strlen($command->getName());
  44489. foreach ($command->getAliases() as $alias) {
  44490. $widths[] = Helper::strlen($alias);
  44491. }
  44492. } else {
  44493. $widths[] = Helper::strlen($command);
  44494. }
  44495. }
  44496. return $widths ? max($widths) + 2 : 0;
  44497. }
  44498. private function calculateTotalWidthForOptions(array $options)
  44499. {
  44500. $totalWidth = 0;
  44501. foreach ($options as $option) {
  44502. $nameLength = 1 + max(Helper::strlen($option->getShortcut()), 1) + 4 + Helper::strlen($option->getName());
  44503. if ($option->acceptValue()) {
  44504. $valueLength = 1 + Helper::strlen($option->getName());
  44505. $valueLength += $option->isValueOptional() ? 2 : 0;
  44506. $nameLength += $valueLength;
  44507. }
  44508. $totalWidth = max($totalWidth, $nameLength);
  44509. }
  44510. return $totalWidth;
  44511. }
  44512. }
  44513. <?php
  44514. namespace Symfony\Component\Console\Descriptor;
  44515. use Symfony\Component\Console\Application;
  44516. use Symfony\Component\Console\Command\Command;
  44517. use Symfony\Component\Console\Input\InputArgument;
  44518. use Symfony\Component\Console\Input\InputDefinition;
  44519. use Symfony\Component\Console\Input\InputOption;
  44520. class XmlDescriptor extends Descriptor
  44521. {
  44522. public function getInputDefinitionDocument(InputDefinition $definition)
  44523. {
  44524. $dom = new \DOMDocument('1.0', 'UTF-8');
  44525. $dom->appendChild($definitionXML = $dom->createElement('definition'));
  44526. $definitionXML->appendChild($argumentsXML = $dom->createElement('arguments'));
  44527. foreach ($definition->getArguments() as $argument) {
  44528. $this->appendDocument($argumentsXML, $this->getInputArgumentDocument($argument));
  44529. }
  44530. $definitionXML->appendChild($optionsXML = $dom->createElement('options'));
  44531. foreach ($definition->getOptions() as $option) {
  44532. $this->appendDocument($optionsXML, $this->getInputOptionDocument($option));
  44533. }
  44534. return $dom;
  44535. }
  44536. public function getCommandDocument(Command $command)
  44537. {
  44538. $dom = new \DOMDocument('1.0', 'UTF-8');
  44539. $dom->appendChild($commandXML = $dom->createElement('command'));
  44540. $command->getSynopsis();
  44541. $command->mergeApplicationDefinition(false);
  44542. $commandXML->setAttribute('id', $command->getName());
  44543. $commandXML->setAttribute('name', $command->getName());
  44544. $commandXML->setAttribute('hidden', $command->isHidden() ? 1 : 0);
  44545. $commandXML->appendChild($usagesXML = $dom->createElement('usages'));
  44546. foreach (array_merge([$command->getSynopsis()], $command->getAliases(), $command->getUsages()) as $usage) {
  44547. $usagesXML->appendChild($dom->createElement('usage', $usage));
  44548. }
  44549. $commandXML->appendChild($descriptionXML = $dom->createElement('description'));
  44550. $descriptionXML->appendChild($dom->createTextNode(str_replace("\n", "\n ", $command->getDescription())));
  44551. $commandXML->appendChild($helpXML = $dom->createElement('help'));
  44552. $helpXML->appendChild($dom->createTextNode(str_replace("\n", "\n ", $command->getProcessedHelp())));
  44553. $definitionXML = $this->getInputDefinitionDocument($command->getNativeDefinition());
  44554. $this->appendDocument($commandXML, $definitionXML->getElementsByTagName('definition')->item(0));
  44555. return $dom;
  44556. }
  44557. public function getApplicationDocument(Application $application, $namespace = null)
  44558. {
  44559. $dom = new \DOMDocument('1.0', 'UTF-8');
  44560. $dom->appendChild($rootXml = $dom->createElement('symfony'));
  44561. if ('UNKNOWN' !== $application->getName()) {
  44562. $rootXml->setAttribute('name', $application->getName());
  44563. if ('UNKNOWN' !== $application->getVersion()) {
  44564. $rootXml->setAttribute('version', $application->getVersion());
  44565. }
  44566. }
  44567. $rootXml->appendChild($commandsXML = $dom->createElement('commands'));
  44568. $description = new ApplicationDescription($application, $namespace, true);
  44569. if ($namespace) {
  44570. $commandsXML->setAttribute('namespace', $namespace);
  44571. }
  44572. foreach ($description->getCommands() as $command) {
  44573. $this->appendDocument($commandsXML, $this->getCommandDocument($command));
  44574. }
  44575. if (!$namespace) {
  44576. $rootXml->appendChild($namespacesXML = $dom->createElement('namespaces'));
  44577. foreach ($description->getNamespaces() as $namespaceDescription) {
  44578. $namespacesXML->appendChild($namespaceArrayXML = $dom->createElement('namespace'));
  44579. $namespaceArrayXML->setAttribute('id', $namespaceDescription['id']);
  44580. foreach ($namespaceDescription['commands'] as $name) {
  44581. $namespaceArrayXML->appendChild($commandXML = $dom->createElement('command'));
  44582. $commandXML->appendChild($dom->createTextNode($name));
  44583. }
  44584. }
  44585. }
  44586. return $dom;
  44587. }
  44588. protected function describeInputArgument(InputArgument $argument, array $options = [])
  44589. {
  44590. $this->writeDocument($this->getInputArgumentDocument($argument));
  44591. }
  44592. protected function describeInputOption(InputOption $option, array $options = [])
  44593. {
  44594. $this->writeDocument($this->getInputOptionDocument($option));
  44595. }
  44596. protected function describeInputDefinition(InputDefinition $definition, array $options = [])
  44597. {
  44598. $this->writeDocument($this->getInputDefinitionDocument($definition));
  44599. }
  44600. protected function describeCommand(Command $command, array $options = [])
  44601. {
  44602. $this->writeDocument($this->getCommandDocument($command));
  44603. }
  44604. protected function describeApplication(Application $application, array $options = [])
  44605. {
  44606. $this->writeDocument($this->getApplicationDocument($application, isset($options['namespace']) ? $options['namespace'] : null));
  44607. }
  44608. private function appendDocument(\DOMNode $parentNode, \DOMNode $importedParent)
  44609. {
  44610. foreach ($importedParent->childNodes as $childNode) {
  44611. $parentNode->appendChild($parentNode->ownerDocument->importNode($childNode, true));
  44612. }
  44613. }
  44614. private function writeDocument(\DOMDocument $dom)
  44615. {
  44616. $dom->formatOutput = true;
  44617. $this->write($dom->saveXML());
  44618. }
  44619. private function getInputArgumentDocument(InputArgument $argument)
  44620. {
  44621. $dom = new \DOMDocument('1.0', 'UTF-8');
  44622. $dom->appendChild($objectXML = $dom->createElement('argument'));
  44623. $objectXML->setAttribute('name', $argument->getName());
  44624. $objectXML->setAttribute('is_required', $argument->isRequired() ? 1 : 0);
  44625. $objectXML->setAttribute('is_array', $argument->isArray() ? 1 : 0);
  44626. $objectXML->appendChild($descriptionXML = $dom->createElement('description'));
  44627. $descriptionXML->appendChild($dom->createTextNode($argument->getDescription()));
  44628. $objectXML->appendChild($defaultsXML = $dom->createElement('defaults'));
  44629. $defaults = \is_array($argument->getDefault()) ? $argument->getDefault() : (\is_bool($argument->getDefault()) ? [var_export($argument->getDefault(), true)] : ($argument->getDefault() ? [$argument->getDefault()] : []));
  44630. foreach ($defaults as $default) {
  44631. $defaultsXML->appendChild($defaultXML = $dom->createElement('default'));
  44632. $defaultXML->appendChild($dom->createTextNode($default));
  44633. }
  44634. return $dom;
  44635. }
  44636. private function getInputOptionDocument(InputOption $option)
  44637. {
  44638. $dom = new \DOMDocument('1.0', 'UTF-8');
  44639. $dom->appendChild($objectXML = $dom->createElement('option'));
  44640. $objectXML->setAttribute('name', '--'.$option->getName());
  44641. $pos = strpos($option->getShortcut(), '|');
  44642. if (false !== $pos) {
  44643. $objectXML->setAttribute('shortcut', '-'.substr($option->getShortcut(), 0, $pos));
  44644. $objectXML->setAttribute('shortcuts', '-'.str_replace('|', '|-', $option->getShortcut()));
  44645. } else {
  44646. $objectXML->setAttribute('shortcut', $option->getShortcut() ? '-'.$option->getShortcut() : '');
  44647. }
  44648. $objectXML->setAttribute('accept_value', $option->acceptValue() ? 1 : 0);
  44649. $objectXML->setAttribute('is_value_required', $option->isValueRequired() ? 1 : 0);
  44650. $objectXML->setAttribute('is_multiple', $option->isArray() ? 1 : 0);
  44651. $objectXML->appendChild($descriptionXML = $dom->createElement('description'));
  44652. $descriptionXML->appendChild($dom->createTextNode($option->getDescription()));
  44653. if ($option->acceptValue()) {
  44654. $defaults = \is_array($option->getDefault()) ? $option->getDefault() : (\is_bool($option->getDefault()) ? [var_export($option->getDefault(), true)] : ($option->getDefault() ? [$option->getDefault()] : []));
  44655. $objectXML->appendChild($defaultsXML = $dom->createElement('defaults'));
  44656. if (!empty($defaults)) {
  44657. foreach ($defaults as $default) {
  44658. $defaultsXML->appendChild($defaultXML = $dom->createElement('default'));
  44659. $defaultXML->appendChild($dom->createTextNode($default));
  44660. }
  44661. }
  44662. }
  44663. return $dom;
  44664. }
  44665. }
  44666. <?php
  44667. namespace Symfony\Component\Console\Command;
  44668. use Symfony\Component\Console\Helper\DescriptorHelper;
  44669. use Symfony\Component\Console\Input\InputArgument;
  44670. use Symfony\Component\Console\Input\InputInterface;
  44671. use Symfony\Component\Console\Input\InputOption;
  44672. use Symfony\Component\Console\Output\OutputInterface;
  44673. class HelpCommand extends Command
  44674. {
  44675. private $command;
  44676. protected function configure()
  44677. {
  44678. $this->ignoreValidationErrors();
  44679. $this
  44680. ->setName('help')
  44681. ->setDefinition([
  44682. new InputArgument('command_name', InputArgument::OPTIONAL, 'The command name', 'help'),
  44683. new InputOption('format', null, InputOption::VALUE_REQUIRED, 'The output format (txt, xml, json, or md)', 'txt'),
  44684. new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw command help'),
  44685. ])
  44686. ->setDescription('Displays help for a command')
  44687. ->setHelp(<<<'EOF'
  44688. The <info>%command.name%</info> command displays help for a given command:
  44689. <info>php %command.full_name% list</info>
  44690. You can also output the help in other formats by using the <comment>--format</comment> option:
  44691. <info>php %command.full_name% --format=xml list</info>
  44692. To display the list of available commands, please use the <info>list</info> command.
  44693. EOF
  44694. )
  44695. ;
  44696. }
  44697. public function setCommand(Command $command)
  44698. {
  44699. $this->command = $command;
  44700. }
  44701. protected function execute(InputInterface $input, OutputInterface $output)
  44702. {
  44703. if (null === $this->command) {
  44704. $this->command = $this->getApplication()->find($input->getArgument('command_name'));
  44705. }
  44706. $helper = new DescriptorHelper();
  44707. $helper->describe($output, $this->command, [
  44708. 'format' => $input->getOption('format'),
  44709. 'raw_text' => $input->getOption('raw'),
  44710. ]);
  44711. $this->command = null;
  44712. }
  44713. }
  44714. <?php
  44715. namespace Symfony\Component\Console\Command;
  44716. use Symfony\Component\Console\Helper\DescriptorHelper;
  44717. use Symfony\Component\Console\Input\InputArgument;
  44718. use Symfony\Component\Console\Input\InputDefinition;
  44719. use Symfony\Component\Console\Input\InputInterface;
  44720. use Symfony\Component\Console\Input\InputOption;
  44721. use Symfony\Component\Console\Output\OutputInterface;
  44722. class ListCommand extends Command
  44723. {
  44724. protected function configure()
  44725. {
  44726. $this
  44727. ->setName('list')
  44728. ->setDefinition($this->createDefinition())
  44729. ->setDescription('Lists commands')
  44730. ->setHelp(<<<'EOF'
  44731. The <info>%command.name%</info> command lists all commands:
  44732. <info>php %command.full_name%</info>
  44733. You can also display the commands for a specific namespace:
  44734. <info>php %command.full_name% test</info>
  44735. You can also output the information in other formats by using the <comment>--format</comment> option:
  44736. <info>php %command.full_name% --format=xml</info>
  44737. It's also possible to get raw list of commands (useful for embedding command runner):
  44738. <info>php %command.full_name% --raw</info>
  44739. EOF
  44740. )
  44741. ;
  44742. }
  44743. public function getNativeDefinition()
  44744. {
  44745. return $this->createDefinition();
  44746. }
  44747. protected function execute(InputInterface $input, OutputInterface $output)
  44748. {
  44749. $helper = new DescriptorHelper();
  44750. $helper->describe($output, $this->getApplication(), [
  44751. 'format' => $input->getOption('format'),
  44752. 'raw_text' => $input->getOption('raw'),
  44753. 'namespace' => $input->getArgument('namespace'),
  44754. ]);
  44755. }
  44756. private function createDefinition()
  44757. {
  44758. return new InputDefinition([
  44759. new InputArgument('namespace', InputArgument::OPTIONAL, 'The namespace name'),
  44760. new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw command list'),
  44761. new InputOption('format', null, InputOption::VALUE_REQUIRED, 'The output format (txt, xml, json, or md)', 'txt'),
  44762. ]);
  44763. }
  44764. }
  44765. <?php
  44766. namespace Symfony\Component\Console\Command;
  44767. use Symfony\Component\Console\Application;
  44768. use Symfony\Component\Console\Exception\ExceptionInterface;
  44769. use Symfony\Component\Console\Exception\InvalidArgumentException;
  44770. use Symfony\Component\Console\Exception\LogicException;
  44771. use Symfony\Component\Console\Helper\HelperSet;
  44772. use Symfony\Component\Console\Input\InputArgument;
  44773. use Symfony\Component\Console\Input\InputDefinition;
  44774. use Symfony\Component\Console\Input\InputInterface;
  44775. use Symfony\Component\Console\Input\InputOption;
  44776. use Symfony\Component\Console\Output\OutputInterface;
  44777. class Command
  44778. {
  44779. protected static $defaultName;
  44780. private $application;
  44781. private $name;
  44782. private $processTitle;
  44783. private $aliases = [];
  44784. private $definition;
  44785. private $hidden = false;
  44786. private $help = '';
  44787. private $description = '';
  44788. private $ignoreValidationErrors = false;
  44789. private $applicationDefinitionMerged = false;
  44790. private $applicationDefinitionMergedWithArgs = false;
  44791. private $code;
  44792. private $synopsis = [];
  44793. private $usages = [];
  44794. private $helperSet;
  44795. public static function getDefaultName()
  44796. {
  44797. $class = static::class;
  44798. $r = new \ReflectionProperty($class, 'defaultName');
  44799. return $class === $r->class ? static::$defaultName : null;
  44800. }
  44801. public function __construct($name = null)
  44802. {
  44803. $this->definition = new InputDefinition();
  44804. if (null !== $name || null !== $name = static::getDefaultName()) {
  44805. $this->setName($name);
  44806. }
  44807. $this->configure();
  44808. }
  44809. public function ignoreValidationErrors()
  44810. {
  44811. $this->ignoreValidationErrors = true;
  44812. }
  44813. public function setApplication(Application $application = null)
  44814. {
  44815. $this->application = $application;
  44816. if ($application) {
  44817. $this->setHelperSet($application->getHelperSet());
  44818. } else {
  44819. $this->helperSet = null;
  44820. }
  44821. }
  44822. public function setHelperSet(HelperSet $helperSet)
  44823. {
  44824. $this->helperSet = $helperSet;
  44825. }
  44826. public function getHelperSet()
  44827. {
  44828. return $this->helperSet;
  44829. }
  44830. public function getApplication()
  44831. {
  44832. return $this->application;
  44833. }
  44834. public function isEnabled()
  44835. {
  44836. return true;
  44837. }
  44838. protected function configure()
  44839. {
  44840. }
  44841. protected function execute(InputInterface $input, OutputInterface $output)
  44842. {
  44843. throw new LogicException('You must override the execute() method in the concrete command class.');
  44844. }
  44845. protected function interact(InputInterface $input, OutputInterface $output)
  44846. {
  44847. }
  44848. protected function initialize(InputInterface $input, OutputInterface $output)
  44849. {
  44850. }
  44851. public function run(InputInterface $input, OutputInterface $output)
  44852. {
  44853. $this->getSynopsis(true);
  44854. $this->getSynopsis(false);
  44855. $this->mergeApplicationDefinition();
  44856. try {
  44857. $input->bind($this->definition);
  44858. } catch (ExceptionInterface $e) {
  44859. if (!$this->ignoreValidationErrors) {
  44860. throw $e;
  44861. }
  44862. }
  44863. $this->initialize($input, $output);
  44864. if (null !== $this->processTitle) {
  44865. if (\function_exists('cli_set_process_title')) {
  44866. if (!@cli_set_process_title($this->processTitle)) {
  44867. if ('Darwin' === PHP_OS) {
  44868. $output->writeln('<comment>Running "cli_set_process_title" as an unprivileged user is not supported on MacOS.</comment>', OutputInterface::VERBOSITY_VERY_VERBOSE);
  44869. } else {
  44870. cli_set_process_title($this->processTitle);
  44871. }
  44872. }
  44873. } elseif (\function_exists('setproctitle')) {
  44874. setproctitle($this->processTitle);
  44875. } elseif (OutputInterface::VERBOSITY_VERY_VERBOSE === $output->getVerbosity()) {
  44876. $output->writeln('<comment>Install the proctitle PECL to be able to change the process title.</comment>');
  44877. }
  44878. }
  44879. if ($input->isInteractive()) {
  44880. $this->interact($input, $output);
  44881. }
  44882. if ($input->hasArgument('command') && null === $input->getArgument('command')) {
  44883. $input->setArgument('command', $this->getName());
  44884. }
  44885. $input->validate();
  44886. if ($this->code) {
  44887. $statusCode = \call_user_func($this->code, $input, $output);
  44888. } else {
  44889. $statusCode = $this->execute($input, $output);
  44890. }
  44891. return is_numeric($statusCode) ? (int) $statusCode : 0;
  44892. }
  44893. public function setCode(callable $code)
  44894. {
  44895. if ($code instanceof \Closure) {
  44896. $r = new \ReflectionFunction($code);
  44897. if (null === $r->getClosureThis()) {
  44898. if (\PHP_VERSION_ID < 70000) {
  44899. $code = @\Closure::bind($code, $this);
  44900. } else {
  44901. $code = \Closure::bind($code, $this);
  44902. }
  44903. }
  44904. }
  44905. $this->code = $code;
  44906. return $this;
  44907. }
  44908. public function mergeApplicationDefinition($mergeArgs = true)
  44909. {
  44910. if (null === $this->application || (true === $this->applicationDefinitionMerged && ($this->applicationDefinitionMergedWithArgs || !$mergeArgs))) {
  44911. return;
  44912. }
  44913. $this->definition->addOptions($this->application->getDefinition()->getOptions());
  44914. $this->applicationDefinitionMerged = true;
  44915. if ($mergeArgs) {
  44916. $currentArguments = $this->definition->getArguments();
  44917. $this->definition->setArguments($this->application->getDefinition()->getArguments());
  44918. $this->definition->addArguments($currentArguments);
  44919. $this->applicationDefinitionMergedWithArgs = true;
  44920. }
  44921. }
  44922. public function setDefinition($definition)
  44923. {
  44924. if ($definition instanceof InputDefinition) {
  44925. $this->definition = $definition;
  44926. } else {
  44927. $this->definition->setDefinition($definition);
  44928. }
  44929. $this->applicationDefinitionMerged = false;
  44930. return $this;
  44931. }
  44932. public function getDefinition()
  44933. {
  44934. if (null === $this->definition) {
  44935. throw new LogicException(sprintf('Command class "%s" is not correctly initialized. You probably forgot to call the parent constructor.', static::class));
  44936. }
  44937. return $this->definition;
  44938. }
  44939. public function getNativeDefinition()
  44940. {
  44941. return $this->getDefinition();
  44942. }
  44943. public function addArgument($name, $mode = null, $description = '', $default = null)
  44944. {
  44945. $this->definition->addArgument(new InputArgument($name, $mode, $description, $default));
  44946. return $this;
  44947. }
  44948. public function addOption($name, $shortcut = null, $mode = null, $description = '', $default = null)
  44949. {
  44950. $this->definition->addOption(new InputOption($name, $shortcut, $mode, $description, $default));
  44951. return $this;
  44952. }
  44953. public function setName($name)
  44954. {
  44955. $this->validateName($name);
  44956. $this->name = $name;
  44957. return $this;
  44958. }
  44959. public function setProcessTitle($title)
  44960. {
  44961. $this->processTitle = $title;
  44962. return $this;
  44963. }
  44964. public function getName()
  44965. {
  44966. return $this->name;
  44967. }
  44968. public function setHidden($hidden)
  44969. {
  44970. $this->hidden = (bool) $hidden;
  44971. return $this;
  44972. }
  44973. public function isHidden()
  44974. {
  44975. return $this->hidden;
  44976. }
  44977. public function setDescription($description)
  44978. {
  44979. $this->description = $description;
  44980. return $this;
  44981. }
  44982. public function getDescription()
  44983. {
  44984. return $this->description;
  44985. }
  44986. public function setHelp($help)
  44987. {
  44988. $this->help = $help;
  44989. return $this;
  44990. }
  44991. public function getHelp()
  44992. {
  44993. return $this->help;
  44994. }
  44995. public function getProcessedHelp()
  44996. {
  44997. $name = $this->name;
  44998. $isSingleCommand = $this->application && $this->application->isSingleCommand();
  44999. $placeholders = [
  45000. '%command.name%',
  45001. '%command.full_name%',
  45002. ];
  45003. $replacements = [
  45004. $name,
  45005. $isSingleCommand ? $_SERVER['PHP_SELF'] : $_SERVER['PHP_SELF'].' '.$name,
  45006. ];
  45007. return str_replace($placeholders, $replacements, $this->getHelp() ?: $this->getDescription());
  45008. }
  45009. public function setAliases($aliases)
  45010. {
  45011. if (!\is_array($aliases) && !$aliases instanceof \Traversable) {
  45012. throw new InvalidArgumentException('$aliases must be an array or an instance of \Traversable.');
  45013. }
  45014. foreach ($aliases as $alias) {
  45015. $this->validateName($alias);
  45016. }
  45017. $this->aliases = $aliases;
  45018. return $this;
  45019. }
  45020. public function getAliases()
  45021. {
  45022. return $this->aliases;
  45023. }
  45024. public function getSynopsis($short = false)
  45025. {
  45026. $key = $short ? 'short' : 'long';
  45027. if (!isset($this->synopsis[$key])) {
  45028. $this->synopsis[$key] = trim(sprintf('%s %s', $this->name, $this->definition->getSynopsis($short)));
  45029. }
  45030. return $this->synopsis[$key];
  45031. }
  45032. public function addUsage($usage)
  45033. {
  45034. if (0 !== strpos($usage, $this->name)) {
  45035. $usage = sprintf('%s %s', $this->name, $usage);
  45036. }
  45037. $this->usages[] = $usage;
  45038. return $this;
  45039. }
  45040. public function getUsages()
  45041. {
  45042. return $this->usages;
  45043. }
  45044. public function getHelper($name)
  45045. {
  45046. if (null === $this->helperSet) {
  45047. 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));
  45048. }
  45049. return $this->helperSet->get($name);
  45050. }
  45051. private function validateName($name)
  45052. {
  45053. if (!preg_match('/^[^\:]++(\:[^\:]++)*$/', $name)) {
  45054. throw new InvalidArgumentException(sprintf('Command name "%s" is invalid.', $name));
  45055. }
  45056. }
  45057. }
  45058. <?php
  45059. namespace Symfony\Component\Console\Command;
  45060. use Symfony\Component\Console\Exception\LogicException;
  45061. use Symfony\Component\Console\Exception\RuntimeException;
  45062. use Symfony\Component\Lock\Factory;
  45063. use Symfony\Component\Lock\Lock;
  45064. use Symfony\Component\Lock\Store\FlockStore;
  45065. use Symfony\Component\Lock\Store\SemaphoreStore;
  45066. trait LockableTrait
  45067. {
  45068. private $lock;
  45069. private function lock($name = null, $blocking = false)
  45070. {
  45071. if (!class_exists(SemaphoreStore::class)) {
  45072. throw new RuntimeException('To enable the locking feature you must install the symfony/lock component.');
  45073. }
  45074. if (null !== $this->lock) {
  45075. throw new LogicException('A lock is already in place.');
  45076. }
  45077. if (SemaphoreStore::isSupported($blocking)) {
  45078. $store = new SemaphoreStore();
  45079. } else {
  45080. $store = new FlockStore();
  45081. }
  45082. $this->lock = (new Factory($store))->createLock($name ?: $this->getName());
  45083. if (!$this->lock->acquire($blocking)) {
  45084. $this->lock = null;
  45085. return false;
  45086. }
  45087. return true;
  45088. }
  45089. private function release()
  45090. {
  45091. if ($this->lock) {
  45092. $this->lock->release();
  45093. $this->lock = null;
  45094. }
  45095. }
  45096. }
  45097. <?php
  45098. namespace Symfony\Component\Console\Tester;
  45099. use Symfony\Component\Console\Command\Command;
  45100. use Symfony\Component\Console\Input\ArrayInput;
  45101. use Symfony\Component\Console\Input\InputInterface;
  45102. use Symfony\Component\Console\Output\OutputInterface;
  45103. use Symfony\Component\Console\Output\StreamOutput;
  45104. /**
  45105. @gmail
  45106. */
  45107. class CommandTester
  45108. {
  45109. private $command;
  45110. private $input;
  45111. private $output;
  45112. private $inputs = [];
  45113. private $statusCode;
  45114. public function __construct(Command $command)
  45115. {
  45116. $this->command = $command;
  45117. }
  45118. public function execute(array $input, array $options = [])
  45119. {
  45120. if (!isset($input['command'])
  45121. && (null !== $application = $this->command->getApplication())
  45122. && $application->getDefinition()->hasArgument('command')
  45123. ) {
  45124. $input = array_merge(['command' => $this->command->getName()], $input);
  45125. }
  45126. $this->input = new ArrayInput($input);
  45127. $this->input->setStream(self::createStream($this->inputs));
  45128. if (isset($options['interactive'])) {
  45129. $this->input->setInteractive($options['interactive']);
  45130. }
  45131. $this->output = new StreamOutput(fopen('php://memory', 'w', false));
  45132. $this->output->setDecorated(isset($options['decorated']) ? $options['decorated'] : false);
  45133. if (isset($options['verbosity'])) {
  45134. $this->output->setVerbosity($options['verbosity']);
  45135. }
  45136. return $this->statusCode = $this->command->run($this->input, $this->output);
  45137. }
  45138. public function getDisplay($normalize = false)
  45139. {
  45140. if (null === $this->output) {
  45141. throw new \RuntimeException('Output not initialized, did you execute the command before requesting the display?');
  45142. }
  45143. rewind($this->output->getStream());
  45144. $display = stream_get_contents($this->output->getStream());
  45145. if ($normalize) {
  45146. $display = str_replace(PHP_EOL, "\n", $display);
  45147. }
  45148. return $display;
  45149. }
  45150. public function getInput()
  45151. {
  45152. return $this->input;
  45153. }
  45154. public function getOutput()
  45155. {
  45156. return $this->output;
  45157. }
  45158. public function getStatusCode()
  45159. {
  45160. return $this->statusCode;
  45161. }
  45162. public function setInputs(array $inputs)
  45163. {
  45164. $this->inputs = $inputs;
  45165. return $this;
  45166. }
  45167. private static function createStream(array $inputs)
  45168. {
  45169. $stream = fopen('php://memory', 'r+', false);
  45170. foreach ($inputs as $input) {
  45171. fwrite($stream, $input.PHP_EOL);
  45172. }
  45173. rewind($stream);
  45174. return $stream;
  45175. }
  45176. }
  45177. <?php
  45178. namespace Symfony\Component\Console\Tester;
  45179. use Symfony\Component\Console\Application;
  45180. use Symfony\Component\Console\Input\ArrayInput;
  45181. use Symfony\Component\Console\Input\InputInterface;
  45182. use Symfony\Component\Console\Output\ConsoleOutput;
  45183. use Symfony\Component\Console\Output\OutputInterface;
  45184. use Symfony\Component\Console\Output\StreamOutput;
  45185. class ApplicationTester
  45186. {
  45187. private $application;
  45188. private $input;
  45189. private $statusCode;
  45190. private $output;
  45191. private $captureStreamsIndependently = false;
  45192. public function __construct(Application $application)
  45193. {
  45194. $this->application = $application;
  45195. }
  45196. public function run(array $input, $options = [])
  45197. {
  45198. $this->input = new ArrayInput($input);
  45199. if (isset($options['interactive'])) {
  45200. $this->input->setInteractive($options['interactive']);
  45201. }
  45202. $this->captureStreamsIndependently = \array_key_exists('capture_stderr_separately', $options) && $options['capture_stderr_separately'];
  45203. if (!$this->captureStreamsIndependently) {
  45204. $this->output = new StreamOutput(fopen('php://memory', 'w', false));
  45205. if (isset($options['decorated'])) {
  45206. $this->output->setDecorated($options['decorated']);
  45207. }
  45208. if (isset($options['verbosity'])) {
  45209. $this->output->setVerbosity($options['verbosity']);
  45210. }
  45211. } else {
  45212. $this->output = new ConsoleOutput(
  45213. isset($options['verbosity']) ? $options['verbosity'] : ConsoleOutput::VERBOSITY_NORMAL,
  45214. isset($options['decorated']) ? $options['decorated'] : null
  45215. );
  45216. $errorOutput = new StreamOutput(fopen('php://memory', 'w', false));
  45217. $errorOutput->setFormatter($this->output->getFormatter());
  45218. $errorOutput->setVerbosity($this->output->getVerbosity());
  45219. $errorOutput->setDecorated($this->output->isDecorated());
  45220. $reflectedOutput = new \ReflectionObject($this->output);
  45221. $strErrProperty = $reflectedOutput->getProperty('stderr');
  45222. $strErrProperty->setAccessible(true);
  45223. $strErrProperty->setValue($this->output, $errorOutput);
  45224. $reflectedParent = $reflectedOutput->getParentClass();
  45225. $streamProperty = $reflectedParent->getProperty('stream');
  45226. $streamProperty->setAccessible(true);
  45227. $streamProperty->setValue($this->output, fopen('php://memory', 'w', false));
  45228. }
  45229. return $this->statusCode = $this->application->run($this->input, $this->output);
  45230. }
  45231. public function getDisplay($normalize = false)
  45232. {
  45233. rewind($this->output->getStream());
  45234. $display = stream_get_contents($this->output->getStream());
  45235. if ($normalize) {
  45236. $display = str_replace(PHP_EOL, "\n", $display);
  45237. }
  45238. return $display;
  45239. }
  45240. public function getErrorOutput($normalize = false)
  45241. {
  45242. if (!$this->captureStreamsIndependently) {
  45243. throw new \LogicException('The error output is not available when the tester is run without "capture_stderr_separately" option set.');
  45244. }
  45245. rewind($this->output->getErrorOutput()->getStream());
  45246. $display = stream_get_contents($this->output->getErrorOutput()->getStream());
  45247. if ($normalize) {
  45248. $display = str_replace(PHP_EOL, "\n", $display);
  45249. }
  45250. return $display;
  45251. }
  45252. public function getInput()
  45253. {
  45254. return $this->input;
  45255. }
  45256. public function getOutput()
  45257. {
  45258. return $this->output;
  45259. }
  45260. public function getStatusCode()
  45261. {
  45262. return $this->statusCode;
  45263. }
  45264. }
  45265. <?php
  45266. namespace Symfony\Component\Console\Helper;
  45267. class DebugFormatterHelper extends Helper
  45268. {
  45269. private $colors = ['black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white', 'default'];
  45270. private $started = [];
  45271. private $count = -1;
  45272. public function start($id, $message, $prefix = 'RUN')
  45273. {
  45274. $this->started[$id] = ['border' => ++$this->count % \count($this->colors)];
  45275. return sprintf("%s<bg=blue;fg=white> %s </> <fg=blue>%s</>\n", $this->getBorder($id), $prefix, $message);
  45276. }
  45277. public function progress($id, $buffer, $error = false, $prefix = 'OUT', $errorPrefix = 'ERR')
  45278. {
  45279. $message = '';
  45280. if ($error) {
  45281. if (isset($this->started[$id]['out'])) {
  45282. $message .= "\n";
  45283. unset($this->started[$id]['out']);
  45284. }
  45285. if (!isset($this->started[$id]['err'])) {
  45286. $message .= sprintf('%s<bg=red;fg=white> %s </> ', $this->getBorder($id), $errorPrefix);
  45287. $this->started[$id]['err'] = true;
  45288. }
  45289. $message .= str_replace("\n", sprintf("\n%s<bg=red;fg=white> %s </> ", $this->getBorder($id), $errorPrefix), $buffer);
  45290. } else {
  45291. if (isset($this->started[$id]['err'])) {
  45292. $message .= "\n";
  45293. unset($this->started[$id]['err']);
  45294. }
  45295. if (!isset($this->started[$id]['out'])) {
  45296. $message .= sprintf('%s<bg=green;fg=white> %s </> ', $this->getBorder($id), $prefix);
  45297. $this->started[$id]['out'] = true;
  45298. }
  45299. $message .= str_replace("\n", sprintf("\n%s<bg=green;fg=white> %s </> ", $this->getBorder($id), $prefix), $buffer);
  45300. }
  45301. return $message;
  45302. }
  45303. public function stop($id, $message, $successful, $prefix = 'RES')
  45304. {
  45305. $trailingEOL = isset($this->started[$id]['out']) || isset($this->started[$id]['err']) ? "\n" : '';
  45306. if ($successful) {
  45307. return sprintf("%s%s<bg=green;fg=white> %s </> <fg=green>%s</>\n", $trailingEOL, $this->getBorder($id), $prefix, $message);
  45308. }
  45309. $message = sprintf("%s%s<bg=red;fg=white> %s </> <fg=red>%s</>\n", $trailingEOL, $this->getBorder($id), $prefix, $message);
  45310. unset($this->started[$id]['out'], $this->started[$id]['err']);
  45311. return $message;
  45312. }
  45313. private function getBorder($id)
  45314. {
  45315. return sprintf('<bg=%s> </>', $this->colors[$this->started[$id]['border']]);
  45316. }
  45317. public function getName()
  45318. {
  45319. return 'debug_formatter';
  45320. }
  45321. }
  45322. <?php
  45323. namespace Symfony\Component\Console\Helper;
  45324. interface HelperInterface
  45325. {
  45326. public function setHelperSet(HelperSet $helperSet = null);
  45327. public function getHelperSet();
  45328. public function getName();
  45329. }
  45330. <?php
  45331. namespace Symfony\Component\Console\Helper;
  45332. use Symfony\Component\Console\Output\ConsoleOutputInterface;
  45333. use Symfony\Component\Console\Output\OutputInterface;
  45334. use Symfony\Component\Process\Exception\ProcessFailedException;
  45335. use Symfony\Component\Process\Process;
  45336. class ProcessHelper extends Helper
  45337. {
  45338. public function run(OutputInterface $output, $cmd, $error = null, callable $callback = null, $verbosity = OutputInterface::VERBOSITY_VERY_VERBOSE)
  45339. {
  45340. if (!class_exists(Process::class)) {
  45341. throw new \LogicException('The ProcessHelper cannot be run as the Process component is not installed. Try running "compose require symfony/process".');
  45342. }
  45343. if ($output instanceof ConsoleOutputInterface) {
  45344. $output = $output->getErrorOutput();
  45345. }
  45346. $formatter = $this->getHelperSet()->get('debug_formatter');
  45347. if ($cmd instanceof Process) {
  45348. $process = $cmd;
  45349. } else {
  45350. $process = new Process($cmd);
  45351. }
  45352. if ($verbosity <= $output->getVerbosity()) {
  45353. $output->write($formatter->start(spl_object_hash($process), $this->escapeString($process->getCommandLine())));
  45354. }
  45355. if ($output->isDebug()) {
  45356. $callback = $this->wrapCallback($output, $process, $callback);
  45357. }
  45358. $process->run($callback);
  45359. if ($verbosity <= $output->getVerbosity()) {
  45360. $message = $process->isSuccessful() ? 'Command ran successfully' : sprintf('%s Command did not run successfully', $process->getExitCode());
  45361. $output->write($formatter->stop(spl_object_hash($process), $message, $process->isSuccessful()));
  45362. }
  45363. if (!$process->isSuccessful() && null !== $error) {
  45364. $output->writeln(sprintf('<error>%s</error>', $this->escapeString($error)));
  45365. }
  45366. return $process;
  45367. }
  45368. public function mustRun(OutputInterface $output, $cmd, $error = null, callable $callback = null)
  45369. {
  45370. $process = $this->run($output, $cmd, $error, $callback);
  45371. if (!$process->isSuccessful()) {
  45372. throw new ProcessFailedException($process);
  45373. }
  45374. return $process;
  45375. }
  45376. public function wrapCallback(OutputInterface $output, Process $process, callable $callback = null)
  45377. {
  45378. if ($output instanceof ConsoleOutputInterface) {
  45379. $output = $output->getErrorOutput();
  45380. }
  45381. $formatter = $this->getHelperSet()->get('debug_formatter');
  45382. return function ($type, $buffer) use ($output, $process, $callback, $formatter) {
  45383. $output->write($formatter->progress(spl_object_hash($process), $this->escapeString($buffer), Process::ERR === $type));
  45384. if (null !== $callback) {
  45385. \call_user_func($callback, $type, $buffer);
  45386. }
  45387. };
  45388. }
  45389. private function escapeString($str)
  45390. {
  45391. return str_replace('<', '\\<', $str);
  45392. }
  45393. public function getName()
  45394. {
  45395. return 'process';
  45396. }
  45397. }
  45398. <?php
  45399. namespace Symfony\Component\Console\Helper;
  45400. use Symfony\Component\Console\Input\InputAwareInterface;
  45401. use Symfony\Component\Console\Input\InputInterface;
  45402. abstract class InputAwareHelper extends Helper implements InputAwareInterface
  45403. {
  45404. protected $input;
  45405. public function setInput(InputInterface $input)
  45406. {
  45407. $this->input = $input;
  45408. }
  45409. }
  45410. <?php
  45411. namespace Symfony\Component\Console\Helper;
  45412. use Symfony\Component\Console\Formatter\OutputFormatterInterface;
  45413. abstract class Helper implements HelperInterface
  45414. {
  45415. protected $helperSet = null;
  45416. public function setHelperSet(HelperSet $helperSet = null)
  45417. {
  45418. $this->helperSet = $helperSet;
  45419. }
  45420. public function getHelperSet()
  45421. {
  45422. return $this->helperSet;
  45423. }
  45424. public static function strlen($string)
  45425. {
  45426. if (false === $encoding = mb_detect_encoding($string, null, true)) {
  45427. return \strlen($string);
  45428. }
  45429. return mb_strwidth($string, $encoding);
  45430. }
  45431. public static function substr($string, $from, $length = null)
  45432. {
  45433. if (false === $encoding = mb_detect_encoding($string, null, true)) {
  45434. return substr($string, $from, $length);
  45435. }
  45436. return mb_substr($string, $from, $length, $encoding);
  45437. }
  45438. public static function formatTime($secs)
  45439. {
  45440. static $timeFormats = [
  45441. [0, '< 1 sec'],
  45442. [1, '1 sec'],
  45443. [2, 'secs', 1],
  45444. [60, '1 min'],
  45445. [120, 'mins', 60],
  45446. [3600, '1 hr'],
  45447. [7200, 'hrs', 3600],
  45448. [86400, '1 day'],
  45449. [172800, 'days', 86400],
  45450. ];
  45451. foreach ($timeFormats as $index => $format) {
  45452. if ($secs >= $format[0]) {
  45453. if ((isset($timeFormats[$index + 1]) && $secs < $timeFormats[$index + 1][0])
  45454. || $index == \count($timeFormats) - 1
  45455. ) {
  45456. if (2 == \count($format)) {
  45457. return $format[1];
  45458. }
  45459. return floor($secs / $format[2]).' '.$format[1];
  45460. }
  45461. }
  45462. }
  45463. }
  45464. public static function formatMemory($memory)
  45465. {
  45466. if ($memory >= 1024 * 1024 * 1024) {
  45467. return sprintf('%.1f GiB', $memory / 1024 / 1024 / 1024);
  45468. }
  45469. if ($memory >= 1024 * 1024) {
  45470. return sprintf('%.1f MiB', $memory / 1024 / 1024);
  45471. }
  45472. if ($memory >= 1024) {
  45473. return sprintf('%d KiB', $memory / 1024);
  45474. }
  45475. return sprintf('%d B', $memory);
  45476. }
  45477. public static function strlenWithoutDecoration(OutputFormatterInterface $formatter, $string)
  45478. {
  45479. return self::strlen(self::removeDecoration($formatter, $string));
  45480. }
  45481. public static function removeDecoration(OutputFormatterInterface $formatter, $string)
  45482. {
  45483. $isDecorated = $formatter->isDecorated();
  45484. $formatter->setDecorated(false);
  45485. $string = $formatter->format($string);
  45486. $string = preg_replace("/\033\[[^m]*m/", '', $string);
  45487. $formatter->setDecorated($isDecorated);
  45488. return $string;
  45489. }
  45490. }
  45491. <?php
  45492. namespace Symfony\Component\Console\Helper;
  45493. use Symfony\Component\Console\Exception\InvalidArgumentException;
  45494. use Symfony\Component\Console\Output\OutputInterface;
  45495. /**
  45496. @gmail
  45497. @gmail
  45498. @gmail
  45499. */
  45500. class Table
  45501. {
  45502. private $headers = [];
  45503. private $rows = [];
  45504. private $effectiveColumnWidths = [];
  45505. private $numberOfColumns;
  45506. private $output;
  45507. private $style;
  45508. private $columnStyles = [];
  45509. private $columnWidths = [];
  45510. private static $styles;
  45511. public function __construct(OutputInterface $output)
  45512. {
  45513. $this->output = $output;
  45514. if (!self::$styles) {
  45515. self::$styles = self::initStyles();
  45516. }
  45517. $this->setStyle('default');
  45518. }
  45519. public static function setStyleDefinition($name, TableStyle $style)
  45520. {
  45521. if (!self::$styles) {
  45522. self::$styles = self::initStyles();
  45523. }
  45524. self::$styles[$name] = $style;
  45525. }
  45526. public static function getStyleDefinition($name)
  45527. {
  45528. if (!self::$styles) {
  45529. self::$styles = self::initStyles();
  45530. }
  45531. if (isset(self::$styles[$name])) {
  45532. return self::$styles[$name];
  45533. }
  45534. throw new InvalidArgumentException(sprintf('Style "%s" is not defined.', $name));
  45535. }
  45536. public function setStyle($name)
  45537. {
  45538. $this->style = $this->resolveStyle($name);
  45539. return $this;
  45540. }
  45541. public function getStyle()
  45542. {
  45543. return $this->style;
  45544. }
  45545. public function setColumnStyle($columnIndex, $name)
  45546. {
  45547. $columnIndex = (int) $columnIndex;
  45548. $this->columnStyles[$columnIndex] = $this->resolveStyle($name);
  45549. return $this;
  45550. }
  45551. public function getColumnStyle($columnIndex)
  45552. {
  45553. if (isset($this->columnStyles[$columnIndex])) {
  45554. return $this->columnStyles[$columnIndex];
  45555. }
  45556. return $this->getStyle();
  45557. }
  45558. public function setColumnWidth($columnIndex, $width)
  45559. {
  45560. $this->columnWidths[(int) $columnIndex] = (int) $width;
  45561. return $this;
  45562. }
  45563. public function setColumnWidths(array $widths)
  45564. {
  45565. $this->columnWidths = [];
  45566. foreach ($widths as $index => $width) {
  45567. $this->setColumnWidth($index, $width);
  45568. }
  45569. return $this;
  45570. }
  45571. public function setHeaders(array $headers)
  45572. {
  45573. $headers = array_values($headers);
  45574. if (!empty($headers) && !\is_array($headers[0])) {
  45575. $headers = [$headers];
  45576. }
  45577. $this->headers = $headers;
  45578. return $this;
  45579. }
  45580. public function setRows(array $rows)
  45581. {
  45582. $this->rows = [];
  45583. return $this->addRows($rows);
  45584. }
  45585. public function addRows(array $rows)
  45586. {
  45587. foreach ($rows as $row) {
  45588. $this->addRow($row);
  45589. }
  45590. return $this;
  45591. }
  45592. public function addRow($row)
  45593. {
  45594. if ($row instanceof TableSeparator) {
  45595. $this->rows[] = $row;
  45596. return $this;
  45597. }
  45598. if (!\is_array($row)) {
  45599. throw new InvalidArgumentException('A row must be an array or a TableSeparator instance.');
  45600. }
  45601. $this->rows[] = array_values($row);
  45602. return $this;
  45603. }
  45604. public function setRow($column, array $row)
  45605. {
  45606. $this->rows[$column] = $row;
  45607. return $this;
  45608. }
  45609. public function render()
  45610. {
  45611. $this->calculateNumberOfColumns();
  45612. $rows = $this->buildTableRows($this->rows);
  45613. $headers = $this->buildTableRows($this->headers);
  45614. $this->calculateColumnsWidth(array_merge($headers, $rows));
  45615. $this->renderRowSeparator();
  45616. if (!empty($headers)) {
  45617. foreach ($headers as $header) {
  45618. $this->renderRow($header, $this->style->getCellHeaderFormat());
  45619. $this->renderRowSeparator();
  45620. }
  45621. }
  45622. foreach ($rows as $row) {
  45623. if ($row instanceof TableSeparator) {
  45624. $this->renderRowSeparator();
  45625. } else {
  45626. $this->renderRow($row, $this->style->getCellRowFormat());
  45627. }
  45628. }
  45629. if (!empty($rows)) {
  45630. $this->renderRowSeparator();
  45631. }
  45632. $this->cleanup();
  45633. }
  45634. private function renderRowSeparator()
  45635. {
  45636. if (0 === $count = $this->numberOfColumns) {
  45637. return;
  45638. }
  45639. if (!$this->style->getHorizontalBorderChar() && !$this->style->getCrossingChar()) {
  45640. return;
  45641. }
  45642. $markup = $this->style->getCrossingChar();
  45643. for ($column = 0; $column < $count; ++$column) {
  45644. $markup .= str_repeat($this->style->getHorizontalBorderChar(), $this->effectiveColumnWidths[$column]).$this->style->getCrossingChar();
  45645. }
  45646. $this->output->writeln(sprintf($this->style->getBorderFormat(), $markup));
  45647. }
  45648. private function renderColumnSeparator()
  45649. {
  45650. return sprintf($this->style->getBorderFormat(), $this->style->getVerticalBorderChar());
  45651. }
  45652. private function renderRow(array $row, $cellFormat)
  45653. {
  45654. if (empty($row)) {
  45655. return;
  45656. }
  45657. $rowContent = $this->renderColumnSeparator();
  45658. foreach ($this->getRowColumns($row) as $column) {
  45659. $rowContent .= $this->renderCell($row, $column, $cellFormat);
  45660. $rowContent .= $this->renderColumnSeparator();
  45661. }
  45662. $this->output->writeln($rowContent);
  45663. }
  45664. private function renderCell(array $row, $column, $cellFormat)
  45665. {
  45666. $cell = isset($row[$column]) ? $row[$column] : '';
  45667. $width = $this->effectiveColumnWidths[$column];
  45668. if ($cell instanceof TableCell && $cell->getColspan() > 1) {
  45669. foreach (range($column + 1, $column + $cell->getColspan() - 1) as $nextColumn) {
  45670. $width += $this->getColumnSeparatorWidth() + $this->effectiveColumnWidths[$nextColumn];
  45671. }
  45672. }
  45673. if (false !== $encoding = mb_detect_encoding($cell, null, true)) {
  45674. $width += \strlen($cell) - mb_strwidth($cell, $encoding);
  45675. }
  45676. $style = $this->getColumnStyle($column);
  45677. if ($cell instanceof TableSeparator) {
  45678. return sprintf($style->getBorderFormat(), str_repeat($style->getHorizontalBorderChar(), $width));
  45679. }
  45680. $width += Helper::strlen($cell) - Helper::strlenWithoutDecoration($this->output->getFormatter(), $cell);
  45681. $content = sprintf($style->getCellRowContentFormat(), $cell);
  45682. return sprintf($cellFormat, str_pad($content, $width, $style->getPaddingChar(), $style->getPadType()));
  45683. }
  45684. private function calculateNumberOfColumns()
  45685. {
  45686. if (null !== $this->numberOfColumns) {
  45687. return;
  45688. }
  45689. $columns = [0];
  45690. foreach (array_merge($this->headers, $this->rows) as $row) {
  45691. if ($row instanceof TableSeparator) {
  45692. continue;
  45693. }
  45694. $columns[] = $this->getNumberOfColumns($row);
  45695. }
  45696. $this->numberOfColumns = max($columns);
  45697. }
  45698. private function buildTableRows($rows)
  45699. {
  45700. $unmergedRows = [];
  45701. for ($rowKey = 0; $rowKey < \count($rows); ++$rowKey) {
  45702. $rows = $this->fillNextRows($rows, $rowKey);
  45703. foreach ($rows[$rowKey] as $column => $cell) {
  45704. if (!strstr($cell, "\n")) {
  45705. continue;
  45706. }
  45707. $lines = explode("\n", str_replace("\n", "<fg=default;bg=default>\n</>", $cell));
  45708. foreach ($lines as $lineKey => $line) {
  45709. if ($cell instanceof TableCell) {
  45710. $line = new TableCell($line, ['colspan' => $cell->getColspan()]);
  45711. }
  45712. if (0 === $lineKey) {
  45713. $rows[$rowKey][$column] = $line;
  45714. } else {
  45715. $unmergedRows[$rowKey][$lineKey][$column] = $line;
  45716. }
  45717. }
  45718. }
  45719. }
  45720. $tableRows = [];
  45721. foreach ($rows as $rowKey => $row) {
  45722. $tableRows[] = $this->fillCells($row);
  45723. if (isset($unmergedRows[$rowKey])) {
  45724. $tableRows = array_merge($tableRows, $unmergedRows[$rowKey]);
  45725. }
  45726. }
  45727. return $tableRows;
  45728. }
  45729. private function fillNextRows(array $rows, $line)
  45730. {
  45731. $unmergedRows = [];
  45732. foreach ($rows[$line] as $column => $cell) {
  45733. if (null !== $cell && !$cell instanceof TableCell && !is_scalar($cell) && !(\is_object($cell) && method_exists($cell, '__toString'))) {
  45734. throw new InvalidArgumentException(sprintf('A cell must be a TableCell, a scalar or an object implementing "__toString()", "%s" given.', \gettype($cell)));
  45735. }
  45736. if ($cell instanceof TableCell && $cell->getRowspan() > 1) {
  45737. $nbLines = $cell->getRowspan() - 1;
  45738. $lines = [$cell];
  45739. if (strstr($cell, "\n")) {
  45740. $lines = explode("\n", str_replace("\n", "<fg=default;bg=default>\n</>", $cell));
  45741. $nbLines = \count($lines) > $nbLines ? substr_count($cell, "\n") : $nbLines;
  45742. $rows[$line][$column] = new TableCell($lines[0], ['colspan' => $cell->getColspan()]);
  45743. unset($lines[0]);
  45744. }
  45745. $unmergedRows = array_replace_recursive(array_fill($line + 1, $nbLines, []), $unmergedRows);
  45746. foreach ($unmergedRows as $unmergedRowKey => $unmergedRow) {
  45747. $value = isset($lines[$unmergedRowKey - $line]) ? $lines[$unmergedRowKey - $line] : '';
  45748. $unmergedRows[$unmergedRowKey][$column] = new TableCell($value, ['colspan' => $cell->getColspan()]);
  45749. if ($nbLines === $unmergedRowKey - $line) {
  45750. break;
  45751. }
  45752. }
  45753. }
  45754. }
  45755. foreach ($unmergedRows as $unmergedRowKey => $unmergedRow) {
  45756. if (isset($rows[$unmergedRowKey]) && \is_array($rows[$unmergedRowKey]) && ($this->getNumberOfColumns($rows[$unmergedRowKey]) + $this->getNumberOfColumns($unmergedRows[$unmergedRowKey]) <= $this->numberOfColumns)) {
  45757. foreach ($unmergedRow as $cellKey => $cell) {
  45758. array_splice($rows[$unmergedRowKey], $cellKey, 0, [$cell]);
  45759. }
  45760. } else {
  45761. $row = $this->copyRow($rows, $unmergedRowKey - 1);
  45762. foreach ($unmergedRow as $column => $cell) {
  45763. if (!empty($cell)) {
  45764. $row[$column] = $unmergedRow[$column];
  45765. }
  45766. }
  45767. array_splice($rows, $unmergedRowKey, 0, [$row]);
  45768. }
  45769. }
  45770. return $rows;
  45771. }
  45772. private function fillCells($row)
  45773. {
  45774. $newRow = [];
  45775. foreach ($row as $column => $cell) {
  45776. $newRow[] = $cell;
  45777. if ($cell instanceof TableCell && $cell->getColspan() > 1) {
  45778. foreach (range($column + 1, $column + $cell->getColspan() - 1) as $position) {
  45779. $newRow[] = '';
  45780. }
  45781. }
  45782. }
  45783. return $newRow ?: $row;
  45784. }
  45785. private function copyRow(array $rows, $line)
  45786. {
  45787. $row = $rows[$line];
  45788. foreach ($row as $cellKey => $cellValue) {
  45789. $row[$cellKey] = '';
  45790. if ($cellValue instanceof TableCell) {
  45791. $row[$cellKey] = new TableCell('', ['colspan' => $cellValue->getColspan()]);
  45792. }
  45793. }
  45794. return $row;
  45795. }
  45796. private function getNumberOfColumns(array $row)
  45797. {
  45798. $columns = \count($row);
  45799. foreach ($row as $column) {
  45800. $columns += $column instanceof TableCell ? ($column->getColspan() - 1) : 0;
  45801. }
  45802. return $columns;
  45803. }
  45804. private function getRowColumns(array $row)
  45805. {
  45806. $columns = range(0, $this->numberOfColumns - 1);
  45807. foreach ($row as $cellKey => $cell) {
  45808. if ($cell instanceof TableCell && $cell->getColspan() > 1) {
  45809. $columns = array_diff($columns, range($cellKey + 1, $cellKey + $cell->getColspan() - 1));
  45810. }
  45811. }
  45812. return $columns;
  45813. }
  45814. private function calculateColumnsWidth(array $rows)
  45815. {
  45816. for ($column = 0; $column < $this->numberOfColumns; ++$column) {
  45817. $lengths = [];
  45818. foreach ($rows as $row) {
  45819. if ($row instanceof TableSeparator) {
  45820. continue;
  45821. }
  45822. foreach ($row as $i => $cell) {
  45823. if ($cell instanceof TableCell) {
  45824. $textContent = Helper::removeDecoration($this->output->getFormatter(), $cell);
  45825. $textLength = Helper::strlen($textContent);
  45826. if ($textLength > 0) {
  45827. $contentColumns = str_split($textContent, ceil($textLength / $cell->getColspan()));
  45828. foreach ($contentColumns as $position => $content) {
  45829. $row[$i + $position] = $content;
  45830. }
  45831. }
  45832. }
  45833. }
  45834. $lengths[] = $this->getCellWidth($row, $column);
  45835. }
  45836. $this->effectiveColumnWidths[$column] = max($lengths) + Helper::strlen($this->style->getCellRowContentFormat()) - 2;
  45837. }
  45838. }
  45839. private function getColumnSeparatorWidth()
  45840. {
  45841. return Helper::strlen(sprintf($this->style->getBorderFormat(), $this->style->getVerticalBorderChar()));
  45842. }
  45843. private function getCellWidth(array $row, $column)
  45844. {
  45845. $cellWidth = 0;
  45846. if (isset($row[$column])) {
  45847. $cell = $row[$column];
  45848. $cellWidth = Helper::strlenWithoutDecoration($this->output->getFormatter(), $cell);
  45849. }
  45850. $columnWidth = isset($this->columnWidths[$column]) ? $this->columnWidths[$column] : 0;
  45851. return max($cellWidth, $columnWidth);
  45852. }
  45853. private function cleanup()
  45854. {
  45855. $this->effectiveColumnWidths = [];
  45856. $this->numberOfColumns = null;
  45857. }
  45858. private static function initStyles()
  45859. {
  45860. $borderless = new TableStyle();
  45861. $borderless
  45862. ->setHorizontalBorderChar('=')
  45863. ->setVerticalBorderChar(' ')
  45864. ->setCrossingChar(' ')
  45865. ;
  45866. $compact = new TableStyle();
  45867. $compact
  45868. ->setHorizontalBorderChar('')
  45869. ->setVerticalBorderChar(' ')
  45870. ->setCrossingChar('')
  45871. ->setCellRowContentFormat('%s')
  45872. ;
  45873. $styleGuide = new TableStyle();
  45874. $styleGuide
  45875. ->setHorizontalBorderChar('-')
  45876. ->setVerticalBorderChar(' ')
  45877. ->setCrossingChar(' ')
  45878. ->setCellHeaderFormat('%s')
  45879. ;
  45880. return [
  45881. 'default' => new TableStyle(),
  45882. 'borderless' => $borderless,
  45883. 'compact' => $compact,
  45884. 'symfony-style-guide' => $styleGuide,
  45885. ];
  45886. }
  45887. private function resolveStyle($name)
  45888. {
  45889. if ($name instanceof TableStyle) {
  45890. return $name;
  45891. }
  45892. if (isset(self::$styles[$name])) {
  45893. return self::$styles[$name];
  45894. }
  45895. throw new InvalidArgumentException(sprintf('Style "%s" is not defined.', $name));
  45896. }
  45897. }
  45898. <?php
  45899. namespace Symfony\Component\Console\Helper;
  45900. use Symfony\Component\Console\Descriptor\DescriptorInterface;
  45901. use Symfony\Component\Console\Descriptor\JsonDescriptor;
  45902. use Symfony\Component\Console\Descriptor\MarkdownDescriptor;
  45903. use Symfony\Component\Console\Descriptor\TextDescriptor;
  45904. use Symfony\Component\Console\Descriptor\XmlDescriptor;
  45905. use Symfony\Component\Console\Exception\InvalidArgumentException;
  45906. use Symfony\Component\Console\Output\OutputInterface;
  45907. class DescriptorHelper extends Helper
  45908. {
  45909. private $descriptors = [];
  45910. public function __construct()
  45911. {
  45912. $this
  45913. ->register('txt', new TextDescriptor())
  45914. ->register('xml', new XmlDescriptor())
  45915. ->register('json', new JsonDescriptor())
  45916. ->register('md', new MarkdownDescriptor())
  45917. ;
  45918. }
  45919. public function describe(OutputInterface $output, $object, array $options = [])
  45920. {
  45921. $options = array_merge([
  45922. 'raw_text' => false,
  45923. 'format' => 'txt',
  45924. ], $options);
  45925. if (!isset($this->descriptors[$options['format']])) {
  45926. throw new InvalidArgumentException(sprintf('Unsupported format "%s".', $options['format']));
  45927. }
  45928. $descriptor = $this->descriptors[$options['format']];
  45929. $descriptor->describe($output, $object, $options);
  45930. }
  45931. public function register($format, DescriptorInterface $descriptor)
  45932. {
  45933. $this->descriptors[$format] = $descriptor;
  45934. return $this;
  45935. }
  45936. public function getName()
  45937. {
  45938. return 'descriptor';
  45939. }
  45940. }
  45941. <?php
  45942. namespace Symfony\Component\Console\Helper;
  45943. use Symfony\Component\Console\Exception\LogicException;
  45944. use Symfony\Component\Console\Formatter\OutputFormatter;
  45945. use Symfony\Component\Console\Input\InputInterface;
  45946. use Symfony\Component\Console\Output\OutputInterface;
  45947. use Symfony\Component\Console\Question\ChoiceQuestion;
  45948. use Symfony\Component\Console\Question\ConfirmationQuestion;
  45949. use Symfony\Component\Console\Question\Question;
  45950. use Symfony\Component\Console\Style\SymfonyStyle;
  45951. class SymfonyQuestionHelper extends QuestionHelper
  45952. {
  45953. public function ask(InputInterface $input, OutputInterface $output, Question $question)
  45954. {
  45955. $validator = $question->getValidator();
  45956. $question->setValidator(function ($value) use ($validator) {
  45957. if (null !== $validator) {
  45958. $value = $validator($value);
  45959. } else {
  45960. if (!\is_array($value) && !\is_bool($value) && 0 === \strlen($value)) {
  45961. @trigger_error('The default question validator is deprecated since Symfony 3.3 and will not be used anymore in version 4.0. Set a custom question validator if needed.', E_USER_DEPRECATED);
  45962. throw new LogicException('A value is required.');
  45963. }
  45964. }
  45965. return $value;
  45966. });
  45967. return parent::ask($input, $output, $question);
  45968. }
  45969. protected function writePrompt(OutputInterface $output, Question $question)
  45970. {
  45971. $text = OutputFormatter::escapeTrailingBackslash($question->getQuestion());
  45972. $default = $question->getDefault();
  45973. switch (true) {
  45974. case null === $default:
  45975. $text = sprintf(' <info>%s</info>:', $text);
  45976. break;
  45977. case $question instanceof ConfirmationQuestion:
  45978. $text = sprintf(' <info>%s (yes/no)</info> [<comment>%s</comment>]:', $text, $default ? 'yes' : 'no');
  45979. break;
  45980. case $question instanceof ChoiceQuestion && $question->isMultiselect():
  45981. $choices = $question->getChoices();
  45982. $default = explode(',', $default);
  45983. foreach ($default as $key => $value) {
  45984. $default[$key] = $choices[trim($value)];
  45985. }
  45986. $text = sprintf(' <info>%s</info> [<comment>%s</comment>]:', $text, OutputFormatter::escape(implode(', ', $default)));
  45987. break;
  45988. case $question instanceof ChoiceQuestion:
  45989. $choices = $question->getChoices();
  45990. $text = sprintf(' <info>%s</info> [<comment>%s</comment>]:', $text, OutputFormatter::escape(isset($choices[$default]) ? $choices[$default] : $default));
  45991. break;
  45992. default:
  45993. $text = sprintf(' <info>%s</info> [<comment>%s</comment>]:', $text, OutputFormatter::escape($default));
  45994. }
  45995. $output->writeln($text);
  45996. $prompt = ' > ';
  45997. if ($question instanceof ChoiceQuestion) {
  45998. $output->writeln($this->formatChoiceQuestionChoices($question, 'comment'));
  45999. $prompt = $question->getPrompt();
  46000. }
  46001. $output->write($prompt);
  46002. }
  46003. protected function writeError(OutputInterface $output, \Exception $error)
  46004. {
  46005. if ($output instanceof SymfonyStyle) {
  46006. $output->newLine();
  46007. $output->error($error->getMessage());
  46008. return;
  46009. }
  46010. parent::writeError($output, $error);
  46011. }
  46012. }
  46013. <?php
  46014. namespace Symfony\Component\Console\Helper;
  46015. class TableSeparator extends TableCell
  46016. {
  46017. public function __construct(array $options = [])
  46018. {
  46019. parent::__construct('', $options);
  46020. }
  46021. }
  46022. <?php
  46023. namespace Symfony\Component\Console\Helper;
  46024. use Symfony\Component\Console\Formatter\OutputFormatter;
  46025. class FormatterHelper extends Helper
  46026. {
  46027. public function formatSection($section, $message, $style = 'info')
  46028. {
  46029. return sprintf('<%s>[%s]</%s> %s', $style, $section, $style, $message);
  46030. }
  46031. public function formatBlock($messages, $style, $large = false)
  46032. {
  46033. if (!\is_array($messages)) {
  46034. $messages = [$messages];
  46035. }
  46036. $len = 0;
  46037. $lines = [];
  46038. foreach ($messages as $message) {
  46039. $message = OutputFormatter::escape($message);
  46040. $lines[] = sprintf($large ? ' %s ' : ' %s ', $message);
  46041. $len = max(self::strlen($message) + ($large ? 4 : 2), $len);
  46042. }
  46043. $messages = $large ? [str_repeat(' ', $len)] : [];
  46044. for ($i = 0; isset($lines[$i]); ++$i) {
  46045. $messages[] = $lines[$i].str_repeat(' ', $len - self::strlen($lines[$i]));
  46046. }
  46047. if ($large) {
  46048. $messages[] = str_repeat(' ', $len);
  46049. }
  46050. for ($i = 0; isset($messages[$i]); ++$i) {
  46051. $messages[$i] = sprintf('<%s>%s</%s>', $style, $messages[$i], $style);
  46052. }
  46053. return implode("\n", $messages);
  46054. }
  46055. public function truncate($message, $length, $suffix = '...')
  46056. {
  46057. $computedLength = $length - self::strlen($suffix);
  46058. if ($computedLength > self::strlen($message)) {
  46059. return $message;
  46060. }
  46061. return self::substr($message, 0, $length).$suffix;
  46062. }
  46063. public function getName()
  46064. {
  46065. return 'formatter';
  46066. }
  46067. }
  46068. <?php
  46069. namespace Symfony\Component\Console\Helper;
  46070. use Symfony\Component\Console\Command\Command;
  46071. use Symfony\Component\Console\Exception\InvalidArgumentException;
  46072. class HelperSet implements \IteratorAggregate
  46073. {
  46074. private $helpers = [];
  46075. private $command;
  46076. public function __construct(array $helpers = [])
  46077. {
  46078. foreach ($helpers as $alias => $helper) {
  46079. $this->set($helper, \is_int($alias) ? null : $alias);
  46080. }
  46081. }
  46082. public function set(HelperInterface $helper, $alias = null)
  46083. {
  46084. $this->helpers[$helper->getName()] = $helper;
  46085. if (null !== $alias) {
  46086. $this->helpers[$alias] = $helper;
  46087. }
  46088. $helper->setHelperSet($this);
  46089. }
  46090. public function has($name)
  46091. {
  46092. return isset($this->helpers[$name]);
  46093. }
  46094. public function get($name)
  46095. {
  46096. if (!$this->has($name)) {
  46097. throw new InvalidArgumentException(sprintf('The helper "%s" is not defined.', $name));
  46098. }
  46099. return $this->helpers[$name];
  46100. }
  46101. public function setCommand(Command $command = null)
  46102. {
  46103. $this->command = $command;
  46104. }
  46105. public function getCommand()
  46106. {
  46107. return $this->command;
  46108. }
  46109. public function getIterator()
  46110. {
  46111. return new \ArrayIterator($this->helpers);
  46112. }
  46113. }
  46114. <?php
  46115. namespace Symfony\Component\Console\Helper;
  46116. use Symfony\Component\Console\Exception\InvalidArgumentException;
  46117. use Symfony\Component\Console\Exception\LogicException;
  46118. /**
  46119. @gmail
  46120. */
  46121. class TableStyle
  46122. {
  46123. private $paddingChar = ' ';
  46124. private $horizontalBorderChar = '-';
  46125. private $verticalBorderChar = '|';
  46126. private $crossingChar = '+';
  46127. private $cellHeaderFormat = '<info>%s</info>';
  46128. private $cellRowFormat = '%s';
  46129. private $cellRowContentFormat = ' %s ';
  46130. private $borderFormat = '%s';
  46131. private $padType = STR_PAD_RIGHT;
  46132. public function setPaddingChar($paddingChar)
  46133. {
  46134. if (!$paddingChar) {
  46135. throw new LogicException('The padding char must not be empty.');
  46136. }
  46137. $this->paddingChar = $paddingChar;
  46138. return $this;
  46139. }
  46140. public function getPaddingChar()
  46141. {
  46142. return $this->paddingChar;
  46143. }
  46144. public function setHorizontalBorderChar($horizontalBorderChar)
  46145. {
  46146. $this->horizontalBorderChar = $horizontalBorderChar;
  46147. return $this;
  46148. }
  46149. public function getHorizontalBorderChar()
  46150. {
  46151. return $this->horizontalBorderChar;
  46152. }
  46153. public function setVerticalBorderChar($verticalBorderChar)
  46154. {
  46155. $this->verticalBorderChar = $verticalBorderChar;
  46156. return $this;
  46157. }
  46158. public function getVerticalBorderChar()
  46159. {
  46160. return $this->verticalBorderChar;
  46161. }
  46162. public function setCrossingChar($crossingChar)
  46163. {
  46164. $this->crossingChar = $crossingChar;
  46165. return $this;
  46166. }
  46167. public function getCrossingChar()
  46168. {
  46169. return $this->crossingChar;
  46170. }
  46171. public function setCellHeaderFormat($cellHeaderFormat)
  46172. {
  46173. $this->cellHeaderFormat = $cellHeaderFormat;
  46174. return $this;
  46175. }
  46176. public function getCellHeaderFormat()
  46177. {
  46178. return $this->cellHeaderFormat;
  46179. }
  46180. public function setCellRowFormat($cellRowFormat)
  46181. {
  46182. $this->cellRowFormat = $cellRowFormat;
  46183. return $this;
  46184. }
  46185. public function getCellRowFormat()
  46186. {
  46187. return $this->cellRowFormat;
  46188. }
  46189. public function setCellRowContentFormat($cellRowContentFormat)
  46190. {
  46191. $this->cellRowContentFormat = $cellRowContentFormat;
  46192. return $this;
  46193. }
  46194. public function getCellRowContentFormat()
  46195. {
  46196. return $this->cellRowContentFormat;
  46197. }
  46198. public function setBorderFormat($borderFormat)
  46199. {
  46200. $this->borderFormat = $borderFormat;
  46201. return $this;
  46202. }
  46203. public function getBorderFormat()
  46204. {
  46205. return $this->borderFormat;
  46206. }
  46207. public function setPadType($padType)
  46208. {
  46209. if (!\in_array($padType, [STR_PAD_LEFT, STR_PAD_RIGHT, STR_PAD_BOTH], true)) {
  46210. throw new InvalidArgumentException('Invalid padding type. Expected one of (STR_PAD_LEFT, STR_PAD_RIGHT, STR_PAD_BOTH).');
  46211. }
  46212. $this->padType = $padType;
  46213. return $this;
  46214. }
  46215. public function getPadType()
  46216. {
  46217. return $this->padType;
  46218. }
  46219. }
  46220. <?php
  46221. namespace Symfony\Component\Console\Helper;
  46222. use Symfony\Component\Console\Exception\InvalidArgumentException;
  46223. class TableCell
  46224. {
  46225. private $value;
  46226. private $options = [
  46227. 'rowspan' => 1,
  46228. 'colspan' => 1,
  46229. ];
  46230. public function __construct($value = '', array $options = [])
  46231. {
  46232. if (is_numeric($value) && !\is_string($value)) {
  46233. $value = (string) $value;
  46234. }
  46235. $this->value = $value;
  46236. if ($diff = array_diff(array_keys($options), array_keys($this->options))) {
  46237. throw new InvalidArgumentException(sprintf('The TableCell does not support the following options: \'%s\'.', implode('\', \'', $diff)));
  46238. }
  46239. $this->options = array_merge($this->options, $options);
  46240. }
  46241. public function __toString()
  46242. {
  46243. return $this->value;
  46244. }
  46245. public function getColspan()
  46246. {
  46247. return (int) $this->options['colspan'];
  46248. }
  46249. public function getRowspan()
  46250. {
  46251. return (int) $this->options['rowspan'];
  46252. }
  46253. }
  46254. <?php
  46255. namespace Symfony\Component\Console\Helper;
  46256. use Symfony\Component\Console\Exception\InvalidArgumentException;
  46257. use Symfony\Component\Console\Exception\LogicException;
  46258. use Symfony\Component\Console\Output\OutputInterface;
  46259. class ProgressIndicator
  46260. {
  46261. private $output;
  46262. private $startTime;
  46263. private $format;
  46264. private $message;
  46265. private $indicatorValues;
  46266. private $indicatorCurrent;
  46267. private $indicatorChangeInterval;
  46268. private $indicatorUpdateTime;
  46269. private $started = false;
  46270. private static $formatters;
  46271. private static $formats;
  46272. public function __construct(OutputInterface $output, $format = null, $indicatorChangeInterval = 100, $indicatorValues = null)
  46273. {
  46274. $this->output = $output;
  46275. if (null === $format) {
  46276. $format = $this->determineBestFormat();
  46277. }
  46278. if (null === $indicatorValues) {
  46279. $indicatorValues = ['-', '\\', '|', '/'];
  46280. }
  46281. $indicatorValues = array_values($indicatorValues);
  46282. if (2 > \count($indicatorValues)) {
  46283. throw new InvalidArgumentException('Must have at least 2 indicator value characters.');
  46284. }
  46285. $this->format = self::getFormatDefinition($format);
  46286. $this->indicatorChangeInterval = $indicatorChangeInterval;
  46287. $this->indicatorValues = $indicatorValues;
  46288. $this->startTime = time();
  46289. }
  46290. public function setMessage($message)
  46291. {
  46292. $this->message = $message;
  46293. $this->display();
  46294. }
  46295. public function start($message)
  46296. {
  46297. if ($this->started) {
  46298. throw new LogicException('Progress indicator already started.');
  46299. }
  46300. $this->message = $message;
  46301. $this->started = true;
  46302. $this->startTime = time();
  46303. $this->indicatorUpdateTime = $this->getCurrentTimeInMilliseconds() + $this->indicatorChangeInterval;
  46304. $this->indicatorCurrent = 0;
  46305. $this->display();
  46306. }
  46307. public function advance()
  46308. {
  46309. if (!$this->started) {
  46310. throw new LogicException('Progress indicator has not yet been started.');
  46311. }
  46312. if (!$this->output->isDecorated()) {
  46313. return;
  46314. }
  46315. $currentTime = $this->getCurrentTimeInMilliseconds();
  46316. if ($currentTime < $this->indicatorUpdateTime) {
  46317. return;
  46318. }
  46319. $this->indicatorUpdateTime = $currentTime + $this->indicatorChangeInterval;
  46320. ++$this->indicatorCurrent;
  46321. $this->display();
  46322. }
  46323. public function finish($message)
  46324. {
  46325. if (!$this->started) {
  46326. throw new LogicException('Progress indicator has not yet been started.');
  46327. }
  46328. $this->message = $message;
  46329. $this->display();
  46330. $this->output->writeln('');
  46331. $this->started = false;
  46332. }
  46333. public static function getFormatDefinition($name)
  46334. {
  46335. if (!self::$formats) {
  46336. self::$formats = self::initFormats();
  46337. }
  46338. return isset(self::$formats[$name]) ? self::$formats[$name] : null;
  46339. }
  46340. public static function setPlaceholderFormatterDefinition($name, $callable)
  46341. {
  46342. if (!self::$formatters) {
  46343. self::$formatters = self::initPlaceholderFormatters();
  46344. }
  46345. self::$formatters[$name] = $callable;
  46346. }
  46347. public static function getPlaceholderFormatterDefinition($name)
  46348. {
  46349. if (!self::$formatters) {
  46350. self::$formatters = self::initPlaceholderFormatters();
  46351. }
  46352. return isset(self::$formatters[$name]) ? self::$formatters[$name] : null;
  46353. }
  46354. private function display()
  46355. {
  46356. if (OutputInterface::VERBOSITY_QUIET === $this->output->getVerbosity()) {
  46357. return;
  46358. }
  46359. $self = $this;
  46360. $this->overwrite(preg_replace_callback("{%([a-z\-_]+)(?:\:([^%]+))?%}i", function ($matches) use ($self) {
  46361. if ($formatter = $self::getPlaceholderFormatterDefinition($matches[1])) {
  46362. return \call_user_func($formatter, $self);
  46363. }
  46364. return $matches[0];
  46365. }, $this->format));
  46366. }
  46367. private function determineBestFormat()
  46368. {
  46369. switch ($this->output->getVerbosity()) {
  46370. case OutputInterface::VERBOSITY_VERBOSE:
  46371. return $this->output->isDecorated() ? 'verbose' : 'verbose_no_ansi';
  46372. case OutputInterface::VERBOSITY_VERY_VERBOSE:
  46373. case OutputInterface::VERBOSITY_DEBUG:
  46374. return $this->output->isDecorated() ? 'very_verbose' : 'very_verbose_no_ansi';
  46375. default:
  46376. return $this->output->isDecorated() ? 'normal' : 'normal_no_ansi';
  46377. }
  46378. }
  46379. private function overwrite($message)
  46380. {
  46381. if ($this->output->isDecorated()) {
  46382. $this->output->write("\x0D\x1B[2K");
  46383. $this->output->write($message);
  46384. } else {
  46385. $this->output->writeln($message);
  46386. }
  46387. }
  46388. private function getCurrentTimeInMilliseconds()
  46389. {
  46390. return round(microtime(true) * 1000);
  46391. }
  46392. private static function initPlaceholderFormatters()
  46393. {
  46394. return [
  46395. 'indicator' => function (self $indicator) {
  46396. return $indicator->indicatorValues[$indicator->indicatorCurrent % \count($indicator->indicatorValues)];
  46397. },
  46398. 'message' => function (self $indicator) {
  46399. return $indicator->message;
  46400. },
  46401. 'elapsed' => function (self $indicator) {
  46402. return Helper::formatTime(time() - $indicator->startTime);
  46403. },
  46404. 'memory' => function () {
  46405. return Helper::formatMemory(memory_get_usage(true));
  46406. },
  46407. ];
  46408. }
  46409. private static function initFormats()
  46410. {
  46411. return [
  46412. 'normal' => ' %indicator% %message%',
  46413. 'normal_no_ansi' => ' %message%',
  46414. 'verbose' => ' %indicator% %message% (%elapsed:6s%)',
  46415. 'verbose_no_ansi' => ' %message% (%elapsed:6s%)',
  46416. 'very_verbose' => ' %indicator% %message% (%elapsed:6s%, %memory:6s%)',
  46417. 'very_verbose_no_ansi' => ' %message% (%elapsed:6s%, %memory:6s%)',
  46418. ];
  46419. }
  46420. }
  46421. <?php
  46422. namespace Symfony\Component\Console\Helper;
  46423. use Symfony\Component\Console\Exception\InvalidArgumentException;
  46424. use Symfony\Component\Console\Exception\RuntimeException;
  46425. use Symfony\Component\Console\Formatter\OutputFormatter;
  46426. use Symfony\Component\Console\Formatter\OutputFormatterStyle;
  46427. use Symfony\Component\Console\Input\InputInterface;
  46428. use Symfony\Component\Console\Input\StreamableInputInterface;
  46429. use Symfony\Component\Console\Output\ConsoleOutputInterface;
  46430. use Symfony\Component\Console\Output\OutputInterface;
  46431. use Symfony\Component\Console\Question\ChoiceQuestion;
  46432. use Symfony\Component\Console\Question\Question;
  46433. use Symfony\Component\Console\Terminal;
  46434. class QuestionHelper extends Helper
  46435. {
  46436. private $inputStream;
  46437. private static $shell;
  46438. private static $stty = true;
  46439. public function ask(InputInterface $input, OutputInterface $output, Question $question)
  46440. {
  46441. if ($output instanceof ConsoleOutputInterface) {
  46442. $output = $output->getErrorOutput();
  46443. }
  46444. if (!$input->isInteractive()) {
  46445. $default = $question->getDefault();
  46446. if (null === $default) {
  46447. return $default;
  46448. }
  46449. if ($validator = $question->getValidator()) {
  46450. return \call_user_func($question->getValidator(), $default);
  46451. } elseif ($question instanceof ChoiceQuestion) {
  46452. $choices = $question->getChoices();
  46453. if (!$question->isMultiselect()) {
  46454. return isset($choices[$default]) ? $choices[$default] : $default;
  46455. }
  46456. $default = explode(',', $default);
  46457. foreach ($default as $k => $v) {
  46458. $v = trim($v);
  46459. $default[$k] = isset($choices[$v]) ? $choices[$v] : $v;
  46460. }
  46461. }
  46462. return $default;
  46463. }
  46464. if ($input instanceof StreamableInputInterface && $stream = $input->getStream()) {
  46465. $this->inputStream = $stream;
  46466. }
  46467. if (!$question->getValidator()) {
  46468. return $this->doAsk($output, $question);
  46469. }
  46470. $interviewer = function () use ($output, $question) {
  46471. return $this->doAsk($output, $question);
  46472. };
  46473. return $this->validateAttempts($interviewer, $output, $question);
  46474. }
  46475. public function setInputStream($stream)
  46476. {
  46477. @trigger_error(sprintf('The %s() method is deprecated since Symfony 3.2 and will be removed in 4.0. Use %s::setStream() instead.', __METHOD__, StreamableInputInterface::class), E_USER_DEPRECATED);
  46478. if (!\is_resource($stream)) {
  46479. throw new InvalidArgumentException('Input stream must be a valid resource.');
  46480. }
  46481. $this->inputStream = $stream;
  46482. }
  46483. public function getInputStream()
  46484. {
  46485. if (0 === \func_num_args() || func_get_arg(0)) {
  46486. @trigger_error(sprintf('The %s() method is deprecated since Symfony 3.2 and will be removed in 4.0. Use %s::getStream() instead.', __METHOD__, StreamableInputInterface::class), E_USER_DEPRECATED);
  46487. }
  46488. return $this->inputStream;
  46489. }
  46490. public function getName()
  46491. {
  46492. return 'question';
  46493. }
  46494. public static function disableStty()
  46495. {
  46496. self::$stty = false;
  46497. }
  46498. private function doAsk(OutputInterface $output, Question $question)
  46499. {
  46500. $this->writePrompt($output, $question);
  46501. $inputStream = $this->inputStream ?: STDIN;
  46502. $autocomplete = $question->getAutocompleterValues();
  46503. if (null === $autocomplete || !self::$stty || !Terminal::hasSttyAvailable()) {
  46504. $ret = false;
  46505. if ($question->isHidden()) {
  46506. try {
  46507. $ret = trim($this->getHiddenResponse($output, $inputStream));
  46508. } catch (RuntimeException $e) {
  46509. if (!$question->isHiddenFallback()) {
  46510. throw $e;
  46511. }
  46512. }
  46513. }
  46514. if (false === $ret) {
  46515. $ret = fgets($inputStream, 4096);
  46516. if (false === $ret) {
  46517. throw new RuntimeException('Aborted.');
  46518. }
  46519. $ret = trim($ret);
  46520. }
  46521. } else {
  46522. $ret = trim($this->autocomplete($output, $question, $inputStream, \is_array($autocomplete) ? $autocomplete : iterator_to_array($autocomplete, false)));
  46523. }
  46524. $ret = \strlen($ret) > 0 ? $ret : $question->getDefault();
  46525. if ($normalizer = $question->getNormalizer()) {
  46526. return $normalizer($ret);
  46527. }
  46528. return $ret;
  46529. }
  46530. protected function writePrompt(OutputInterface $output, Question $question)
  46531. {
  46532. $message = $question->getQuestion();
  46533. if ($question instanceof ChoiceQuestion) {
  46534. $output->writeln(array_merge([
  46535. $question->getQuestion(),
  46536. ], $this->formatChoiceQuestionChoices($question, 'info')));
  46537. $message = $question->getPrompt();
  46538. }
  46539. $output->write($message);
  46540. }
  46541. protected function formatChoiceQuestionChoices(ChoiceQuestion $question, $tag)
  46542. {
  46543. $messages = [];
  46544. $maxWidth = max(array_map('self::strlen', array_keys($choices = $question->getChoices())));
  46545. foreach ($choices as $key => $value) {
  46546. $padding = str_repeat(' ', $maxWidth - self::strlen($key));
  46547. $messages[] = sprintf(" [<$tag>%s$padding</$tag>] %s", $key, $value);
  46548. }
  46549. return $messages;
  46550. }
  46551. protected function writeError(OutputInterface $output, \Exception $error)
  46552. {
  46553. if (null !== $this->getHelperSet() && $this->getHelperSet()->has('formatter')) {
  46554. $message = $this->getHelperSet()->get('formatter')->formatBlock($error->getMessage(), 'error');
  46555. } else {
  46556. $message = '<error>'.$error->getMessage().'</error>';
  46557. }
  46558. $output->writeln($message);
  46559. }
  46560. private function autocomplete(OutputInterface $output, Question $question, $inputStream, array $autocomplete)
  46561. {
  46562. $fullChoice = '';
  46563. $ret = '';
  46564. $i = 0;
  46565. $ofs = -1;
  46566. $matches = $autocomplete;
  46567. $numMatches = \count($matches);
  46568. $sttyMode = shell_exec('stty -g');
  46569. shell_exec('stty -icanon -echo');
  46570. $output->getFormatter()->setStyle('hl', new OutputFormatterStyle('black', 'white'));
  46571. while (!feof($inputStream)) {
  46572. $c = fread($inputStream, 1);
  46573. if (false === $c || ('' === $ret && '' === $c && null === $question->getDefault())) {
  46574. shell_exec(sprintf('stty %s', $sttyMode));
  46575. throw new RuntimeException('Aborted.');
  46576. } elseif ("\177" === $c) {
  46577. if (0 === $numMatches && 0 !== $i) {
  46578. --$i;
  46579. $fullChoice = self::substr($fullChoice, 0, $i);
  46580. $output->write("\033[1D");
  46581. }
  46582. if (0 === $i) {
  46583. $ofs = -1;
  46584. $matches = $autocomplete;
  46585. $numMatches = \count($matches);
  46586. } else {
  46587. $numMatches = 0;
  46588. }
  46589. $ret = self::substr($ret, 0, $i);
  46590. } elseif ("\033" === $c) {
  46591. $c .= fread($inputStream, 2);
  46592. if (isset($c[2]) && ('A' === $c[2] || 'B' === $c[2])) {
  46593. if ('A' === $c[2] && -1 === $ofs) {
  46594. $ofs = 0;
  46595. }
  46596. if (0 === $numMatches) {
  46597. continue;
  46598. }
  46599. $ofs += ('A' === $c[2]) ? -1 : 1;
  46600. $ofs = ($numMatches + $ofs) % $numMatches;
  46601. }
  46602. } elseif (\ord($c) < 32) {
  46603. if ("\t" === $c || "\n" === $c) {
  46604. if ($numMatches > 0 && -1 !== $ofs) {
  46605. $ret = $matches[$ofs];
  46606. $remainingCharacters = substr($ret, \strlen(trim($this->mostRecentlyEnteredValue($fullChoice))));
  46607. $output->write($remainingCharacters);
  46608. $fullChoice .= $remainingCharacters;
  46609. $i = self::strlen($fullChoice);
  46610. }
  46611. if ("\n" === $c) {
  46612. $output->write($c);
  46613. break;
  46614. }
  46615. $numMatches = 0;
  46616. }
  46617. continue;
  46618. } else {
  46619. if ("\x80" <= $c) {
  46620. $c .= fread($inputStream, ["\xC0" => 1, "\xD0" => 1, "\xE0" => 2, "\xF0" => 3][$c & "\xF0"]);
  46621. }
  46622. $output->write($c);
  46623. $ret .= $c;
  46624. $fullChoice .= $c;
  46625. ++$i;
  46626. $tempRet = $ret;
  46627. if ($question instanceof ChoiceQuestion && $question->isMultiselect()) {
  46628. $tempRet = $this->mostRecentlyEnteredValue($fullChoice);
  46629. }
  46630. $numMatches = 0;
  46631. $ofs = 0;
  46632. foreach ($autocomplete as $value) {
  46633. if (0 === strpos($value, $tempRet)) {
  46634. $matches[$numMatches++] = $value;
  46635. }
  46636. }
  46637. }
  46638. $output->write("\033[K");
  46639. if ($numMatches > 0 && -1 !== $ofs) {
  46640. $output->write("\0337");
  46641. $charactersEntered = \strlen(trim($this->mostRecentlyEnteredValue($fullChoice)));
  46642. $output->write('<hl>'.OutputFormatter::escapeTrailingBackslash(substr($matches[$ofs], $charactersEntered)).'</hl>');
  46643. $output->write("\0338");
  46644. }
  46645. }
  46646. shell_exec(sprintf('stty %s', $sttyMode));
  46647. return $fullChoice;
  46648. }
  46649. private function mostRecentlyEnteredValue($entered)
  46650. {
  46651. if (false === strpos($entered, ',')) {
  46652. return $entered;
  46653. }
  46654. $choices = explode(',', $entered);
  46655. if (\strlen($lastChoice = trim($choices[\count($choices) - 1])) > 0) {
  46656. return $lastChoice;
  46657. }
  46658. return $entered;
  46659. }
  46660. private function getHiddenResponse(OutputInterface $output, $inputStream)
  46661. {
  46662. if ('\\' === \DIRECTORY_SEPARATOR) {
  46663. $exe = __DIR__.'/../Resources/bin/hiddeninput.exe';
  46664. if ('phar:' === substr(__FILE__, 0, 5)) {
  46665. $tmpExe = sys_get_temp_dir().'/hiddeninput.exe';
  46666. copy($exe, $tmpExe);
  46667. $exe = $tmpExe;
  46668. }
  46669. $value = rtrim(shell_exec($exe));
  46670. $output->writeln('');
  46671. if (isset($tmpExe)) {
  46672. unlink($tmpExe);
  46673. }
  46674. return $value;
  46675. }
  46676. if (self::$stty && Terminal::hasSttyAvailable()) {
  46677. $sttyMode = shell_exec('stty -g');
  46678. shell_exec('stty -echo');
  46679. $value = fgets($inputStream, 4096);
  46680. shell_exec(sprintf('stty %s', $sttyMode));
  46681. if (false === $value) {
  46682. throw new RuntimeException('Aborted.');
  46683. }
  46684. $value = trim($value);
  46685. $output->writeln('');
  46686. return $value;
  46687. }
  46688. if (false !== $shell = $this->getShell()) {
  46689. $readCmd = 'csh' === $shell ? 'set mypassword = $<' : 'read -r mypassword';
  46690. $command = sprintf("/usr/bin/env %s -c 'stty -echo; %s; stty echo; echo \$mypassword'", $shell, $readCmd);
  46691. $value = rtrim(shell_exec($command));
  46692. $output->writeln('');
  46693. return $value;
  46694. }
  46695. throw new RuntimeException('Unable to hide the response.');
  46696. }
  46697. private function validateAttempts(callable $interviewer, OutputInterface $output, Question $question)
  46698. {
  46699. $error = null;
  46700. $attempts = $question->getMaxAttempts();
  46701. while (null === $attempts || $attempts--) {
  46702. if (null !== $error) {
  46703. $this->writeError($output, $error);
  46704. }
  46705. try {
  46706. return \call_user_func($question->getValidator(), $interviewer());
  46707. } catch (RuntimeException $e) {
  46708. throw $e;
  46709. } catch (\Exception $error) {
  46710. }
  46711. }
  46712. throw $error;
  46713. }
  46714. private function getShell()
  46715. {
  46716. if (null !== self::$shell) {
  46717. return self::$shell;
  46718. }
  46719. self::$shell = false;
  46720. if (file_exists('/usr/bin/env')) {
  46721. $test = "/usr/bin/env %s -c 'echo OK' 2> /dev/null";
  46722. foreach (['bash', 'zsh', 'ksh', 'csh'] as $sh) {
  46723. if ('OK' === rtrim(shell_exec(sprintf($test, $sh)))) {
  46724. self::$shell = $sh;
  46725. break;
  46726. }
  46727. }
  46728. }
  46729. return self::$shell;
  46730. }
  46731. }
  46732. <?php
  46733. namespace Symfony\Component\Console\Helper;
  46734. use Symfony\Component\Console\Exception\LogicException;
  46735. use Symfony\Component\Console\Output\ConsoleOutputInterface;
  46736. use Symfony\Component\Console\Output\OutputInterface;
  46737. use Symfony\Component\Console\Terminal;
  46738. /**
  46739. @gmail
  46740. */
  46741. final class ProgressBar
  46742. {
  46743. private $barWidth = 28;
  46744. private $barChar;
  46745. private $emptyBarChar = '-';
  46746. private $progressChar = '>';
  46747. private $format;
  46748. private $internalFormat;
  46749. private $redrawFreq = 1;
  46750. private $output;
  46751. private $step = 0;
  46752. private $max;
  46753. private $startTime;
  46754. private $stepWidth;
  46755. private $percent = 0.0;
  46756. private $formatLineCount;
  46757. private $messages = [];
  46758. private $overwrite = true;
  46759. private $terminal;
  46760. private $firstRun = true;
  46761. private static $formatters;
  46762. private static $formats;
  46763. public function __construct(OutputInterface $output, $max = 0)
  46764. {
  46765. if ($output instanceof ConsoleOutputInterface) {
  46766. $output = $output->getErrorOutput();
  46767. }
  46768. $this->output = $output;
  46769. $this->setMaxSteps($max);
  46770. $this->terminal = new Terminal();
  46771. if (!$this->output->isDecorated()) {
  46772. $this->overwrite = false;
  46773. $this->setRedrawFrequency($max / 10);
  46774. }
  46775. $this->startTime = time();
  46776. }
  46777. public static function setPlaceholderFormatterDefinition($name, callable $callable)
  46778. {
  46779. if (!self::$formatters) {
  46780. self::$formatters = self::initPlaceholderFormatters();
  46781. }
  46782. self::$formatters[$name] = $callable;
  46783. }
  46784. public static function getPlaceholderFormatterDefinition($name)
  46785. {
  46786. if (!self::$formatters) {
  46787. self::$formatters = self::initPlaceholderFormatters();
  46788. }
  46789. return isset(self::$formatters[$name]) ? self::$formatters[$name] : null;
  46790. }
  46791. public static function setFormatDefinition($name, $format)
  46792. {
  46793. if (!self::$formats) {
  46794. self::$formats = self::initFormats();
  46795. }
  46796. self::$formats[$name] = $format;
  46797. }
  46798. public static function getFormatDefinition($name)
  46799. {
  46800. if (!self::$formats) {
  46801. self::$formats = self::initFormats();
  46802. }
  46803. return isset(self::$formats[$name]) ? self::$formats[$name] : null;
  46804. }
  46805. public function setMessage($message, $name = 'message')
  46806. {
  46807. $this->messages[$name] = $message;
  46808. }
  46809. public function getMessage($name = 'message')
  46810. {
  46811. return $this->messages[$name];
  46812. }
  46813. public function getStartTime()
  46814. {
  46815. return $this->startTime;
  46816. }
  46817. public function getMaxSteps()
  46818. {
  46819. return $this->max;
  46820. }
  46821. public function getProgress()
  46822. {
  46823. return $this->step;
  46824. }
  46825. private function getStepWidth()
  46826. {
  46827. return $this->stepWidth;
  46828. }
  46829. public function getProgressPercent()
  46830. {
  46831. return $this->percent;
  46832. }
  46833. public function setBarWidth($size)
  46834. {
  46835. $this->barWidth = max(1, (int) $size);
  46836. }
  46837. public function getBarWidth()
  46838. {
  46839. return $this->barWidth;
  46840. }
  46841. public function setBarCharacter($char)
  46842. {
  46843. $this->barChar = $char;
  46844. }
  46845. public function getBarCharacter()
  46846. {
  46847. if (null === $this->barChar) {
  46848. return $this->max ? '=' : $this->emptyBarChar;
  46849. }
  46850. return $this->barChar;
  46851. }
  46852. public function setEmptyBarCharacter($char)
  46853. {
  46854. $this->emptyBarChar = $char;
  46855. }
  46856. public function getEmptyBarCharacter()
  46857. {
  46858. return $this->emptyBarChar;
  46859. }
  46860. public function setProgressCharacter($char)
  46861. {
  46862. $this->progressChar = $char;
  46863. }
  46864. public function getProgressCharacter()
  46865. {
  46866. return $this->progressChar;
  46867. }
  46868. public function setFormat($format)
  46869. {
  46870. $this->format = null;
  46871. $this->internalFormat = $format;
  46872. }
  46873. public function setRedrawFrequency($freq)
  46874. {
  46875. $this->redrawFreq = max((int) $freq, 1);
  46876. }
  46877. public function start($max = null)
  46878. {
  46879. $this->startTime = time();
  46880. $this->step = 0;
  46881. $this->percent = 0.0;
  46882. if (null !== $max) {
  46883. $this->setMaxSteps($max);
  46884. }
  46885. $this->display();
  46886. }
  46887. public function advance($step = 1)
  46888. {
  46889. $this->setProgress($this->step + $step);
  46890. }
  46891. public function setOverwrite($overwrite)
  46892. {
  46893. $this->overwrite = (bool) $overwrite;
  46894. }
  46895. public function setProgress($step)
  46896. {
  46897. $step = (int) $step;
  46898. if ($this->max && $step > $this->max) {
  46899. $this->max = $step;
  46900. } elseif ($step < 0) {
  46901. $step = 0;
  46902. }
  46903. $prevPeriod = (int) ($this->step / $this->redrawFreq);
  46904. $currPeriod = (int) ($step / $this->redrawFreq);
  46905. $this->step = $step;
  46906. $this->percent = $this->max ? (float) $this->step / $this->max : 0;
  46907. if ($prevPeriod !== $currPeriod || $this->max === $step) {
  46908. $this->display();
  46909. }
  46910. }
  46911. public function finish()
  46912. {
  46913. if (!$this->max) {
  46914. $this->max = $this->step;
  46915. }
  46916. if ($this->step === $this->max && !$this->overwrite) {
  46917. return;
  46918. }
  46919. $this->setProgress($this->max);
  46920. }
  46921. public function display()
  46922. {
  46923. if (OutputInterface::VERBOSITY_QUIET === $this->output->getVerbosity()) {
  46924. return;
  46925. }
  46926. if (null === $this->format) {
  46927. $this->setRealFormat($this->internalFormat ?: $this->determineBestFormat());
  46928. }
  46929. $this->overwrite($this->buildLine());
  46930. }
  46931. public function clear()
  46932. {
  46933. if (!$this->overwrite) {
  46934. return;
  46935. }
  46936. if (null === $this->format) {
  46937. $this->setRealFormat($this->internalFormat ?: $this->determineBestFormat());
  46938. }
  46939. $this->overwrite('');
  46940. }
  46941. private function setRealFormat($format)
  46942. {
  46943. if (!$this->max && null !== self::getFormatDefinition($format.'_nomax')) {
  46944. $this->format = self::getFormatDefinition($format.'_nomax');
  46945. } elseif (null !== self::getFormatDefinition($format)) {
  46946. $this->format = self::getFormatDefinition($format);
  46947. } else {
  46948. $this->format = $format;
  46949. }
  46950. $this->formatLineCount = substr_count($this->format, "\n");
  46951. }
  46952. private function setMaxSteps($max)
  46953. {
  46954. $this->max = max(0, (int) $max);
  46955. $this->stepWidth = $this->max ? Helper::strlen($this->max) : 4;
  46956. }
  46957. private function overwrite($message)
  46958. {
  46959. if ($this->overwrite) {
  46960. if (!$this->firstRun) {
  46961. if ($this->formatLineCount > 0) {
  46962. $message = str_repeat("\x1B[1A\x1B[2K", $this->formatLineCount).$message;
  46963. }
  46964. $message = "\x0D\x1B[2K$message";
  46965. }
  46966. } elseif ($this->step > 0) {
  46967. $message = PHP_EOL.$message;
  46968. }
  46969. $this->firstRun = false;
  46970. $this->output->write($message);
  46971. }
  46972. private function determineBestFormat()
  46973. {
  46974. switch ($this->output->getVerbosity()) {
  46975. case OutputInterface::VERBOSITY_VERBOSE:
  46976. return $this->max ? 'verbose' : 'verbose_nomax';
  46977. case OutputInterface::VERBOSITY_VERY_VERBOSE:
  46978. return $this->max ? 'very_verbose' : 'very_verbose_nomax';
  46979. case OutputInterface::VERBOSITY_DEBUG:
  46980. return $this->max ? 'debug' : 'debug_nomax';
  46981. default:
  46982. return $this->max ? 'normal' : 'normal_nomax';
  46983. }
  46984. }
  46985. private static function initPlaceholderFormatters()
  46986. {
  46987. return [
  46988. 'bar' => function (self $bar, OutputInterface $output) {
  46989. $completeBars = floor($bar->getMaxSteps() > 0 ? $bar->getProgressPercent() * $bar->getBarWidth() : $bar->getProgress() % $bar->getBarWidth());
  46990. $display = str_repeat($bar->getBarCharacter(), $completeBars);
  46991. if ($completeBars < $bar->getBarWidth()) {
  46992. $emptyBars = $bar->getBarWidth() - $completeBars - Helper::strlenWithoutDecoration($output->getFormatter(), $bar->getProgressCharacter());
  46993. $display .= $bar->getProgressCharacter().str_repeat($bar->getEmptyBarCharacter(), $emptyBars);
  46994. }
  46995. return $display;
  46996. },
  46997. 'elapsed' => function (self $bar) {
  46998. return Helper::formatTime(time() - $bar->getStartTime());
  46999. },
  47000. 'remaining' => function (self $bar) {
  47001. if (!$bar->getMaxSteps()) {
  47002. throw new LogicException('Unable to display the remaining time if the maximum number of steps is not set.');
  47003. }
  47004. if (!$bar->getProgress()) {
  47005. $remaining = 0;
  47006. } else {
  47007. $remaining = round((time() - $bar->getStartTime()) / $bar->getProgress() * ($bar->getMaxSteps() - $bar->getProgress()));
  47008. }
  47009. return Helper::formatTime($remaining);
  47010. },
  47011. 'estimated' => function (self $bar) {
  47012. if (!$bar->getMaxSteps()) {
  47013. throw new LogicException('Unable to display the estimated time if the maximum number of steps is not set.');
  47014. }
  47015. if (!$bar->getProgress()) {
  47016. $estimated = 0;
  47017. } else {
  47018. $estimated = round((time() - $bar->getStartTime()) / $bar->getProgress() * $bar->getMaxSteps());
  47019. }
  47020. return Helper::formatTime($estimated);
  47021. },
  47022. 'memory' => function (self $bar) {
  47023. return Helper::formatMemory(memory_get_usage(true));
  47024. },
  47025. 'current' => function (self $bar) {
  47026. return str_pad($bar->getProgress(), $bar->getStepWidth(), ' ', STR_PAD_LEFT);
  47027. },
  47028. 'max' => function (self $bar) {
  47029. return $bar->getMaxSteps();
  47030. },
  47031. 'percent' => function (self $bar) {
  47032. return floor($bar->getProgressPercent() * 100);
  47033. },
  47034. ];
  47035. }
  47036. private static function initFormats()
  47037. {
  47038. return [
  47039. 'normal' => ' %current%/%max% [%bar%] %percent:3s%%',
  47040. 'normal_nomax' => ' %current% [%bar%]',
  47041. 'verbose' => ' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%',
  47042. 'verbose_nomax' => ' %current% [%bar%] %elapsed:6s%',
  47043. 'very_verbose' => ' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%/%estimated:-6s%',
  47044. 'very_verbose_nomax' => ' %current% [%bar%] %elapsed:6s%',
  47045. 'debug' => ' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%/%estimated:-6s% %memory:6s%',
  47046. 'debug_nomax' => ' %current% [%bar%] %elapsed:6s% %memory:6s%',
  47047. ];
  47048. }
  47049. private function buildLine()
  47050. {
  47051. $regex = "{%([a-z\-_]+)(?:\:([^%]+))?%}i";
  47052. $callback = function ($matches) {
  47053. if ($formatter = $this::getPlaceholderFormatterDefinition($matches[1])) {
  47054. $text = \call_user_func($formatter, $this, $this->output);
  47055. } elseif (isset($this->messages[$matches[1]])) {
  47056. $text = $this->messages[$matches[1]];
  47057. } else {
  47058. return $matches[0];
  47059. }
  47060. if (isset($matches[2])) {
  47061. $text = sprintf('%'.$matches[2], $text);
  47062. }
  47063. return $text;
  47064. };
  47065. $line = preg_replace_callback($regex, $callback, $this->format);
  47066. $linesLength = array_map(function ($subLine) {
  47067. return Helper::strlenWithoutDecoration($this->output->getFormatter(), rtrim($subLine, "\r"));
  47068. }, explode("\n", $line));
  47069. $linesWidth = max($linesLength);
  47070. $terminalWidth = $this->terminal->getWidth();
  47071. if ($linesWidth <= $terminalWidth) {
  47072. return $line;
  47073. }
  47074. $this->setBarWidth($this->barWidth - $linesWidth + $terminalWidth);
  47075. return preg_replace_callback($regex, $callback, $this->format);
  47076. }
  47077. }
  47078. <?php
  47079. namespace Symfony\Component\Console\Style;
  47080. interface StyleInterface
  47081. {
  47082. public function title($message);
  47083. public function section($message);
  47084. public function listing(array $elements);
  47085. public function text($message);
  47086. public function success($message);
  47087. public function error($message);
  47088. public function warning($message);
  47089. public function note($message);
  47090. public function caution($message);
  47091. public function table(array $headers, array $rows);
  47092. public function ask($question, $default = null, $validator = null);
  47093. public function askHidden($question, $validator = null);
  47094. public function confirm($question, $default = true);
  47095. public function choice($question, array $choices, $default = null);
  47096. public function newLine($count = 1);
  47097. public function progressStart($max = 0);
  47098. public function progressAdvance($step = 1);
  47099. public function progressFinish();
  47100. }
  47101. <?php
  47102. namespace Symfony\Component\Console\Style;
  47103. use Symfony\Component\Console\Exception\RuntimeException;
  47104. use Symfony\Component\Console\Formatter\OutputFormatter;
  47105. use Symfony\Component\Console\Helper\Helper;
  47106. use Symfony\Component\Console\Helper\ProgressBar;
  47107. use Symfony\Component\Console\Helper\SymfonyQuestionHelper;
  47108. use Symfony\Component\Console\Helper\Table;
  47109. use Symfony\Component\Console\Input\InputInterface;
  47110. use Symfony\Component\Console\Output\BufferedOutput;
  47111. use Symfony\Component\Console\Output\OutputInterface;
  47112. use Symfony\Component\Console\Question\ChoiceQuestion;
  47113. use Symfony\Component\Console\Question\ConfirmationQuestion;
  47114. use Symfony\Component\Console\Question\Question;
  47115. use Symfony\Component\Console\Terminal;
  47116. class SymfonyStyle extends OutputStyle
  47117. {
  47118. const MAX_LINE_LENGTH = 120;
  47119. private $input;
  47120. private $questionHelper;
  47121. private $progressBar;
  47122. private $lineLength;
  47123. private $bufferedOutput;
  47124. public function __construct(InputInterface $input, OutputInterface $output)
  47125. {
  47126. $this->input = $input;
  47127. $this->bufferedOutput = new BufferedOutput($output->getVerbosity(), false, clone $output->getFormatter());
  47128. $width = (new Terminal())->getWidth() ?: self::MAX_LINE_LENGTH;
  47129. $this->lineLength = min($width - (int) (\DIRECTORY_SEPARATOR === '\\'), self::MAX_LINE_LENGTH);
  47130. parent::__construct($output);
  47131. }
  47132. public function block($messages, $type = null, $style = null, $prefix = ' ', $padding = false, $escape = true)
  47133. {
  47134. $messages = \is_array($messages) ? array_values($messages) : [$messages];
  47135. $this->autoPrependBlock();
  47136. $this->writeln($this->createBlock($messages, $type, $style, $prefix, $padding, $escape));
  47137. $this->newLine();
  47138. }
  47139. public function title($message)
  47140. {
  47141. $this->autoPrependBlock();
  47142. $this->writeln([
  47143. sprintf('<comment>%s</>', OutputFormatter::escapeTrailingBackslash($message)),
  47144. sprintf('<comment>%s</>', str_repeat('=', Helper::strlenWithoutDecoration($this->getFormatter(), $message))),
  47145. ]);
  47146. $this->newLine();
  47147. }
  47148. public function section($message)
  47149. {
  47150. $this->autoPrependBlock();
  47151. $this->writeln([
  47152. sprintf('<comment>%s</>', OutputFormatter::escapeTrailingBackslash($message)),
  47153. sprintf('<comment>%s</>', str_repeat('-', Helper::strlenWithoutDecoration($this->getFormatter(), $message))),
  47154. ]);
  47155. $this->newLine();
  47156. }
  47157. public function listing(array $elements)
  47158. {
  47159. $this->autoPrependText();
  47160. $elements = array_map(function ($element) {
  47161. return sprintf(' * %s', $element);
  47162. }, $elements);
  47163. $this->writeln($elements);
  47164. $this->newLine();
  47165. }
  47166. public function text($message)
  47167. {
  47168. $this->autoPrependText();
  47169. $messages = \is_array($message) ? array_values($message) : [$message];
  47170. foreach ($messages as $message) {
  47171. $this->writeln(sprintf(' %s', $message));
  47172. }
  47173. }
  47174. public function comment($message)
  47175. {
  47176. $this->block($message, null, null, '<fg=default;bg=default> // </>', false, false);
  47177. }
  47178. public function success($message)
  47179. {
  47180. $this->block($message, 'OK', 'fg=black;bg=green', ' ', true);
  47181. }
  47182. public function error($message)
  47183. {
  47184. $this->block($message, 'ERROR', 'fg=white;bg=red', ' ', true);
  47185. }
  47186. public function warning($message)
  47187. {
  47188. $this->block($message, 'WARNING', 'fg=white;bg=red', ' ', true);
  47189. }
  47190. public function note($message)
  47191. {
  47192. $this->block($message, 'NOTE', 'fg=yellow', ' ! ');
  47193. }
  47194. public function caution($message)
  47195. {
  47196. $this->block($message, 'CAUTION', 'fg=white;bg=red', ' ! ', true);
  47197. }
  47198. public function table(array $headers, array $rows)
  47199. {
  47200. $style = clone Table::getStyleDefinition('symfony-style-guide');
  47201. $style->setCellHeaderFormat('<info>%s</info>');
  47202. $table = new Table($this);
  47203. $table->setHeaders($headers);
  47204. $table->setRows($rows);
  47205. $table->setStyle($style);
  47206. $table->render();
  47207. $this->newLine();
  47208. }
  47209. public function ask($question, $default = null, $validator = null)
  47210. {
  47211. $question = new Question($question, $default);
  47212. $question->setValidator($validator);
  47213. return $this->askQuestion($question);
  47214. }
  47215. public function askHidden($question, $validator = null)
  47216. {
  47217. $question = new Question($question);
  47218. $question->setHidden(true);
  47219. $question->setValidator($validator);
  47220. return $this->askQuestion($question);
  47221. }
  47222. public function confirm($question, $default = true)
  47223. {
  47224. return $this->askQuestion(new ConfirmationQuestion($question, $default));
  47225. }
  47226. public function choice($question, array $choices, $default = null)
  47227. {
  47228. if (null !== $default) {
  47229. $values = array_flip($choices);
  47230. $default = isset($values[$default]) ? $values[$default] : $default;
  47231. }
  47232. return $this->askQuestion(new ChoiceQuestion($question, $choices, $default));
  47233. }
  47234. public function progressStart($max = 0)
  47235. {
  47236. $this->progressBar = $this->createProgressBar($max);
  47237. $this->progressBar->start();
  47238. }
  47239. public function progressAdvance($step = 1)
  47240. {
  47241. $this->getProgressBar()->advance($step);
  47242. }
  47243. public function progressFinish()
  47244. {
  47245. $this->getProgressBar()->finish();
  47246. $this->newLine(2);
  47247. $this->progressBar = null;
  47248. }
  47249. public function createProgressBar($max = 0)
  47250. {
  47251. $progressBar = parent::createProgressBar($max);
  47252. if ('\\' !== \DIRECTORY_SEPARATOR || 'Hyper' === getenv('TERM_PROGRAM')) {
  47253. $progressBar->setEmptyBarCharacter('â–‘');
  47254. $progressBar->setProgressCharacter('');
  47255. $progressBar->setBarCharacter('â–“');
  47256. }
  47257. return $progressBar;
  47258. }
  47259. public function askQuestion(Question $question)
  47260. {
  47261. if ($this->input->isInteractive()) {
  47262. $this->autoPrependBlock();
  47263. }
  47264. if (!$this->questionHelper) {
  47265. $this->questionHelper = new SymfonyQuestionHelper();
  47266. }
  47267. $answer = $this->questionHelper->ask($this->input, $this, $question);
  47268. if ($this->input->isInteractive()) {
  47269. $this->newLine();
  47270. $this->bufferedOutput->write("\n");
  47271. }
  47272. return $answer;
  47273. }
  47274. public function writeln($messages, $type = self::OUTPUT_NORMAL)
  47275. {
  47276. parent::writeln($messages, $type);
  47277. $this->bufferedOutput->writeln($this->reduceBuffer($messages), $type);
  47278. }
  47279. public function write($messages, $newline = false, $type = self::OUTPUT_NORMAL)
  47280. {
  47281. parent::write($messages, $newline, $type);
  47282. $this->bufferedOutput->write($this->reduceBuffer($messages), $newline, $type);
  47283. }
  47284. public function newLine($count = 1)
  47285. {
  47286. parent::newLine($count);
  47287. $this->bufferedOutput->write(str_repeat("\n", $count));
  47288. }
  47289. public function getErrorStyle()
  47290. {
  47291. return new self($this->input, $this->getErrorOutput());
  47292. }
  47293. private function getProgressBar()
  47294. {
  47295. if (!$this->progressBar) {
  47296. throw new RuntimeException('The ProgressBar is not started.');
  47297. }
  47298. return $this->progressBar;
  47299. }
  47300. private function autoPrependBlock()
  47301. {
  47302. $chars = substr(str_replace(PHP_EOL, "\n", $this->bufferedOutput->fetch()), -2);
  47303. if (!isset($chars[0])) {
  47304. $this->newLine();
  47305. return;
  47306. }
  47307. $this->newLine(2 - substr_count($chars, "\n"));
  47308. }
  47309. private function autoPrependText()
  47310. {
  47311. $fetched = $this->bufferedOutput->fetch();
  47312. if ("\n" !== substr($fetched, -1)) {
  47313. $this->newLine();
  47314. }
  47315. }
  47316. private function reduceBuffer($messages)
  47317. {
  47318. return array_map(function ($value) {
  47319. return substr($value, -4);
  47320. }, array_merge([$this->bufferedOutput->fetch()], (array) $messages));
  47321. }
  47322. private function createBlock($messages, $type = null, $style = null, $prefix = ' ', $padding = false, $escape = false)
  47323. {
  47324. $indentLength = 0;
  47325. $prefixLength = Helper::strlenWithoutDecoration($this->getFormatter(), $prefix);
  47326. $lines = [];
  47327. if (null !== $type) {
  47328. $type = sprintf('[%s] ', $type);
  47329. $indentLength = \strlen($type);
  47330. $lineIndentation = str_repeat(' ', $indentLength);
  47331. }
  47332. foreach ($messages as $key => $message) {
  47333. if ($escape) {
  47334. $message = OutputFormatter::escape($message);
  47335. }
  47336. $lines = array_merge($lines, explode(PHP_EOL, wordwrap($message, $this->lineLength - $prefixLength - $indentLength, PHP_EOL, true)));
  47337. if (\count($messages) > 1 && $key < \count($messages) - 1) {
  47338. $lines[] = '';
  47339. }
  47340. }
  47341. $firstLineIndex = 0;
  47342. if ($padding && $this->isDecorated()) {
  47343. $firstLineIndex = 1;
  47344. array_unshift($lines, '');
  47345. $lines[] = '';
  47346. }
  47347. foreach ($lines as $i => &$line) {
  47348. if (null !== $type) {
  47349. $line = $firstLineIndex === $i ? $type.$line : $lineIndentation.$line;
  47350. }
  47351. $line = $prefix.$line;
  47352. $line .= str_repeat(' ', $this->lineLength - Helper::strlenWithoutDecoration($this->getFormatter(), $line));
  47353. if ($style) {
  47354. $line = sprintf('<%s>%s</>', $style, $line);
  47355. }
  47356. }
  47357. return $lines;
  47358. }
  47359. }
  47360. <?php
  47361. namespace Symfony\Component\Console\Style;
  47362. use Symfony\Component\Console\Formatter\OutputFormatterInterface;
  47363. use Symfony\Component\Console\Helper\ProgressBar;
  47364. use Symfony\Component\Console\Output\ConsoleOutputInterface;
  47365. use Symfony\Component\Console\Output\OutputInterface;
  47366. abstract class OutputStyle implements OutputInterface, StyleInterface
  47367. {
  47368. private $output;
  47369. public function __construct(OutputInterface $output)
  47370. {
  47371. $this->output = $output;
  47372. }
  47373. public function newLine($count = 1)
  47374. {
  47375. $this->output->write(str_repeat(PHP_EOL, $count));
  47376. }
  47377. public function createProgressBar($max = 0)
  47378. {
  47379. return new ProgressBar($this->output, $max);
  47380. }
  47381. public function write($messages, $newline = false, $type = self::OUTPUT_NORMAL)
  47382. {
  47383. $this->output->write($messages, $newline, $type);
  47384. }
  47385. public function writeln($messages, $type = self::OUTPUT_NORMAL)
  47386. {
  47387. $this->output->writeln($messages, $type);
  47388. }
  47389. public function setVerbosity($level)
  47390. {
  47391. $this->output->setVerbosity($level);
  47392. }
  47393. public function getVerbosity()
  47394. {
  47395. return $this->output->getVerbosity();
  47396. }
  47397. public function setDecorated($decorated)
  47398. {
  47399. $this->output->setDecorated($decorated);
  47400. }
  47401. public function isDecorated()
  47402. {
  47403. return $this->output->isDecorated();
  47404. }
  47405. public function setFormatter(OutputFormatterInterface $formatter)
  47406. {
  47407. $this->output->setFormatter($formatter);
  47408. }
  47409. public function getFormatter()
  47410. {
  47411. return $this->output->getFormatter();
  47412. }
  47413. public function isQuiet()
  47414. {
  47415. return $this->output->isQuiet();
  47416. }
  47417. public function isVerbose()
  47418. {
  47419. return $this->output->isVerbose();
  47420. }
  47421. public function isVeryVerbose()
  47422. {
  47423. return $this->output->isVeryVerbose();
  47424. }
  47425. public function isDebug()
  47426. {
  47427. return $this->output->isDebug();
  47428. }
  47429. protected function getErrorOutput()
  47430. {
  47431. if (!$this->output instanceof ConsoleOutputInterface) {
  47432. return $this->output;
  47433. }
  47434. return $this->output->getErrorOutput();
  47435. }
  47436. }
  47437. <?php
  47438. namespace Symfony\Component\Console\Logger;
  47439. use Psr\Log\AbstractLogger;
  47440. use Psr\Log\InvalidArgumentException;
  47441. use Psr\Log\LogLevel;
  47442. use Symfony\Component\Console\Output\ConsoleOutputInterface;
  47443. use Symfony\Component\Console\Output\OutputInterface;
  47444. class ConsoleLogger extends AbstractLogger
  47445. {
  47446. const INFO = 'info';
  47447. const ERROR = 'error';
  47448. private $output;
  47449. private $verbosityLevelMap = [
  47450. LogLevel::EMERGENCY => OutputInterface::VERBOSITY_NORMAL,
  47451. LogLevel::ALERT => OutputInterface::VERBOSITY_NORMAL,
  47452. LogLevel::CRITICAL => OutputInterface::VERBOSITY_NORMAL,
  47453. LogLevel::ERROR => OutputInterface::VERBOSITY_NORMAL,
  47454. LogLevel::WARNING => OutputInterface::VERBOSITY_NORMAL,
  47455. LogLevel::NOTICE => OutputInterface::VERBOSITY_VERBOSE,
  47456. LogLevel::INFO => OutputInterface::VERBOSITY_VERY_VERBOSE,
  47457. LogLevel::DEBUG => OutputInterface::VERBOSITY_DEBUG,
  47458. ];
  47459. private $formatLevelMap = [
  47460. LogLevel::EMERGENCY => self::ERROR,
  47461. LogLevel::ALERT => self::ERROR,
  47462. LogLevel::CRITICAL => self::ERROR,
  47463. LogLevel::ERROR => self::ERROR,
  47464. LogLevel::WARNING => self::INFO,
  47465. LogLevel::NOTICE => self::INFO,
  47466. LogLevel::INFO => self::INFO,
  47467. LogLevel::DEBUG => self::INFO,
  47468. ];
  47469. private $errored = false;
  47470. public function __construct(OutputInterface $output, array $verbosityLevelMap = [], array $formatLevelMap = [])
  47471. {
  47472. $this->output = $output;
  47473. $this->verbosityLevelMap = $verbosityLevelMap + $this->verbosityLevelMap;
  47474. $this->formatLevelMap = $formatLevelMap + $this->formatLevelMap;
  47475. }
  47476. public function log($level, $message, array $context = [])
  47477. {
  47478. if (!isset($this->verbosityLevelMap[$level])) {
  47479. throw new InvalidArgumentException(sprintf('The log level "%s" does not exist.', $level));
  47480. }
  47481. $output = $this->output;
  47482. if (self::ERROR === $this->formatLevelMap[$level]) {
  47483. if ($this->output instanceof ConsoleOutputInterface) {
  47484. $output = $output->getErrorOutput();
  47485. }
  47486. $this->errored = true;
  47487. }
  47488. if ($output->getVerbosity() >= $this->verbosityLevelMap[$level]) {
  47489. $output->writeln(sprintf('<%1$s>[%2$s] %3$s</%1$s>', $this->formatLevelMap[$level], $level, $this->interpolate($message, $context)), $this->verbosityLevelMap[$level]);
  47490. }
  47491. }
  47492. public function hasErrored()
  47493. {
  47494. return $this->errored;
  47495. }
  47496. private function interpolate($message, array $context)
  47497. {
  47498. if (false === strpos($message, '{')) {
  47499. return $message;
  47500. }
  47501. $replacements = [];
  47502. foreach ($context as $key => $val) {
  47503. if (null === $val || is_scalar($val) || (\is_object($val) && method_exists($val, '__toString'))) {
  47504. $replacements["{{$key}}"] = $val;
  47505. } elseif ($val instanceof \DateTimeInterface) {
  47506. $replacements["{{$key}}"] = $val->format(\DateTime::RFC3339);
  47507. } elseif (\is_object($val)) {
  47508. $replacements["{{$key}}"] = '[object '.\get_class($val).']';
  47509. } else {
  47510. $replacements["{{$key}}"] = '['.\gettype($val).']';
  47511. }
  47512. }
  47513. return strtr($message, $replacements);
  47514. }
  47515. }
  47516. <?php
  47517. namespace Symfony\Component\Console;
  47518. final class ConsoleEvents
  47519. {
  47520. /**
  47521. @Event("Symfony\Component\Console\Event\ConsoleCommandEvent")
  47522. */
  47523. const COMMAND = 'console.command';
  47524. /**
  47525. @Event("Symfony\Component\Console\Event\ConsoleTerminateEvent")
  47526. */
  47527. const TERMINATE = 'console.terminate';
  47528. /**
  47529. @Event("Symfony\Component\Console\Event\ConsoleExceptionEvent")
  47530. */
  47531. const EXCEPTION = 'console.exception';
  47532. /**
  47533. @Event("Symfony\Component\Console\Event\ConsoleErrorEvent")
  47534. */
  47535. const ERROR = 'console.error';
  47536. }
  47537. <?php
  47538. namespace Symfony\Component\Console\CommandLoader;
  47539. use Psr\Container\ContainerInterface;
  47540. use Symfony\Component\Console\Exception\CommandNotFoundException;
  47541. class ContainerCommandLoader implements CommandLoaderInterface
  47542. {
  47543. private $container;
  47544. private $commandMap;
  47545. public function __construct(ContainerInterface $container, array $commandMap)
  47546. {
  47547. $this->container = $container;
  47548. $this->commandMap = $commandMap;
  47549. }
  47550. public function get($name)
  47551. {
  47552. if (!$this->has($name)) {
  47553. throw new CommandNotFoundException(sprintf('Command "%s" does not exist.', $name));
  47554. }
  47555. return $this->container->get($this->commandMap[$name]);
  47556. }
  47557. public function has($name)
  47558. {
  47559. return isset($this->commandMap[$name]) && $this->container->has($this->commandMap[$name]);
  47560. }
  47561. public function getNames()
  47562. {
  47563. return array_keys($this->commandMap);
  47564. }
  47565. }
  47566. <?php
  47567. namespace Symfony\Component\Console\CommandLoader;
  47568. use Symfony\Component\Console\Command\Command;
  47569. use Symfony\Component\Console\Exception\CommandNotFoundException;
  47570. interface CommandLoaderInterface
  47571. {
  47572. public function get($name);
  47573. public function has($name);
  47574. public function getNames();
  47575. }
  47576. <?php
  47577. namespace Symfony\Component\Console\CommandLoader;
  47578. use Symfony\Component\Console\Exception\CommandNotFoundException;
  47579. class FactoryCommandLoader implements CommandLoaderInterface
  47580. {
  47581. private $factories;
  47582. public function __construct(array $factories)
  47583. {
  47584. $this->factories = $factories;
  47585. }
  47586. public function has($name)
  47587. {
  47588. return isset($this->factories[$name]);
  47589. }
  47590. public function get($name)
  47591. {
  47592. if (!isset($this->factories[$name])) {
  47593. throw new CommandNotFoundException(sprintf('Command "%s" does not exist.', $name));
  47594. }
  47595. $factory = $this->factories[$name];
  47596. return $factory();
  47597. }
  47598. public function getNames()
  47599. {
  47600. return array_keys($this->factories);
  47601. }
  47602. }
  47603. <?php
  47604. namespace Symfony\Component\Console\EventListener;
  47605. use Psr\Log\LoggerInterface;
  47606. use Symfony\Component\Console\ConsoleEvents;
  47607. use Symfony\Component\Console\Event\ConsoleErrorEvent;
  47608. use Symfony\Component\Console\Event\ConsoleEvent;
  47609. use Symfony\Component\Console\Event\ConsoleTerminateEvent;
  47610. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  47611. /**
  47612. @gmail
  47613. */
  47614. class ErrorListener implements EventSubscriberInterface
  47615. {
  47616. private $logger;
  47617. public function __construct(LoggerInterface $logger = null)
  47618. {
  47619. $this->logger = $logger;
  47620. }
  47621. public function onConsoleError(ConsoleErrorEvent $event)
  47622. {
  47623. if (null === $this->logger) {
  47624. return;
  47625. }
  47626. $error = $event->getError();
  47627. if (!$inputString = $this->getInputString($event)) {
  47628. $this->logger->error('An error occurred while using the console. Message: "{message}"', ['exception' => $error, 'message' => $error->getMessage()]);
  47629. return;
  47630. }
  47631. $this->logger->error('Error thrown while running command "{command}". Message: "{message}"', ['exception' => $error, 'command' => $inputString, 'message' => $error->getMessage()]);
  47632. }
  47633. public function onConsoleTerminate(ConsoleTerminateEvent $event)
  47634. {
  47635. if (null === $this->logger) {
  47636. return;
  47637. }
  47638. $exitCode = $event->getExitCode();
  47639. if (0 === $exitCode) {
  47640. return;
  47641. }
  47642. if (!$inputString = $this->getInputString($event)) {
  47643. $this->logger->debug('The console exited with code "{code}"', ['code' => $exitCode]);
  47644. return;
  47645. }
  47646. $this->logger->debug('Command "{command}" exited with code "{code}"', ['command' => $inputString, 'code' => $exitCode]);
  47647. }
  47648. public static function getSubscribedEvents()
  47649. {
  47650. return [
  47651. ConsoleEvents::ERROR => ['onConsoleError', -128],
  47652. ConsoleEvents::TERMINATE => ['onConsoleTerminate', -128],
  47653. ];
  47654. }
  47655. private static function getInputString(ConsoleEvent $event)
  47656. {
  47657. $commandName = $event->getCommand() ? $event->getCommand()->getName() : null;
  47658. $input = $event->getInput();
  47659. if (method_exists($input, '__toString')) {
  47660. if ($commandName) {
  47661. return str_replace(["'$commandName'", "\"$commandName\""], $commandName, (string) $input);
  47662. }
  47663. return (string) $input;
  47664. }
  47665. return $commandName;
  47666. }
  47667. }
  47668. <?php
  47669. namespace Symfony\Component\Debug;
  47670. use Psr\Log\LoggerInterface;
  47671. use Psr\Log\LogLevel;
  47672. use Symfony\Component\Debug\Exception\ContextErrorException;
  47673. use Symfony\Component\Debug\Exception\FatalErrorException;
  47674. use Symfony\Component\Debug\Exception\FatalThrowableError;
  47675. use Symfony\Component\Debug\Exception\OutOfMemoryException;
  47676. use Symfony\Component\Debug\Exception\SilencedErrorContext;
  47677. use Symfony\Component\Debug\FatalErrorHandler\ClassNotFoundFatalErrorHandler;
  47678. use Symfony\Component\Debug\FatalErrorHandler\FatalErrorHandlerInterface;
  47679. use Symfony\Component\Debug\FatalErrorHandler\UndefinedFunctionFatalErrorHandler;
  47680. use Symfony\Component\Debug\FatalErrorHandler\UndefinedMethodFatalErrorHandler;
  47681. /**
  47682. * A generic ErrorHandler for the PHP engine.
  47683. *
  47684. * Provides five bit fields that control how errors are handled:
  47685. * - thrownErrors: errors thrown as \ErrorException
  47686. * - loggedErrors: logged errors, when not @-silenced
  47687. * - scopedErrors: errors thrown or logged with their local context
  47688. * - tracedErrors: errors logged with their stack trace
  47689. * - screamedErrors: never @-silenced errors
  47690. *
  47691. * Each error level can be logged by a dedicated PSR-3 logger object.
  47692. * Screaming only applies to logging.
  47693. * Throwing takes precedence over logging.
  47694. * Uncaught exceptions are logged as E_ERROR.
  47695. * E_DEPRECATED and E_USER_DEPRECATED levels never throw.
  47696. * E_RECOVERABLE_ERROR and E_USER_ERROR levels always throw.
  47697. * Non catchable errors that can be detected at shutdown time are logged when the scream bit field allows so.
  47698. * As errors have a performance cost, repeated errors are all logged, so that the developer
  47699. * can see them and weight them as more important to fix than others of the same level.
  47700. *
  47701. * @author Nicolas Grekas <p@tchwork.com>
  47702. * @author Grégoire Pineau <lyrixx@lyrixx.info>
  47703. */
  47704. class ErrorHandler
  47705. {
  47706. private $levels = [
  47707. E_DEPRECATED => 'Deprecated',
  47708. E_USER_DEPRECATED => 'User Deprecated',
  47709. E_NOTICE => 'Notice',
  47710. E_USER_NOTICE => 'User Notice',
  47711. E_STRICT => 'Runtime Notice',
  47712. E_WARNING => 'Warning',
  47713. E_USER_WARNING => 'User Warning',
  47714. E_COMPILE_WARNING => 'Compile Warning',
  47715. E_CORE_WARNING => 'Core Warning',
  47716. E_USER_ERROR => 'User Error',
  47717. E_RECOVERABLE_ERROR => 'Catchable Fatal Error',
  47718. E_COMPILE_ERROR => 'Compile Error',
  47719. E_PARSE => 'Parse Error',
  47720. E_ERROR => 'Error',
  47721. E_CORE_ERROR => 'Core Error',
  47722. ];
  47723. private $loggers = [
  47724. E_DEPRECATED => [null, LogLevel::INFO],
  47725. E_USER_DEPRECATED => [null, LogLevel::INFO],
  47726. E_NOTICE => [null, LogLevel::WARNING],
  47727. E_USER_NOTICE => [null, LogLevel::WARNING],
  47728. E_STRICT => [null, LogLevel::WARNING],
  47729. E_WARNING => [null, LogLevel::WARNING],
  47730. E_USER_WARNING => [null, LogLevel::WARNING],
  47731. E_COMPILE_WARNING => [null, LogLevel::WARNING],
  47732. E_CORE_WARNING => [null, LogLevel::WARNING],
  47733. E_USER_ERROR => [null, LogLevel::CRITICAL],
  47734. E_RECOVERABLE_ERROR => [null, LogLevel::CRITICAL],
  47735. E_COMPILE_ERROR => [null, LogLevel::CRITICAL],
  47736. E_PARSE => [null, LogLevel::CRITICAL],
  47737. E_ERROR => [null, LogLevel::CRITICAL],
  47738. E_CORE_ERROR => [null, LogLevel::CRITICAL],
  47739. ];
  47740. private $thrownErrors = 0x1FFF;
  47741. private $scopedErrors = 0x1FFF;
  47742. private $tracedErrors = 0x77FB;
  47743. private $screamedErrors = 0x55;
  47744. private $loggedErrors = 0;
  47745. private $traceReflector;
  47746. private $isRecursive = 0;
  47747. private $isRoot = false;
  47748. private $exceptionHandler;
  47749. private $bootstrappingLogger;
  47750. private static $reservedMemory;
  47751. private static $stackedErrors = [];
  47752. private static $stackedErrorLevels = [];
  47753. private static $toStringException = null;
  47754. private static $silencedErrorCache = [];
  47755. private static $silencedErrorCount = 0;
  47756. private static $exitCode = 0;
  47757. public static function register(self $handler = null, $replace = true)
  47758. {
  47759. if (null === self::$reservedMemory) {
  47760. self::$reservedMemory = str_repeat('x', 10240);
  47761. register_shutdown_function(__CLASS__.'::handleFatalError');
  47762. }
  47763. if ($handlerIsNew = null === $handler) {
  47764. $handler = new static();
  47765. }
  47766. if (null === $prev = set_error_handler([$handler, 'handleError'])) {
  47767. restore_error_handler();
  47768. set_error_handler([$handler, 'handleError'], $handler->thrownErrors | $handler->loggedErrors);
  47769. $handler->isRoot = true;
  47770. }
  47771. if ($handlerIsNew && \is_array($prev) && $prev[0] instanceof self) {
  47772. $handler = $prev[0];
  47773. $replace = false;
  47774. }
  47775. if (!$replace && $prev) {
  47776. restore_error_handler();
  47777. $handlerIsRegistered = \is_array($prev) && $handler === $prev[0];
  47778. } else {
  47779. $handlerIsRegistered = true;
  47780. }
  47781. if (\is_array($prev = set_exception_handler([$handler, 'handleException'])) && $prev[0] instanceof self) {
  47782. restore_exception_handler();
  47783. if (!$handlerIsRegistered) {
  47784. $handler = $prev[0];
  47785. } elseif ($handler !== $prev[0] && $replace) {
  47786. set_exception_handler([$handler, 'handleException']);
  47787. $p = $prev[0]->setExceptionHandler(null);
  47788. $handler->setExceptionHandler($p);
  47789. $prev[0]->setExceptionHandler($p);
  47790. }
  47791. } else {
  47792. $handler->setExceptionHandler($prev);
  47793. }
  47794. $handler->throwAt(E_ALL & $handler->thrownErrors, true);
  47795. return $handler;
  47796. }
  47797. public function __construct(BufferingLogger $bootstrappingLogger = null)
  47798. {
  47799. if ($bootstrappingLogger) {
  47800. $this->bootstrappingLogger = $bootstrappingLogger;
  47801. $this->setDefaultLogger($bootstrappingLogger);
  47802. }
  47803. $this->traceReflector = new \ReflectionProperty('Exception', 'trace');
  47804. $this->traceReflector->setAccessible(true);
  47805. }
  47806. public function setDefaultLogger(LoggerInterface $logger, $levels = E_ALL, $replace = false)
  47807. {
  47808. $loggers = [];
  47809. if (\is_array($levels)) {
  47810. foreach ($levels as $type => $logLevel) {
  47811. if (empty($this->loggers[$type][0]) || $replace || $this->loggers[$type][0] === $this->bootstrappingLogger) {
  47812. $loggers[$type] = [$logger, $logLevel];
  47813. }
  47814. }
  47815. } else {
  47816. if (null === $levels) {
  47817. $levels = E_ALL;
  47818. }
  47819. foreach ($this->loggers as $type => $log) {
  47820. if (($type & $levels) && (empty($log[0]) || $replace || $log[0] === $this->bootstrappingLogger)) {
  47821. $log[0] = $logger;
  47822. $loggers[$type] = $log;
  47823. }
  47824. }
  47825. }
  47826. $this->setLoggers($loggers);
  47827. }
  47828. public function setLoggers(array $loggers)
  47829. {
  47830. $prevLogged = $this->loggedErrors;
  47831. $prev = $this->loggers;
  47832. $flush = [];
  47833. foreach ($loggers as $type => $log) {
  47834. if (!isset($prev[$type])) {
  47835. throw new \InvalidArgumentException('Unknown error type: '.$type);
  47836. }
  47837. if (!\is_array($log)) {
  47838. $log = [$log];
  47839. } elseif (!\array_key_exists(0, $log)) {
  47840. throw new \InvalidArgumentException('No logger provided.');
  47841. }
  47842. if (null === $log[0]) {
  47843. $this->loggedErrors &= ~$type;
  47844. } elseif ($log[0] instanceof LoggerInterface) {
  47845. $this->loggedErrors |= $type;
  47846. } else {
  47847. throw new \InvalidArgumentException('Invalid logger provided.');
  47848. }
  47849. $this->loggers[$type] = $log + $prev[$type];
  47850. if ($this->bootstrappingLogger && $prev[$type][0] === $this->bootstrappingLogger) {
  47851. $flush[$type] = $type;
  47852. }
  47853. }
  47854. $this->reRegister($prevLogged | $this->thrownErrors);
  47855. if ($flush) {
  47856. foreach ($this->bootstrappingLogger->cleanLogs() as $log) {
  47857. $type = $log[2]['exception'] instanceof \ErrorException ? $log[2]['exception']->getSeverity() : E_ERROR;
  47858. if (!isset($flush[$type])) {
  47859. $this->bootstrappingLogger->log($log[0], $log[1], $log[2]);
  47860. } elseif ($this->loggers[$type][0]) {
  47861. $this->loggers[$type][0]->log($this->loggers[$type][1], $log[1], $log[2]);
  47862. }
  47863. }
  47864. }
  47865. return $prev;
  47866. }
  47867. public function setExceptionHandler(callable $handler = null)
  47868. {
  47869. $prev = $this->exceptionHandler;
  47870. $this->exceptionHandler = $handler;
  47871. return $prev;
  47872. }
  47873. public function throwAt($levels, $replace = false)
  47874. {
  47875. $prev = $this->thrownErrors;
  47876. $this->thrownErrors = ($levels | E_RECOVERABLE_ERROR | E_USER_ERROR) & ~E_USER_DEPRECATED & ~E_DEPRECATED;
  47877. if (!$replace) {
  47878. $this->thrownErrors |= $prev;
  47879. }
  47880. $this->reRegister($prev | $this->loggedErrors);
  47881. return $prev;
  47882. }
  47883. public function scopeAt($levels, $replace = false)
  47884. {
  47885. $prev = $this->scopedErrors;
  47886. $this->scopedErrors = (int) $levels;
  47887. if (!$replace) {
  47888. $this->scopedErrors |= $prev;
  47889. }
  47890. return $prev;
  47891. }
  47892. public function traceAt($levels, $replace = false)
  47893. {
  47894. $prev = $this->tracedErrors;
  47895. $this->tracedErrors = (int) $levels;
  47896. if (!$replace) {
  47897. $this->tracedErrors |= $prev;
  47898. }
  47899. return $prev;
  47900. }
  47901. /**
  47902. * Sets the error levels where the @-operator is ignored.
  47903. *
  47904. * @param int $levels A bit field of E_* constants for screamed errors
  47905. * @param bool $replace Replace or amend the previous value
  47906. *
  47907. * @return int The previous value
  47908. */
  47909. public function screamAt($levels, $replace = false)
  47910. {
  47911. $prev = $this->screamedErrors;
  47912. $this->screamedErrors = (int) $levels;
  47913. if (!$replace) {
  47914. $this->screamedErrors |= $prev;
  47915. }
  47916. return $prev;
  47917. }
  47918. private function reRegister($prev)
  47919. {
  47920. if ($prev !== $this->thrownErrors | $this->loggedErrors) {
  47921. $handler = set_error_handler('var_dump');
  47922. $handler = \is_array($handler) ? $handler[0] : null;
  47923. restore_error_handler();
  47924. if ($handler === $this) {
  47925. restore_error_handler();
  47926. if ($this->isRoot) {
  47927. set_error_handler([$this, 'handleError'], $this->thrownErrors | $this->loggedErrors);
  47928. } else {
  47929. set_error_handler([$this, 'handleError']);
  47930. }
  47931. }
  47932. }
  47933. }
  47934. public function handleError($type, $message, $file, $line)
  47935. {
  47936. if (\PHP_VERSION_ID >= 70300 && E_WARNING === $type && '"' === $message[0] && false !== strpos($message, '" targeting switch is equivalent to "break')) {
  47937. $type = E_DEPRECATED;
  47938. }
  47939. $level = error_reporting();
  47940. $silenced = 0 === ($level & $type);
  47941. $level |= E_RECOVERABLE_ERROR | E_USER_ERROR | E_DEPRECATED | E_USER_DEPRECATED;
  47942. $log = $this->loggedErrors & $type;
  47943. $throw = $this->thrownErrors & $type & $level;
  47944. $type &= $level | $this->screamedErrors;
  47945. if (!$type || (!$log && !$throw)) {
  47946. return !$silenced && $type && $log;
  47947. }
  47948. $scope = $this->scopedErrors & $type;
  47949. if (4 < $numArgs = \func_num_args()) {
  47950. $context = $scope ? (func_get_arg(4) ?: []) : [];
  47951. $backtrace = 5 < $numArgs ? func_get_arg(5) : null;
  47952. } else {
  47953. $context = [];
  47954. $backtrace = null;
  47955. }
  47956. if (isset($context['GLOBALS']) && $scope) {
  47957. $e = $context;
  47958. unset($e['GLOBALS'], $context);
  47959. $context = $e;
  47960. }
  47961. if (null !== $backtrace && $type & E_ERROR) {
  47962. $this->handleFatalError(compact('type', 'message', 'file', 'line', 'backtrace'));
  47963. return true;
  47964. }
  47965. $logMessage = $this->levels[$type].': '.$message;
  47966. if (null !== self::$toStringException) {
  47967. $errorAsException = self::$toStringException;
  47968. self::$toStringException = null;
  47969. } elseif (!$throw && !($type & $level)) {
  47970. if (!isset(self::$silencedErrorCache[$id = $file.':'.$line])) {
  47971. $lightTrace = $this->tracedErrors & $type ? $this->cleanTrace(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 3), $type, $file, $line, false) : [];
  47972. $errorAsException = new SilencedErrorContext($type, $file, $line, $lightTrace);
  47973. } elseif (isset(self::$silencedErrorCache[$id][$message])) {
  47974. $lightTrace = null;
  47975. $errorAsException = self::$silencedErrorCache[$id][$message];
  47976. ++$errorAsException->count;
  47977. } else {
  47978. $lightTrace = [];
  47979. $errorAsException = null;
  47980. }
  47981. if (100 < ++self::$silencedErrorCount) {
  47982. self::$silencedErrorCache = $lightTrace = [];
  47983. self::$silencedErrorCount = 1;
  47984. }
  47985. if ($errorAsException) {
  47986. self::$silencedErrorCache[$id][$message] = $errorAsException;
  47987. }
  47988. if (null === $lightTrace) {
  47989. return true;
  47990. }
  47991. } else {
  47992. if ($scope) {
  47993. $errorAsException = new ContextErrorException($logMessage, 0, $type, $file, $line, $context);
  47994. } else {
  47995. $errorAsException = new \ErrorException($logMessage, 0, $type, $file, $line);
  47996. }
  47997. if ($throw || $this->tracedErrors & $type) {
  47998. $backtrace = $backtrace ?: $errorAsException->getTrace();
  47999. $lightTrace = $this->cleanTrace($backtrace, $type, $file, $line, $throw);
  48000. $this->traceReflector->setValue($errorAsException, $lightTrace);
  48001. } else {
  48002. $this->traceReflector->setValue($errorAsException, []);
  48003. }
  48004. }
  48005. if ($throw) {
  48006. if (\PHP_VERSION_ID < 70400 && E_USER_ERROR & $type) {
  48007. for ($i = 1; isset($backtrace[$i]); ++$i) {
  48008. if (isset($backtrace[$i]['function'], $backtrace[$i]['type'], $backtrace[$i - 1]['function'])
  48009. && '__toString' === $backtrace[$i]['function']
  48010. && '->' === $backtrace[$i]['type']
  48011. && !isset($backtrace[$i - 1]['class'])
  48012. && ('trigger_error' === $backtrace[$i - 1]['function'] || 'user_error' === $backtrace[$i - 1]['function'])
  48013. ) {
  48014. foreach ($context as $e) {
  48015. if (($e instanceof \Exception || $e instanceof \Throwable) && $e->__toString() === $message) {
  48016. if (1 === $i) {
  48017. $errorAsException = $e;
  48018. break;
  48019. }
  48020. self::$toStringException = $e;
  48021. return true;
  48022. }
  48023. }
  48024. if (1 < $i) {
  48025. $this->handleException($errorAsException);
  48026. return false;
  48027. }
  48028. }
  48029. }
  48030. }
  48031. throw $errorAsException;
  48032. }
  48033. if ($this->isRecursive) {
  48034. $log = 0;
  48035. } elseif (self::$stackedErrorLevels) {
  48036. self::$stackedErrors[] = [
  48037. $this->loggers[$type][0],
  48038. ($type & $level) ? $this->loggers[$type][1] : LogLevel::DEBUG,
  48039. $logMessage,
  48040. $errorAsException ? ['exception' => $errorAsException] : [],
  48041. ];
  48042. } else {
  48043. if (\PHP_VERSION_ID < (\PHP_VERSION_ID < 70400 ? 70316 : 70404) && !\defined('HHVM_VERSION')) {
  48044. $currentErrorHandler = set_error_handler('var_dump');
  48045. restore_error_handler();
  48046. }
  48047. try {
  48048. $this->isRecursive = true;
  48049. $level = ($type & $level) ? $this->loggers[$type][1] : LogLevel::DEBUG;
  48050. $this->loggers[$type][0]->log($level, $logMessage, $errorAsException ? ['exception' => $errorAsException] : []);
  48051. } finally {
  48052. $this->isRecursive = false;
  48053. if (\PHP_VERSION_ID < (\PHP_VERSION_ID < 70400 ? 70316 : 70404) && !\defined('HHVM_VERSION')) {
  48054. set_error_handler($currentErrorHandler);
  48055. }
  48056. }
  48057. }
  48058. return !$silenced && $type && $log;
  48059. }
  48060. public function handleException($exception, array $error = null)
  48061. {
  48062. if (null === $error) {
  48063. self::$exitCode = 255;
  48064. }
  48065. if (!$exception instanceof \Exception) {
  48066. $exception = new FatalThrowableError($exception);
  48067. }
  48068. $type = $exception instanceof FatalErrorException ? $exception->getSeverity() : E_ERROR;
  48069. $handlerException = null;
  48070. if (($this->loggedErrors & $type) || $exception instanceof FatalThrowableError) {
  48071. if ($exception instanceof FatalErrorException) {
  48072. if ($exception instanceof FatalThrowableError) {
  48073. $error = [
  48074. 'type' => $type,
  48075. 'message' => $message = $exception->getMessage(),
  48076. 'file' => $exception->getFile(),
  48077. 'line' => $exception->getLine(),
  48078. ];
  48079. } else {
  48080. $message = 'Fatal '.$exception->getMessage();
  48081. }
  48082. } elseif ($exception instanceof \ErrorException) {
  48083. $message = 'Uncaught '.$exception->getMessage();
  48084. } else {
  48085. $message = 'Uncaught Exception: '.$exception->getMessage();
  48086. }
  48087. }
  48088. if ($this->loggedErrors & $type) {
  48089. try {
  48090. $this->loggers[$type][0]->log($this->loggers[$type][1], $message, ['exception' => $exception]);
  48091. } catch (\Exception $handlerException) {
  48092. } catch (\Throwable $handlerException) {
  48093. }
  48094. }
  48095. if ($exception instanceof FatalErrorException && !$exception instanceof OutOfMemoryException && $error) {
  48096. foreach ($this->getFatalErrorHandlers() as $handler) {
  48097. if ($e = $handler->handleError($error, $exception)) {
  48098. $exception = $e;
  48099. break;
  48100. }
  48101. }
  48102. }
  48103. $exceptionHandler = $this->exceptionHandler;
  48104. $this->exceptionHandler = null;
  48105. try {
  48106. if (null !== $exceptionHandler) {
  48107. $exceptionHandler($exception);
  48108. return;
  48109. }
  48110. $handlerException = $handlerException ?: $exception;
  48111. } catch (\Exception $handlerException) {
  48112. } catch (\Throwable $handlerException) {
  48113. }
  48114. if ($exception === $handlerException) {
  48115. self::$reservedMemory = null;
  48116. throw $exception;
  48117. }
  48118. $this->handleException($handlerException);
  48119. }
  48120. public static function handleFatalError(array $error = null)
  48121. {
  48122. if (null === self::$reservedMemory) {
  48123. return;
  48124. }
  48125. $handler = self::$reservedMemory = null;
  48126. $handlers = [];
  48127. $previousHandler = null;
  48128. $sameHandlerLimit = 10;
  48129. while (!\is_array($handler) || !$handler[0] instanceof self) {
  48130. $handler = set_exception_handler('var_dump');
  48131. restore_exception_handler();
  48132. if (!$handler) {
  48133. break;
  48134. }
  48135. restore_exception_handler();
  48136. if ($handler !== $previousHandler) {
  48137. array_unshift($handlers, $handler);
  48138. $previousHandler = $handler;
  48139. } elseif (0 === --$sameHandlerLimit) {
  48140. $handler = null;
  48141. break;
  48142. }
  48143. }
  48144. foreach ($handlers as $h) {
  48145. set_exception_handler($h);
  48146. }
  48147. if (!$handler) {
  48148. return;
  48149. }
  48150. if ($handler !== $h) {
  48151. $handler[0]->setExceptionHandler($h);
  48152. }
  48153. $handler = $handler[0];
  48154. $handlers = [];
  48155. if ($exit = null === $error) {
  48156. $error = error_get_last();
  48157. }
  48158. try {
  48159. while (self::$stackedErrorLevels) {
  48160. static::unstackErrors();
  48161. }
  48162. } catch (\Exception $exception) {
  48163. } catch (\Throwable $exception) {
  48164. }
  48165. if ($error && $error['type'] &= E_PARSE | E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR) {
  48166. $handler->throwAt(0, true);
  48167. $trace = isset($error['backtrace']) ? $error['backtrace'] : null;
  48168. if (0 === strpos($error['message'], 'Allowed memory') || 0 === strpos($error['message'], 'Out of memory')) {
  48169. $exception = new OutOfMemoryException($handler->levels[$error['type']].': '.$error['message'], 0, $error['type'], $error['file'], $error['line'], 2, false, $trace);
  48170. } else {
  48171. $exception = new FatalErrorException($handler->levels[$error['type']].': '.$error['message'], 0, $error['type'], $error['file'], $error['line'], 2, true, $trace);
  48172. }
  48173. }
  48174. try {
  48175. if (isset($exception)) {
  48176. self::$exitCode = 255;
  48177. $handler->handleException($exception, $error);
  48178. }
  48179. } catch (FatalErrorException $e) {
  48180. }
  48181. if ($exit && self::$exitCode) {
  48182. $exitCode = self::$exitCode;
  48183. register_shutdown_function('register_shutdown_function', function () use ($exitCode) { exit($exitCode); });
  48184. }
  48185. }
  48186. public static function stackErrors()
  48187. {
  48188. @trigger_error('Support for stacking errors is deprecated since Symfony 3.4 and will be removed in 4.0.', E_USER_DEPRECATED);
  48189. self::$stackedErrorLevels[] = error_reporting(error_reporting() | E_PARSE | E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR);
  48190. }
  48191. public static function unstackErrors()
  48192. {
  48193. @trigger_error('Support for unstacking errors is deprecated since Symfony 3.4 and will be removed in 4.0.', E_USER_DEPRECATED);
  48194. $level = array_pop(self::$stackedErrorLevels);
  48195. if (null !== $level) {
  48196. $errorReportingLevel = error_reporting($level);
  48197. if ($errorReportingLevel !== ($level | E_PARSE | E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR)) {
  48198. error_reporting($errorReportingLevel);
  48199. }
  48200. }
  48201. if (empty(self::$stackedErrorLevels)) {
  48202. $errors = self::$stackedErrors;
  48203. self::$stackedErrors = [];
  48204. foreach ($errors as $error) {
  48205. $error[0]->log($error[1], $error[2], $error[3]);
  48206. }
  48207. }
  48208. }
  48209. protected function getFatalErrorHandlers()
  48210. {
  48211. return [
  48212. new UndefinedFunctionFatalErrorHandler(),
  48213. new UndefinedMethodFatalErrorHandler(),
  48214. new ClassNotFoundFatalErrorHandler(),
  48215. ];
  48216. }
  48217. private function cleanTrace($backtrace, $type, $file, $line, $throw)
  48218. {
  48219. $lightTrace = $backtrace;
  48220. for ($i = 0; isset($backtrace[$i]); ++$i) {
  48221. if (isset($backtrace[$i]['file'], $backtrace[$i]['line']) && $backtrace[$i]['line'] === $line && $backtrace[$i]['file'] === $file) {
  48222. $lightTrace = \array_slice($lightTrace, 1 + $i);
  48223. break;
  48224. }
  48225. }
  48226. if (!($throw || $this->scopedErrors & $type)) {
  48227. for ($i = 0; isset($lightTrace[$i]); ++$i) {
  48228. unset($lightTrace[$i]['args'], $lightTrace[$i]['object']);
  48229. }
  48230. }
  48231. return $lightTrace;
  48232. }
  48233. }
  48234. <?php
  48235. namespace Symfony\Component\Debug;
  48236. use Symfony\Component\Debug\Exception\FlattenException;
  48237. use Symfony\Component\Debug\Exception\OutOfMemoryException;
  48238. use Symfony\Component\HttpKernel\Debug\FileLinkFormatter;
  48239. /**
  48240. @tchwork
  48241. */
  48242. class ExceptionHandler
  48243. {
  48244. private $debug;
  48245. private $charset;
  48246. private $handler;
  48247. private $caughtBuffer;
  48248. private $caughtLength;
  48249. private $fileLinkFormat;
  48250. public function __construct($debug = true, $charset = null, $fileLinkFormat = null)
  48251. {
  48252. $this->debug = $debug;
  48253. $this->charset = $charset ?: ini_get('default_charset') ?: 'UTF-8';
  48254. $this->fileLinkFormat = $fileLinkFormat;
  48255. }
  48256. public static function register($debug = true, $charset = null, $fileLinkFormat = null)
  48257. {
  48258. $handler = new static($debug, $charset, $fileLinkFormat);
  48259. $prev = set_exception_handler([$handler, 'handle']);
  48260. if (\is_array($prev) && $prev[0] instanceof ErrorHandler) {
  48261. restore_exception_handler();
  48262. $prev[0]->setExceptionHandler([$handler, 'handle']);
  48263. }
  48264. return $handler;
  48265. }
  48266. public function setHandler(callable $handler = null)
  48267. {
  48268. $old = $this->handler;
  48269. $this->handler = $handler;
  48270. return $old;
  48271. }
  48272. public function setFileLinkFormat($fileLinkFormat)
  48273. {
  48274. $old = $this->fileLinkFormat;
  48275. $this->fileLinkFormat = $fileLinkFormat;
  48276. return $old;
  48277. }
  48278. public function handle(\Exception $exception)
  48279. {
  48280. if (null === $this->handler || $exception instanceof OutOfMemoryException) {
  48281. $this->sendPhpResponse($exception);
  48282. return;
  48283. }
  48284. $caughtLength = $this->caughtLength = 0;
  48285. ob_start(function ($buffer) {
  48286. $this->caughtBuffer = $buffer;
  48287. return '';
  48288. });
  48289. $this->sendPhpResponse($exception);
  48290. while (null === $this->caughtBuffer && ob_end_flush()) {
  48291. }
  48292. if (isset($this->caughtBuffer[0])) {
  48293. ob_start(function ($buffer) {
  48294. if ($this->caughtLength) {
  48295. $cleanBuffer = substr_replace($buffer, '', 0, $this->caughtLength);
  48296. if (isset($cleanBuffer[0])) {
  48297. $buffer = $cleanBuffer;
  48298. }
  48299. }
  48300. return $buffer;
  48301. });
  48302. echo $this->caughtBuffer;
  48303. $caughtLength = ob_get_length();
  48304. }
  48305. $this->caughtBuffer = null;
  48306. try {
  48307. \call_user_func($this->handler, $exception);
  48308. $this->caughtLength = $caughtLength;
  48309. } catch (\Exception $e) {
  48310. if (!$caughtLength) {
  48311. throw $exception;
  48312. }
  48313. }
  48314. }
  48315. public function sendPhpResponse($exception)
  48316. {
  48317. if (!$exception instanceof FlattenException) {
  48318. $exception = FlattenException::create($exception);
  48319. }
  48320. if (!headers_sent()) {
  48321. header(sprintf('HTTP/1.0 %s', $exception->getStatusCode()));
  48322. foreach ($exception->getHeaders() as $name => $value) {
  48323. header($name.': '.$value, false);
  48324. }
  48325. header('Content-Type: text/html; charset='.$this->charset);
  48326. }
  48327. echo $this->decorate($this->getContent($exception), $this->getStylesheet($exception));
  48328. }
  48329. public function getHtml($exception)
  48330. {
  48331. if (!$exception instanceof FlattenException) {
  48332. $exception = FlattenException::create($exception);
  48333. }
  48334. return $this->decorate($this->getContent($exception), $this->getStylesheet($exception));
  48335. }
  48336. public function getContent(FlattenException $exception)
  48337. {
  48338. switch ($exception->getStatusCode()) {
  48339. case 404:
  48340. $title = 'Sorry, the page you are looking for could not be found.';
  48341. break;
  48342. default:
  48343. $title = 'Whoops, looks like something went wrong.';
  48344. }
  48345. if (!$this->debug) {
  48346. return <<<EOF
  48347. <div class="container">
  48348. <h1>$title</h1>
  48349. </div>
  48350. EOF;
  48351. }
  48352. $content = '';
  48353. try {
  48354. $count = \count($exception->getAllPrevious());
  48355. $total = $count + 1;
  48356. foreach ($exception->toArray() as $position => $e) {
  48357. $ind = $count - $position + 1;
  48358. $class = $this->formatClass($e['class']);
  48359. $message = nl2br($this->escapeHtml($e['message']));
  48360. $content .= sprintf(<<<'EOF'
  48361. <div class="trace trace-as-html">
  48362. <table class="trace-details">
  48363. <thead class="trace-head"><tr><th>
  48364. <h3 class="trace-class">
  48365. <span class="text-muted">(%d/%d)</span>
  48366. <span class="exception_title">%s</span>
  48367. </h3>
  48368. <p class="break-long-words trace-message">%s</p>
  48369. </th></tr></thead>
  48370. <tbody>
  48371. EOF
  48372. , $ind, $total, $class, $message);
  48373. foreach ($e['trace'] as $trace) {
  48374. $content .= '<tr><td>';
  48375. if ($trace['function']) {
  48376. $content .= sprintf('at <span class="trace-class">%s</span><span class="trace-type">%s</span><span class="trace-method">%s</span>(<span class="trace-arguments">%s</span>)', $this->formatClass($trace['class']), $trace['type'], $trace['function'], $this->formatArgs($trace['args']));
  48377. }
  48378. if (isset($trace['file']) && isset($trace['line'])) {
  48379. $content .= $this->formatPath($trace['file'], $trace['line']);
  48380. }
  48381. $content .= "</td></tr>\n";
  48382. }
  48383. $content .= "</tbody>\n</table>\n</div>\n";
  48384. }
  48385. } catch (\Exception $e) {
  48386. if ($this->debug) {
  48387. $title = sprintf('Exception thrown when handling an exception (%s: %s)', \get_class($e), $this->escapeHtml($e->getMessage()));
  48388. } else {
  48389. $title = 'Whoops, looks like something went wrong.';
  48390. }
  48391. }
  48392. $symfonyGhostImageContents = $this->getSymfonyGhostAsSvg();
  48393. return <<<EOF
  48394. <div class="exception-summary">
  48395. <div class="container">
  48396. <div class="exception-message-wrapper">
  48397. <h1 class="break-long-words exception-message">$title</h1>
  48398. <div class="exception-illustration hidden-xs-down">$symfonyGhostImageContents</div>
  48399. </div>
  48400. </div>
  48401. </div>
  48402. <div class="container">
  48403. $content
  48404. </div>
  48405. EOF;
  48406. }
  48407. public function getStylesheet(FlattenException $exception)
  48408. {
  48409. if (!$this->debug) {
  48410. return <<<'EOF'
  48411. body { background-color: #fff; color: #222; font: 16px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; margin: 0; }
  48412. .container { margin: 30px; max-width: 600px; }
  48413. h1 { color: #dc3545; font-size: 24px; }
  48414. EOF;
  48415. }
  48416. return <<<'EOF'
  48417. body { background-color: #F9F9F9; color: #222; font: 14px/1.4 Helvetica, Arial, sans-serif; margin: 0; padding-bottom: 45px; }
  48418. a { cursor: pointer; text-decoration: none; }
  48419. a:hover { text-decoration: underline; }
  48420. abbr[title] { border-bottom: none; cursor: help; text-decoration: none; }
  48421. code, pre { font: 13px/1.5 Consolas, Monaco, Menlo, "Ubuntu Mono", "Liberation Mono", monospace; }
  48422. table, tr, th, td { background: #FFF; border-collapse: collapse; vertical-align: top; }
  48423. table { background: #FFF; border: 1px solid #E0E0E0; box-shadow: 0px 0px 1px rgba(128, 128, 128, .2); margin: 1em 0; width: 100%; }
  48424. table th, table td { border: solid #E0E0E0; border-width: 1px 0; padding: 8px 10px; }
  48425. table th { background-color: #E0E0E0; font-weight: bold; text-align: left; }
  48426. .hidden-xs-down { display: none; }
  48427. .block { display: block; }
  48428. .break-long-words { -ms-word-break: break-all; word-break: break-all; word-break: break-word; -webkit-hyphens: auto; -moz-hyphens: auto; hyphens: auto; }
  48429. .text-muted { color: #999; }
  48430. .container { max-width: 1024px; margin: 0 auto; padding: 0 15px; }
  48431. .container::after { content: ""; display: table; clear: both; }
  48432. .exception-summary { background: #B0413E; border-bottom: 2px solid rgba(0, 0, 0, 0.1); border-top: 1px solid rgba(0, 0, 0, .3); flex: 0 0 auto; margin-bottom: 30px; }
  48433. .exception-message-wrapper { display: flex; align-items: center; min-height: 70px; }
  48434. .exception-message { flex-grow: 1; padding: 30px 0; }
  48435. .exception-message, .exception-message a { color: #FFF; font-size: 21px; font-weight: 400; margin: 0; }
  48436. .exception-message.long { font-size: 18px; }
  48437. .exception-message a { border-bottom: 1px solid rgba(255, 255, 255, 0.5); font-size: inherit; text-decoration: none; }
  48438. .exception-message a:hover { border-bottom-color: #ffffff; }
  48439. .exception-illustration { flex-basis: 111px; flex-shrink: 0; height: 66px; margin-left: 15px; opacity: .7; }
  48440. .trace + .trace { margin-top: 30px; }
  48441. .trace-head .trace-class { color: #222; font-size: 18px; font-weight: bold; line-height: 1.3; margin: 0; position: relative; }
  48442. .trace-message { font-size: 14px; font-weight: normal; margin: .5em 0 0; }
  48443. .trace-file-path, .trace-file-path a { color: #222; margin-top: 3px; font-size: 13px; }
  48444. .trace-class { color: #B0413E; }
  48445. .trace-type { padding: 0 2px; }
  48446. .trace-method { color: #B0413E; font-weight: bold; }
  48447. .trace-arguments { color: #777; font-weight: normal; padding-left: 2px; }
  48448. @media (min-width: 575px) {
  48449. .hidden-xs-down { display: initial; }
  48450. }
  48451. EOF;
  48452. }
  48453. private function decorate($content, $css)
  48454. {
  48455. return <<<EOF
  48456. <!DOCTYPE html>
  48457. <html>
  48458. <head>
  48459. <meta charset="{$this->charset}" />
  48460. <meta name="robots" content="noindex,nofollow" />
  48461. <style>$css</style>
  48462. </head>
  48463. <body>
  48464. $content
  48465. </body>
  48466. </html>
  48467. EOF;
  48468. }
  48469. private function formatClass($class)
  48470. {
  48471. $parts = explode('\\', $class);
  48472. return sprintf('<abbr title="%s">%s</abbr>', $class, array_pop($parts));
  48473. }
  48474. private function formatPath($path, $line)
  48475. {
  48476. $file = $this->escapeHtml(preg_match('#[^/\\\\]*+$#', $path, $file) ? $file[0] : $path);
  48477. $fmt = $this->fileLinkFormat ?: ini_get('xdebug.file_link_format') ?: get_cfg_var('xdebug.file_link_format');
  48478. if (!$fmt) {
  48479. return sprintf('<span class="block trace-file-path">in <span title="%s%3$s"><strong>%s</strong>%s</span></span>', $this->escapeHtml($path), $file, 0 < $line ? ' line '.$line : '');
  48480. }
  48481. if (\is_string($fmt)) {
  48482. $i = strpos($f = $fmt, '&', max(strrpos($f, '%f'), strrpos($f, '%l'))) ?: \strlen($f);
  48483. $fmt = [substr($f, 0, $i)] + preg_split('/&([^>]++)>/', substr($f, $i), -1, PREG_SPLIT_DELIM_CAPTURE);
  48484. for ($i = 1; isset($fmt[$i]); ++$i) {
  48485. if (0 === strpos($path, $k = $fmt[$i++])) {
  48486. $path = substr_replace($path, $fmt[$i], 0, \strlen($k));
  48487. break;
  48488. }
  48489. }
  48490. $link = strtr($fmt[0], ['%f' => $path, '%l' => $line]);
  48491. } else {
  48492. try {
  48493. $link = $fmt->format($path, $line);
  48494. } catch (\Exception $e) {
  48495. return sprintf('<span class="block trace-file-path">in <span title="%s%3$s"><strong>%s</strong>%s</span></span>', $this->escapeHtml($path), $file, 0 < $line ? ' line '.$line : '');
  48496. }
  48497. }
  48498. return sprintf('<span class="block trace-file-path">in <a href="%s" title="Go to source"><strong>%s</string>%s</a></span>', $this->escapeHtml($link), $file, 0 < $line ? ' line '.$line : '');
  48499. }
  48500. private function formatArgs(array $args)
  48501. {
  48502. $result = [];
  48503. foreach ($args as $key => $item) {
  48504. if ('object' === $item[0]) {
  48505. $formattedValue = sprintf('<em>object</em>(%s)', $this->formatClass($item[1]));
  48506. } elseif ('array' === $item[0]) {
  48507. $formattedValue = sprintf('<em>array</em>(%s)', \is_array($item[1]) ? $this->formatArgs($item[1]) : $item[1]);
  48508. } elseif ('null' === $item[0]) {
  48509. $formattedValue = '<em>null</em>';
  48510. } elseif ('boolean' === $item[0]) {
  48511. $formattedValue = '<em>'.strtolower(var_export($item[1], true)).'</em>';
  48512. } elseif ('resource' === $item[0]) {
  48513. $formattedValue = '<em>resource</em>';
  48514. } else {
  48515. $formattedValue = str_replace("\n", '', $this->escapeHtml(var_export($item[1], true)));
  48516. }
  48517. $result[] = \is_int($key) ? $formattedValue : sprintf("'%s' => %s", $this->escapeHtml($key), $formattedValue);
  48518. }
  48519. return implode(', ', $result);
  48520. }
  48521. private function escapeHtml($str)
  48522. {
  48523. return htmlspecialchars($str, ENT_COMPAT | ENT_SUBSTITUTE, $this->charset);
  48524. }
  48525. private function getSymfonyGhostAsSvg()
  48526. {
  48527. return '<svg viewBox="0 0 136 81" xmlns="http://www.w3.org/2000/svg" fill-rule="evenodd" clip-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="1.4"><path d="M92.4 20.4a23.2 23.2 0 0 1 9 1.9 23.7 23.7 0 0 1 5.2 3 24.3 24.3 0 0 1 3.4 3.4 24.8 24.8 0 0 1 5 9.4c.5 1.7.8 3.4 1 5.2v14.5h.4l.5.2a7.4 7.4 0 0 0 2.5.2l.2-.2.6-.8.8-1.3-.2-.1a5.5 5.5 0 0 1-.8-.3 5.6 5.6 0 0 1-2.3-1.8 5.7 5.7 0 0 1-.9-1.6 6.5 6.5 0 0 1-.2-2.8 7.3 7.3 0 0 1 .5-2l.3-.3.8-.9.3-.3c.2-.2.5-.3.8-.3H120.7c.2 0 .3-.1.4 0h.4l.2.1.3.2.2-.4.3-.4.1-.1 1.2-1 .3-.2.4-.1.4-.1h.3l1.5.1.4.1.8.5.1.2 1 1.1v.2H129.4l.4-.2 1.4-.5h1.1c.3 0 .7.2 1 .4.2 0 .3.2.5.3l.2.2.5.3.4.6.1.3.4 1.4.1.4v.6a7.8 7.8 0 0 1-.1.6 9.9 9.9 0 0 1-.8 2.4 7.8 7.8 0 0 1-3 3.3 6.4 6.4 0 0 1-1 .5 6.1 6.1 0 0 1-.6.2l-.7.1h-.1a23.4 23.4 0 0 1-.2 1.7 14.3 14.3 0 0 1-.6 2.1l-.8 2a9.2 9.2 0 0 1-.4.6l-.7 1a9.1 9.1 0 0 1-2.3 2.2c-.9.5-2 .6-3 .7l-1.4.1h-.5l-.4.1a15.8 15.8 0 0 1-2.8-.1v4.2a9.7 9.7 0 0 1-.7 3.5 9.6 9.6 0 0 1-1.7 2.8 9.3 9.3 0 0 1-3 2.3 9 9 0 0 1-5.4.7 9 9 0 0 1-3-1 9.4 9.4 0 0 1-2.7-2.5 10 10 0 0 1-1 1.2 9.3 9.3 0 0 1-2 1.3 9 9 0 0 1-2.4 1 9 9 0 0 1-6.5-1.1A9.4 9.4 0 0 1 85 77V77a10.9 10.9 0 0 1-.6.6 9.3 9.3 0 0 1-2.7 2 9 9 0 0 1-6 .8 9 9 0 0 1-2.4-1 9.3 9.3 0 0 1-2.3-1.7 9.6 9.6 0 0 1-1.8-2.8 9.7 9.7 0 0 1-.8-3.7v-4a18.5 18.5 0 0 1-2.9.2l-1.2-.1c-1.9-.3-3.7-1-5.1-2.1A8.2 8.2 0 0 1 58 64a10.2 10.2 0 0 1-.9-1.2 15.3 15.3 0 0 1-.7-1.3 20.8 20.8 0 0 1-1.9-6.2v-.2a6.5 6.5 0 0 1-1-.3 6.1 6.1 0 0 1-.6-.3 6.6 6.6 0 0 1-.9-.5 8.2 8.2 0 0 1-2.7-3.8 10 10 0 0 1-.3-1 10.3 10.3 0 0 1-.3-1.9V47v-.4l.1-.4.6-1.4.1-.2a2 2 0 0 1 .8-.8l.3-.2.3-.2a3.2 3.2 0 0 1 1.8-.5h.4l.3.2 1.4.6.2.2.4.3.3.4.7-.7.2-.2.4-.2.6-.2h2.1l.4.2.4.2.3.2.8 1 .2-.1h.1v-.1H63l1.1.1h.3l.8.5.3.4.7 1 .2.3.1.5a11 11 0 0 1 .2 1.5c0 .8 0 1.6-.3 2.3a6 6 0 0 1-.5 1.2 5.5 5.5 0 0 1-3.3 2.5 12.3 12.3 0 0 0 1.4 3h.1l.2.1 1 .2h1.5l.5-.2H67.8l.5-.2h.1V44v-.4a26.7 26.7 0 0 1 .3-2.3 24.7 24.7 0 0 1 5.7-12.5 24.2 24.2 0 0 1 3.5-3.3 23.7 23.7 0 0 1 4.9-3 23.2 23.2 0 0 1 5.6-1.7 23.7 23.7 0 0 1 4-.3zm-.3 2a21.2 21.2 0 0 0-8 1.7 21.6 21.6 0 0 0-4.8 2.7 22.2 22.2 0 0 0-3.2 3 22.7 22.7 0 0 0-5 9.2 23.4 23.4 0 0 0-.7 4.9v15.7l-.5.1a34.3 34.3 0 0 1-1.5.3h-.2l-.4.1h-.4l-.9.2a10 10 0 0 1-1.9 0c-.5 0-1-.2-1.5-.4a1.8 1.8 0 0 1-.3-.2 2 2 0 0 1-.3-.3 5.2 5.2 0 0 1-.1-.2 9 9 0 0 1-.6-.9 13.8 13.8 0 0 1-1-2 14.3 14.3 0 0 1-.6-2 14 14 0 0 1-.1-.8v-.2h.3a12.8 12.8 0 0 0 1.4-.2 4.4 4.4 0 0 0 .3 0 3.6 3.6 0 0 0 1.1-.7 3.4 3.4 0 0 0 1.2-1.7l.2-1.2a5.1 5.1 0 0 0 0-.8 7.2 7.2 0 0 0-.1-.8l-.7-1-1.2-.2-1 .7-.1 1.3a5 5 0 0 1 .1.4v.6a1 1 0 0 1 0 .3c-.1.3-.4.4-.7.5l-1.2.4v-.7A9.9 9.9 0 0 1 60 49l.3-.6v-.2l.1-.1v-1.6l-1-1.2h-1.5l-1 1.1v.4a5.3 5.3 0 0 0-.2.6 5.5 5.5 0 0 0 0 .5c0 .7 0 1.4.3 2 0 .4.2.8.4 1.2L57 51a9.5 9.5 0 0 1-1.1-.5h-.2a2 2 0 0 1-.4-.3c-.4-.4-.5-1-.6-1.6a5.6 5.6 0 0 1 0-.5v-.5-.5l-.6-1.5-1.4-.6-.9.3s-.2 0-.3.2a2 2 0 0 1-.1 0l-.6 1.4v.7a8.5 8.5 0 0 0 .5 2c.4 1.1 1 2.1 2 2.8a4.7 4.7 0 0 0 2.1.9h1a22.8 22.8 0 0 0 .1 1 18.1 18.1 0 0 0 .8 3.8 18.2 18.2 0 0 0 1.6 3.7l1 1.3c1 1 2.3 1.6 3.7 2a11.7 11.7 0 0 0 4.8 0h.4l.5-.2.5-.1.6-.2v6.6a8 8 0 0 0 .1 1.3 7.5 7.5 0 0 0 2.4 4.3 7.2 7.2 0 0 0 2.3 1.3 7 7 0 0 0 7-1.1 7.5 7.5 0 0 0 2-2.6A7.7 7.7 0 0 0 85 72V71a8.2 8.2 0 0 0 .2 1.3c0 .7.3 1.4.6 2a7.5 7.5 0 0 0 1.7 2.3 7.3 7.3 0 0 0 2.2 1.4 7.1 7.1 0 0 0 4.6.2 7.2 7.2 0 0 0 2.4-1.2 7.5 7.5 0 0 0 2.1-2.7 7.8 7.8 0 0 0 .7-2.4V71a9.3 9.3 0 0 0 .1.6 7.6 7.6 0 0 0 .6 2.5 7.5 7.5 0 0 0 2.4 3 7.1 7.1 0 0 0 7 .8 7.3 7.3 0 0 0 2.3-1.5 7.5 7.5 0 0 0 1.6-2.3 7.6 7.6 0 0 0 .5-2l.1-1.1v-6.7l.4.1a12.2 12.2 0 0 0 2 .5 11.1 11.1 0 0 0 2.5 0h.8l1.2-.1a9.5 9.5 0 0 0 1.4-.2l.9-.3a3.5 3.5 0 0 0 .6-.4l1.2-1.4a12.2 12.2 0 0 0 .8-1.2c0-.3.2-.5.3-.7a15.9 15.9 0 0 0 .7-2l.3-1.6v-1.3l.2-.9V54.6a15.5 15.5 0 0 0 1.8 0 4.5 4.5 0 0 0 1.4-.5 5.7 5.7 0 0 0 2.5-3.2 7.6 7.6 0 0 0 .4-1.5v-.3l-.4-1.4a5.2 5.2 0 0 1-.2-.1l-.4-.4a3.8 3.8 0 0 0-.2 0 1.4 1.4 0 0 0-.5-.2l-1.4.4-.7 1.3v.7a5.7 5.7 0 0 1-.1.8l-.7 1.4a1.9 1.9 0 0 1-.5.3h-.3a9.6 9.6 0 0 1-.8.3 8.8 8.8 0 0 1-.6 0l.2-.4.2-.5.2-.3v-.4l.1-.2V50l.1-1 .1-.6v-.6a4.8 4.8 0 0 0 0-.8v-.2l-1-1.1-1.5-.2-1.1 1-.2 1.4v.1l.2.4.2.3v.4l.1 1.1v.3l.1.5v.8a9.6 9.6 0 0 1-.8-.3l-.2-.1h-.3l-.8-.1h-.2a1.6 1.6 0 0 1-.2-.2.9.9 0 0 1-.2-.2 1 1 0 0 1-.1-.5l.2-.9v-1.2l-.9-.8h-1.2l-.8.9v.3a4.8 4.8 0 0 0-.3 2l.3.9a3.5 3.5 0 0 0 1.2 1.6l1 .5.8.2 1.4.1h.4l.2.1a12.1 12.1 0 0 1-1 2.6 13.2 13.2 0 0 1-.8 1.5 9.5 9.5 0 0 1-1 1.2l-.2.3a1.7 1.7 0 0 1-.4.3 2.4 2.4 0 0 1-.7.2h-2.5a7.8 7.8 0 0 1-.6-.2l-.7-.2h-.2a14.8 14.8 0 0 1-.6-.2 23.4 23.4 0 0 1-.4-.1l-.4-.1-.3-.1V43.9a34.6 34.6 0 0 0 0-.6 23.6 23.6 0 0 0-.4-3 22.7 22.7 0 0 0-1.5-4.7 22.6 22.6 0 0 0-4.6-6.7 21.9 21.9 0 0 0-6.9-4.7 21.2 21.2 0 0 0-8.1-1.8H92zm9.1 33.7l.3.1a1 1 0 0 1 .6.8v.4a8.4 8.4 0 0 1 0 .5 8.8 8.8 0 0 1-1.6 4.2l-1 1.3A10 10 0 0 1 95 66c-1.3.3-2.7.4-4 .3a10.4 10.4 0 0 1-2.7-.8 10 10 0 0 1-3.6-2.5 9.3 9.3 0 0 1-.8-1 9 9 0 0 1-.7-1.2 8.6 8.6 0 0 1-.8-3.4V57a1 1 0 0 1 .3-.6 1 1 0 0 1 1.3-.2 1 1 0 0 1 .4.8v.4a6.5 6.5 0 0 0 .5 2.2 7 7 0 0 0 2.1 2.8l1 .6c2.6 1.6 6 1.6 8.5 0a8 8 0 0 0 1.1-.6 7.6 7.6 0 0 0 1.2-1.2 7 7 0 0 0 1-1.7 6.5 6.5 0 0 0 .4-2.5 1 1 0 0 1 .7-1h.4zM30.7 43.7c-15.5 1-28.5-6-30.1-16.4C-1.2 15.7 11.6 4 29 1.3 46.6-1.7 62.3 5.5 64 17.1c1.6 10.4-8.7 21-23.7 25a31.2 31.2 0 0 0 0 .9v.3a19 19 0 0 0 .1 1l.1.4.1.9a4.7 4.7 0 0 0 .5 1l.7 1a9.2 9.2 0 0 0 1.2 1l1.5.8.6.8-.7.6-1.1.3a11.2 11.2 0 0 1-2.6.4 8.6 8.6 0 0 1-3-.5 8.5 8.5 0 0 1-1-.4 11.2 11.2 0 0 1-1.8-1.2 13.3 13.3 0 0 1-1-1 18 18 0 0 1-.7-.6l-.4-.4a23.4 23.4 0 0 1-1.3-1.8l-.1-.1-.3-.5V45l-.3-.6v-.7zM83.1 36c3.6 0 6.5 3.2 6.5 7.1 0 4-3 7.2-6.5 7.2S76.7 47 76.7 43 79.6 36 83 36zm18 0c3.6 0 6.5 3.2 6.5 7.1 0 4-2.9 7.2-6.4 7.2S94.7 47 94.7 43s3-7.1 6.5-7.1zm-18 6.1c2 0 3.5 1.6 3.5 3.6S85 49.2 83 49.2s-3.4-1.6-3.4-3.6S81.2 42 83 42zm17.9 0c1.9 0 3.4 1.6 3.4 3.6s-1.5 3.6-3.4 3.6c-2 0-3.5-1.6-3.5-3.6S99.1 42 101 42zM17 28c-.3 1.6-1.8 5-5.2 5.8-2.5.6-4.1-.8-4.5-2.6-.4-1.9.7-3.5 2.1-4.5A3.5 3.5 0 0 1 8 24.6c-.4-2 .8-3.7 3.2-4.2 1.9-.5 3.1.2 3.4 1.5.3 1.1-.5 2.2-1.8 2.5-.9.3-1.6 0-1.7-.6a1.4 1.4 0 0 1 0-.7s.3.2 1 0c.7-.1 1-.7.9-1.2-.2-.6-1-.8-1.8-.6-1 .2-2 1-1.7 2.6.3 1 .9 1.6 1.5 1.8l.7-.2c1-.2 1.5 0 1.6.5 0 .4-.2 1-1.2 1.2a3.3 3.3 0 0 1-1.5 0c-.9.7-1.6 1.9-1.3 3.2.3 1.3 1.3 2.2 3 1.8 2.5-.7 3.8-3.7 4.2-5-.3-.5-.6-1-.7-1.6-.1-.5.1-1 .9-1.2.4 0 .7.2.8.8a2.8 2.8 0 0 1 0 1l.7 1c.6-2 1.4-4 1.7-4 .6-.2 1.5.6 1.5.6-.8.7-1.7 2.4-2.3 4.2.8.6 1.6 1 2.1 1 .5-.1.8-.6 1-1.2-.3-2.2 1-4.3 2.3-4.6.7-.2 1.3.2 1.4.8.1.5 0 1.3-.9 1.7-.2-1-.6-1.3-1-1.3-.4.1-.7 1.4-.4 2.8.2 1 .7 1.5 1.3 1.4.8-.2 1.3-1.2 1.7-2.1-.3-2.1.9-4.2 2.2-4.5.7-.2 1.2.1 1.4 1 .4 1.4-1 2.8-2.2 3.4.3.7.7 1 1.3.9 1-.3 1.6-1.5 2-2.5l-.5-3v-.3s1.6-.3 1.8.6v.1c.2-.6.7-1.2 1.3-1.4.8-.1 1.5.6 1.7 1.6.5 2.2-.5 4.4-1.8 4.7H33a31.9 31.9 0 0 0 1 5.2c-.4.1-1.8.4-2-.4l-.5-5.6c-.5 1-1.3 2.2-2.5 2.4-1 .3-1.6-.3-2-1.1-.5 1-1.3 2.1-2.4 2.4-.8.2-1.5-.1-2-1-.3.8-.9 1.5-1.5 1.7-.7.1-1.5-.3-2.4-1-.3.8-.4 1.6-.4 2.2 0 0-.7 0-.8-.4-.1-.5 0-1.5.3-2.7a10.3 10.3 0 0 1-.7-.8zm38.2-17.8l.2.9c.5 1.9.4 4.4.8 6.4 0 .6-.4 3-1.4 3.3-.2 0-.3 0-.4-.4-.1-.7 0-1.6-.3-2.6-.2-1.1-.8-1.6-1.5-1.5-.8.2-1.3 1-1.6 2l-.1-.5c-.2-1-1.8-.6-1.8-.6a6.2 6.2 0 0 1 .4 1.3l.2 1c-.2.5-.6 1-1.2 1l-.2.1a7 7 0 0 0-.1-.8c-.3-1.1-1-2-1.6-1.8a.7.7 0 0 0-.4.3c-1.3.3-2.4 2-2.1 3.9-.2.9-.6 1.7-1 1.9-.5 0-.8-.5-1.1-1.8l-.1-1.2a4 4 0 0 0 0-1.7c0-.4-.4-.7-.8-.6-.7.2-.9 1.7-.5 3.8-.2 1-.6 2-1.3 2-.4.2-.8-.2-1-1l-.2-3c1.2-.5 2-1 1.8-1.7-.1-.5-.8-.7-.8-.7s0 .7-1 1.2l-.2-1.4c-.1-.6-.4-1-1.7-.6l.4 1 .2 1.5h-1v.8c0 .3.4.3 1 .2 0 1.3 0 2.7.2 3.6.3 1.4 1.2 2 2 1.7 1-.2 1.6-1.3 2-2.3.3 1.2 1 2 1.9 1.7.7-.2 1.2-1.1 1.6-2.2.4.8 1.1 1.1 2 1 1.2-.4 1.7-1.6 1.8-2.8h.2c.6-.2 1-.6 1.3-1 0 .8 0 1.5.2 2.1.1.5.3.7.6.6.5-.1 1-.9 1-.9a4 4 0 0 1-.3-1c-.3-1.3.3-3.6 1-3.7.2 0 .3.2.5.7v.8l.2 1.5v.7c.2.7.7 1.3 1.5 1 1.3-.2 2-2.6 2.1-3.9.3.2.6.2 1 .1-.6-2.2 0-6.1-.3-7.9-.1-.4-1-.5-1.7-.5h-.4zm-21.5 12c.4 0 .7.3 1 1.1.2 1.3-.3 2.6-.9 2.8-.2 0-.7 0-1-1.2v-.4c0-1.3.4-2 1-2.2zm-5.2 1c.3 0 .6.2.6.5.2.6-.3 1.3-1.2 2-.3-1.4.1-2.3.6-2.5zm18-.4c-.5.2-1-.4-1.2-1.2-.2-1 0-2.1.7-2.5v.5c.2.7.6 1.5 1.3 1.9 0 .7-.2 1.2-.7 1.3zm10-1.6c0 .5.4.7 1 .6.8-.2 1-1 .8-1.6 0-.5-.4-1-1-.8-.5.1-1 .9-.8 1.8zm-14.3-5.5c0-.4-.5-.7-1-.5-.8.2-1 1-.9 1.5.2.6.5 1 1 .8.5 0 1.1-1 1-1.8z" fill="#fff" fill-opacity=".6"/></svg>';
  48528. }
  48529. }
  48530. <?php
  48531. namespace Symfony\Component\Debug;
  48532. /**
  48533. @notk
  48534. @tchwork
  48535. */
  48536. class DebugClassLoader
  48537. {
  48538. private $classLoader;
  48539. private $isFinder;
  48540. private $loaded = [];
  48541. private static $caseCheck;
  48542. private static $checkedClasses = [];
  48543. private static $final = [];
  48544. private static $finalMethods = [];
  48545. private static $deprecated = [];
  48546. private static $internal = [];
  48547. private static $internalMethods = [];
  48548. private static $php7Reserved = ['int' => 1, 'float' => 1, 'bool' => 1, 'string' => 1, 'true' => 1, 'false' => 1, 'null' => 1];
  48549. private static $darwinCache = ['/' => ['/', []]];
  48550. public function __construct(callable $classLoader)
  48551. {
  48552. $this->classLoader = $classLoader;
  48553. $this->isFinder = \is_array($classLoader) && method_exists($classLoader[0], 'findFile');
  48554. if (!isset(self::$caseCheck)) {
  48555. $file = file_exists(__FILE__) ? __FILE__ : rtrim(realpath('.'), \DIRECTORY_SEPARATOR);
  48556. $i = strrpos($file, \DIRECTORY_SEPARATOR);
  48557. $dir = substr($file, 0, 1 + $i);
  48558. $file = substr($file, 1 + $i);
  48559. $test = strtoupper($file) === $file ? strtolower($file) : strtoupper($file);
  48560. $test = realpath($dir.$test);
  48561. if (false === $test || false === $i) {
  48562. self::$caseCheck = 0;
  48563. } elseif (substr($test, -\strlen($file)) === $file) {
  48564. self::$caseCheck = 1;
  48565. } elseif (false !== stripos(PHP_OS, 'darwin')) {
  48566. self::$caseCheck = 2;
  48567. } else {
  48568. self::$caseCheck = 0;
  48569. }
  48570. }
  48571. }
  48572. public function getClassLoader()
  48573. {
  48574. return $this->classLoader;
  48575. }
  48576. public static function enable()
  48577. {
  48578. class_exists('Symfony\Component\Debug\ErrorHandler');
  48579. class_exists('Psr\Log\LogLevel');
  48580. if (!\is_array($functions = spl_autoload_functions())) {
  48581. return;
  48582. }
  48583. foreach ($functions as $function) {
  48584. spl_autoload_unregister($function);
  48585. }
  48586. foreach ($functions as $function) {
  48587. if (!\is_array($function) || !$function[0] instanceof self) {
  48588. $function = [new static($function), 'loadClass'];
  48589. }
  48590. spl_autoload_register($function);
  48591. }
  48592. }
  48593. public static function disable()
  48594. {
  48595. if (!\is_array($functions = spl_autoload_functions())) {
  48596. return;
  48597. }
  48598. foreach ($functions as $function) {
  48599. spl_autoload_unregister($function);
  48600. }
  48601. foreach ($functions as $function) {
  48602. if (\is_array($function) && $function[0] instanceof self) {
  48603. $function = $function[0]->getClassLoader();
  48604. }
  48605. spl_autoload_register($function);
  48606. }
  48607. }
  48608. public function findFile($class)
  48609. {
  48610. return $this->isFinder ? $this->classLoader[0]->findFile($class) ?: null : null;
  48611. }
  48612. public function loadClass($class)
  48613. {
  48614. $e = error_reporting(error_reporting() | E_PARSE | E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR);
  48615. try {
  48616. if ($this->isFinder && !isset($this->loaded[$class])) {
  48617. $this->loaded[$class] = true;
  48618. if (!$file = $this->classLoader[0]->findFile($class) ?: false) {
  48619. } elseif (\function_exists('opcache_is_script_cached') && @opcache_is_script_cached($file)) {
  48620. include $file;
  48621. return;
  48622. } elseif (false === include $file) {
  48623. return;
  48624. }
  48625. } else {
  48626. \call_user_func($this->classLoader, $class);
  48627. $file = false;
  48628. }
  48629. } finally {
  48630. error_reporting($e);
  48631. }
  48632. $this->checkClass($class, $file);
  48633. }
  48634. private function checkClass($class, $file = null)
  48635. {
  48636. $exists = null === $file || class_exists($class, false) || interface_exists($class, false) || trait_exists($class, false);
  48637. if (null !== $file && $class && '\\' === $class[0]) {
  48638. $class = substr($class, 1);
  48639. }
  48640. if ($exists) {
  48641. if (isset(self::$checkedClasses[$class])) {
  48642. return;
  48643. }
  48644. self::$checkedClasses[$class] = true;
  48645. $refl = new \ReflectionClass($class);
  48646. if (null === $file && $refl->isInternal()) {
  48647. return;
  48648. }
  48649. $name = $refl->getName();
  48650. if ($name !== $class && 0 === strcasecmp($name, $class)) {
  48651. throw new \RuntimeException(sprintf('Case mismatch between loaded and declared class names: "%s" vs "%s".', $class, $name));
  48652. }
  48653. $deprecations = $this->checkAnnotations($refl, $name);
  48654. if (isset(self::$php7Reserved[strtolower($refl->getShortName())])) {
  48655. $deprecations[] = sprintf('The "%s" class uses the reserved name "%s", it will break on PHP 7 and higher', $name, $refl->getShortName());
  48656. }
  48657. foreach ($deprecations as $message) {
  48658. @trigger_error($message, E_USER_DEPRECATED);
  48659. }
  48660. }
  48661. if (!$file) {
  48662. return;
  48663. }
  48664. if (!$exists) {
  48665. if (false !== strpos($class, '/')) {
  48666. throw new \RuntimeException(sprintf('Trying to autoload a class with an invalid name "%s". Be careful that the namespace separator is "\" in PHP, not "/".', $class));
  48667. }
  48668. throw new \RuntimeException(sprintf('The autoloader expected class "%s" to be defined in file "%s". The file was found but the class was not in it, the class name or namespace probably has a typo.', $class, $file));
  48669. }
  48670. if (self::$caseCheck && $message = $this->checkCase($refl, $file, $class)) {
  48671. throw new \RuntimeException(sprintf('Case mismatch between class and real file names: "%s" vs "%s" in "%s".', $message[0], $message[1], $message[2]));
  48672. }
  48673. }
  48674. public function checkAnnotations(\ReflectionClass $refl, $class)
  48675. {
  48676. $deprecations = [];
  48677. if (2 > $len = 1 + (strpos($class, '\\') ?: strpos($class, '_'))) {
  48678. $len = 0;
  48679. $ns = '';
  48680. } else {
  48681. $ns = str_replace('_', '\\', substr($class, 0, $len));
  48682. }
  48683. if (false !== $doc = $refl->getDocComment()) {
  48684. foreach (['final', 'deprecated', 'internal'] as $annotation) {
  48685. if (false !== strpos($doc, $annotation) && preg_match('#\n\s+\* @'.$annotation.'(?:( .+?)\.?)?\r?\n\s+\*(?: @|/$|\r?\n)#s', $doc, $notice)) {
  48686. self::${$annotation}[$class] = isset($notice[1]) ? preg_replace('#\.?\r?\n( \*)? *(?= |\r?\n|$)#', '', $notice[1]) : '';
  48687. }
  48688. }
  48689. }
  48690. $parent = get_parent_class($class);
  48691. $parentAndOwnInterfaces = $this->getOwnInterfaces($class, $parent);
  48692. if ($parent) {
  48693. $parentAndOwnInterfaces[$parent] = $parent;
  48694. if (!isset(self::$checkedClasses[$parent])) {
  48695. $this->checkClass($parent);
  48696. }
  48697. if (isset(self::$final[$parent])) {
  48698. $deprecations[] = sprintf('The "%s" class is considered final%s. It may change without further notice as of its next major version. You should not extend it from "%s".', $parent, self::$final[$parent], $class);
  48699. }
  48700. }
  48701. foreach ($parentAndOwnInterfaces + class_uses($class, false) as $use) {
  48702. if (!isset(self::$checkedClasses[$use])) {
  48703. $this->checkClass($use);
  48704. }
  48705. if (isset(self::$deprecated[$use]) && strncmp($ns, str_replace('_', '\\', $use), $len) && !isset(self::$deprecated[$class])) {
  48706. $type = class_exists($class, false) ? 'class' : (interface_exists($class, false) ? 'interface' : 'trait');
  48707. $verb = class_exists($use, false) || interface_exists($class, false) ? 'extends' : (interface_exists($use, false) ? 'implements' : 'uses');
  48708. $deprecations[] = sprintf('The "%s" %s %s "%s" that is deprecated%s.', $class, $type, $verb, $use, self::$deprecated[$use]);
  48709. }
  48710. if (isset(self::$internal[$use]) && strncmp($ns, str_replace('_', '\\', $use), $len)) {
  48711. $deprecations[] = sprintf('The "%s" %s is considered internal%s. It may change without further notice. You should not use it from "%s".', $use, class_exists($use, false) ? 'class' : (interface_exists($use, false) ? 'interface' : 'trait'), self::$internal[$use], $class);
  48712. }
  48713. }
  48714. if (trait_exists($class)) {
  48715. return $deprecations;
  48716. }
  48717. self::$finalMethods[$class] = [];
  48718. self::$internalMethods[$class] = [];
  48719. foreach ($parentAndOwnInterfaces as $use) {
  48720. foreach (['finalMethods', 'internalMethods'] as $property) {
  48721. if (isset(self::${$property}[$use])) {
  48722. self::${$property}[$class] = self::${$property}[$class] ? self::${$property}[$use] + self::${$property}[$class] : self::${$property}[$use];
  48723. }
  48724. }
  48725. }
  48726. foreach ($refl->getMethods(\ReflectionMethod::IS_PUBLIC | \ReflectionMethod::IS_PROTECTED) as $method) {
  48727. if ($method->class !== $class) {
  48728. continue;
  48729. }
  48730. if ($parent && isset(self::$finalMethods[$parent][$method->name])) {
  48731. list($declaringClass, $message) = self::$finalMethods[$parent][$method->name];
  48732. $deprecations[] = sprintf('The "%s::%s()" method is considered final%s. It may change without further notice as of its next major version. You should not extend it from "%s".', $declaringClass, $method->name, $message, $class);
  48733. }
  48734. if (isset(self::$internalMethods[$class][$method->name])) {
  48735. list($declaringClass, $message) = self::$internalMethods[$class][$method->name];
  48736. if (strncmp($ns, $declaringClass, $len)) {
  48737. $deprecations[] = sprintf('The "%s::%s()" method is considered internal%s. It may change without further notice. You should not extend it from "%s".', $declaringClass, $method->name, $message, $class);
  48738. }
  48739. }
  48740. if (false === $doc = $method->getDocComment()) {
  48741. continue;
  48742. }
  48743. foreach (['final', 'internal'] as $annotation) {
  48744. if (false !== strpos($doc, $annotation) && preg_match('#\n\s+\* @'.$annotation.'(?:( .+?)\.?)?\r?\n\s+\*(?: @|/$|\r?\n)#s', $doc, $notice)) {
  48745. $message = isset($notice[1]) ? preg_replace('#\.?\r?\n( \*)? *(?= |\r?\n|$)#', '', $notice[1]) : '';
  48746. self::${$annotation.'Methods'}[$class][$method->name] = [$class, $message];
  48747. }
  48748. }
  48749. }
  48750. return $deprecations;
  48751. }
  48752. public function checkCase(\ReflectionClass $refl, $file, $class)
  48753. {
  48754. $real = explode('\\', $class.strrchr($file, '.'));
  48755. $tail = explode(\DIRECTORY_SEPARATOR, str_replace('/', \DIRECTORY_SEPARATOR, $file));
  48756. $i = \count($tail) - 1;
  48757. $j = \count($real) - 1;
  48758. while (isset($tail[$i], $real[$j]) && $tail[$i] === $real[$j]) {
  48759. --$i;
  48760. --$j;
  48761. }
  48762. array_splice($tail, 0, $i + 1);
  48763. if (!$tail) {
  48764. return null;
  48765. }
  48766. $tail = \DIRECTORY_SEPARATOR.implode(\DIRECTORY_SEPARATOR, $tail);
  48767. $tailLen = \strlen($tail);
  48768. $real = $refl->getFileName();
  48769. if (2 === self::$caseCheck) {
  48770. $real = $this->darwinRealpath($real);
  48771. }
  48772. if (0 === substr_compare($real, $tail, -$tailLen, $tailLen, true)
  48773. && 0 !== substr_compare($real, $tail, -$tailLen, $tailLen, false)
  48774. ) {
  48775. return [substr($tail, -$tailLen + 1), substr($real, -$tailLen + 1), substr($real, 0, -$tailLen + 1)];
  48776. }
  48777. return null;
  48778. }
  48779. private function darwinRealpath($real)
  48780. {
  48781. $i = 1 + strrpos($real, '/');
  48782. $file = substr($real, $i);
  48783. $real = substr($real, 0, $i);
  48784. if (isset(self::$darwinCache[$real])) {
  48785. $kDir = $real;
  48786. } else {
  48787. $kDir = strtolower($real);
  48788. if (isset(self::$darwinCache[$kDir])) {
  48789. $real = self::$darwinCache[$kDir][0];
  48790. } else {
  48791. $dir = getcwd();
  48792. chdir($real);
  48793. $real = getcwd().'/';
  48794. chdir($dir);
  48795. $dir = $real;
  48796. $k = $kDir;
  48797. $i = \strlen($dir) - 1;
  48798. while (!isset(self::$darwinCache[$k])) {
  48799. self::$darwinCache[$k] = [$dir, []];
  48800. self::$darwinCache[$dir] = &self::$darwinCache[$k];
  48801. while ('/' !== $dir[--$i]) {
  48802. }
  48803. $k = substr($k, 0, ++$i);
  48804. $dir = substr($dir, 0, $i--);
  48805. }
  48806. }
  48807. }
  48808. $dirFiles = self::$darwinCache[$kDir][1];
  48809. if (!isset($dirFiles[$file]) && ') : eval()\'d code' === substr($file, -17)) {
  48810. $file = substr($file, 0, strrpos($file, '(', -17));
  48811. }
  48812. if (isset($dirFiles[$file])) {
  48813. return $real.$dirFiles[$file];
  48814. }
  48815. $kFile = strtolower($file);
  48816. if (!isset($dirFiles[$kFile])) {
  48817. foreach (scandir($real, 2) as $f) {
  48818. if ('.' !== $f[0]) {
  48819. $dirFiles[$f] = $f;
  48820. if ($f === $file) {
  48821. $kFile = $k = $file;
  48822. } elseif ($f !== $k = strtolower($f)) {
  48823. $dirFiles[$k] = $f;
  48824. }
  48825. }
  48826. }
  48827. self::$darwinCache[$kDir][1] = $dirFiles;
  48828. }
  48829. return $real.$dirFiles[$kFile];
  48830. }
  48831. private function getOwnInterfaces($class, $parent)
  48832. {
  48833. $ownInterfaces = class_implements($class, false);
  48834. if ($parent) {
  48835. foreach (class_implements($parent, false) as $interface) {
  48836. unset($ownInterfaces[$interface]);
  48837. }
  48838. }
  48839. foreach ($ownInterfaces as $interface) {
  48840. foreach (class_implements($interface) as $interface) {
  48841. unset($ownInterfaces[$interface]);
  48842. }
  48843. }
  48844. return $ownInterfaces;
  48845. }
  48846. }
  48847. <?php
  48848. namespace Symfony\Component\Debug\FatalErrorHandler;
  48849. use Composer\Autoload\ClassLoader as ComposerClassLoader;
  48850. use Symfony\Component\ClassLoader\ClassLoader as SymfonyClassLoader;
  48851. use Symfony\Component\Debug\DebugClassLoader;
  48852. use Symfony\Component\Debug\Exception\ClassNotFoundException;
  48853. use Symfony\Component\Debug\Exception\FatalErrorException;
  48854. class ClassNotFoundFatalErrorHandler implements FatalErrorHandlerInterface
  48855. {
  48856. public function handleError(array $error, FatalErrorException $exception)
  48857. {
  48858. $messageLen = \strlen($error['message']);
  48859. $notFoundSuffix = '\' not found';
  48860. $notFoundSuffixLen = \strlen($notFoundSuffix);
  48861. if ($notFoundSuffixLen > $messageLen) {
  48862. return null;
  48863. }
  48864. if (0 !== substr_compare($error['message'], $notFoundSuffix, -$notFoundSuffixLen)) {
  48865. return null;
  48866. }
  48867. foreach (['class', 'interface', 'trait'] as $typeName) {
  48868. $prefix = ucfirst($typeName).' \'';
  48869. $prefixLen = \strlen($prefix);
  48870. if (0 !== strpos($error['message'], $prefix)) {
  48871. continue;
  48872. }
  48873. $fullyQualifiedClassName = substr($error['message'], $prefixLen, -$notFoundSuffixLen);
  48874. if (false !== $namespaceSeparatorIndex = strrpos($fullyQualifiedClassName, '\\')) {
  48875. $className = substr($fullyQualifiedClassName, $namespaceSeparatorIndex + 1);
  48876. $namespacePrefix = substr($fullyQualifiedClassName, 0, $namespaceSeparatorIndex);
  48877. $message = sprintf('Attempted to load %s "%s" from namespace "%s".', $typeName, $className, $namespacePrefix);
  48878. $tail = ' for another namespace?';
  48879. } else {
  48880. $className = $fullyQualifiedClassName;
  48881. $message = sprintf('Attempted to load %s "%s" from the global namespace.', $typeName, $className);
  48882. $tail = '?';
  48883. }
  48884. if ($candidates = $this->getClassCandidates($className)) {
  48885. $tail = array_pop($candidates).'"?';
  48886. if ($candidates) {
  48887. $tail = ' for e.g. "'.implode('", "', $candidates).'" or "'.$tail;
  48888. } else {
  48889. $tail = ' for "'.$tail;
  48890. }
  48891. }
  48892. $message .= "\nDid you forget a \"use\" statement".$tail;
  48893. return new ClassNotFoundException($message, $exception);
  48894. }
  48895. return null;
  48896. }
  48897. private function getClassCandidates($class)
  48898. {
  48899. if (!\is_array($functions = spl_autoload_functions())) {
  48900. return [];
  48901. }
  48902. $classes = [];
  48903. foreach ($functions as $function) {
  48904. if (!\is_array($function)) {
  48905. continue;
  48906. }
  48907. if ($function[0] instanceof DebugClassLoader) {
  48908. $function = $function[0]->getClassLoader();
  48909. if (!\is_array($function)) {
  48910. continue;
  48911. }
  48912. }
  48913. if ($function[0] instanceof ComposerClassLoader || $function[0] instanceof SymfonyClassLoader) {
  48914. foreach ($function[0]->getPrefixes() as $prefix => $paths) {
  48915. foreach ($paths as $path) {
  48916. $classes = array_merge($classes, $this->findClassInPath($path, $class, $prefix));
  48917. }
  48918. }
  48919. }
  48920. if ($function[0] instanceof ComposerClassLoader) {
  48921. foreach ($function[0]->getPrefixesPsr4() as $prefix => $paths) {
  48922. foreach ($paths as $path) {
  48923. $classes = array_merge($classes, $this->findClassInPath($path, $class, $prefix));
  48924. }
  48925. }
  48926. }
  48927. }
  48928. return array_unique($classes);
  48929. }
  48930. private function findClassInPath($path, $class, $prefix)
  48931. {
  48932. if (!$path = realpath($path.'/'.strtr($prefix, '\\_', '//')) ?: realpath($path.'/'.\dirname(strtr($prefix, '\\_', '//'))) ?: realpath($path)) {
  48933. return [];
  48934. }
  48935. $classes = [];
  48936. $filename = $class.'.php';
  48937. foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($path, \RecursiveDirectoryIterator::SKIP_DOTS), \RecursiveIteratorIterator::LEAVES_ONLY) as $file) {
  48938. if ($filename == $file->getFileName() && $class = $this->convertFileToClass($path, $file->getPathName(), $prefix)) {
  48939. $classes[] = $class;
  48940. }
  48941. }
  48942. return $classes;
  48943. }
  48944. private function convertFileToClass($path, $file, $prefix)
  48945. {
  48946. $candidates = [
  48947. $namespacedClass = str_replace([$path.\DIRECTORY_SEPARATOR, '.php', '/'], ['', '', '\\'], $file),
  48948. $prefix.$namespacedClass,
  48949. $prefix.'\\'.$namespacedClass,
  48950. str_replace('\\', '_', $namespacedClass),
  48951. str_replace('\\', '_', $prefix.$namespacedClass),
  48952. str_replace('\\', '_', $prefix.'\\'.$namespacedClass),
  48953. ];
  48954. if ($prefix) {
  48955. $candidates = array_filter($candidates, function ($candidate) use ($prefix) { return 0 === strpos($candidate, $prefix); });
  48956. }
  48957. foreach ($candidates as $candidate) {
  48958. if ($this->classExists($candidate)) {
  48959. return $candidate;
  48960. }
  48961. }
  48962. try {
  48963. require_once $file;
  48964. } catch (\Throwable $e) {
  48965. return null;
  48966. }
  48967. foreach ($candidates as $candidate) {
  48968. if ($this->classExists($candidate)) {
  48969. return $candidate;
  48970. }
  48971. }
  48972. return null;
  48973. }
  48974. private function classExists($class)
  48975. {
  48976. return class_exists($class, false) || interface_exists($class, false) || trait_exists($class, false);
  48977. }
  48978. }
  48979. <?php
  48980. namespace Symfony\Component\Debug\FatalErrorHandler;
  48981. use Symfony\Component\Debug\Exception\FatalErrorException;
  48982. use Symfony\Component\Debug\Exception\UndefinedMethodException;
  48983. class UndefinedMethodFatalErrorHandler implements FatalErrorHandlerInterface
  48984. {
  48985. public function handleError(array $error, FatalErrorException $exception)
  48986. {
  48987. preg_match('/^Call to undefined method (.*)::(.*)\(\)$/', $error['message'], $matches);
  48988. if (!$matches) {
  48989. return null;
  48990. }
  48991. $className = $matches[1];
  48992. $methodName = $matches[2];
  48993. $message = sprintf('Attempted to call an undefined method named "%s" of class "%s".', $methodName, $className);
  48994. if (!class_exists($className) || null === $methods = get_class_methods($className)) {
  48995. return new UndefinedMethodException($message, $exception);
  48996. }
  48997. $candidates = [];
  48998. foreach ($methods as $definedMethodName) {
  48999. $lev = levenshtein($methodName, $definedMethodName);
  49000. if ($lev <= \strlen($methodName) / 3 || false !== strpos($definedMethodName, $methodName)) {
  49001. $candidates[] = $definedMethodName;
  49002. }
  49003. }
  49004. if ($candidates) {
  49005. sort($candidates);
  49006. $last = array_pop($candidates).'"?';
  49007. if ($candidates) {
  49008. $candidates = 'e.g. "'.implode('", "', $candidates).'" or "'.$last;
  49009. } else {
  49010. $candidates = '"'.$last;
  49011. }
  49012. $message .= "\nDid you mean to call ".$candidates;
  49013. }
  49014. return new UndefinedMethodException($message, $exception);
  49015. }
  49016. }
  49017. <?php
  49018. namespace Symfony\Component\Debug\FatalErrorHandler;
  49019. use Symfony\Component\Debug\Exception\FatalErrorException;
  49020. use Symfony\Component\Debug\Exception\UndefinedFunctionException;
  49021. class UndefinedFunctionFatalErrorHandler implements FatalErrorHandlerInterface
  49022. {
  49023. public function handleError(array $error, FatalErrorException $exception)
  49024. {
  49025. $messageLen = \strlen($error['message']);
  49026. $notFoundSuffix = '()';
  49027. $notFoundSuffixLen = \strlen($notFoundSuffix);
  49028. if ($notFoundSuffixLen > $messageLen) {
  49029. return null;
  49030. }
  49031. if (0 !== substr_compare($error['message'], $notFoundSuffix, -$notFoundSuffixLen)) {
  49032. return null;
  49033. }
  49034. $prefix = 'Call to undefined function ';
  49035. $prefixLen = \strlen($prefix);
  49036. if (0 !== strpos($error['message'], $prefix)) {
  49037. return null;
  49038. }
  49039. $fullyQualifiedFunctionName = substr($error['message'], $prefixLen, -$notFoundSuffixLen);
  49040. if (false !== $namespaceSeparatorIndex = strrpos($fullyQualifiedFunctionName, '\\')) {
  49041. $functionName = substr($fullyQualifiedFunctionName, $namespaceSeparatorIndex + 1);
  49042. $namespacePrefix = substr($fullyQualifiedFunctionName, 0, $namespaceSeparatorIndex);
  49043. $message = sprintf('Attempted to call function "%s" from namespace "%s".', $functionName, $namespacePrefix);
  49044. } else {
  49045. $functionName = $fullyQualifiedFunctionName;
  49046. $message = sprintf('Attempted to call function "%s" from the global namespace.', $functionName);
  49047. }
  49048. $candidates = [];
  49049. foreach (get_defined_functions() as $type => $definedFunctionNames) {
  49050. foreach ($definedFunctionNames as $definedFunctionName) {
  49051. if (false !== $namespaceSeparatorIndex = strrpos($definedFunctionName, '\\')) {
  49052. $definedFunctionNameBasename = substr($definedFunctionName, $namespaceSeparatorIndex + 1);
  49053. } else {
  49054. $definedFunctionNameBasename = $definedFunctionName;
  49055. }
  49056. if ($definedFunctionNameBasename === $functionName) {
  49057. $candidates[] = '\\'.$definedFunctionName;
  49058. }
  49059. }
  49060. }
  49061. if ($candidates) {
  49062. sort($candidates);
  49063. $last = array_pop($candidates).'"?';
  49064. if ($candidates) {
  49065. $candidates = 'e.g. "'.implode('", "', $candidates).'" or "'.$last;
  49066. } else {
  49067. $candidates = '"'.$last;
  49068. }
  49069. $message .= "\nDid you mean to call ".$candidates;
  49070. }
  49071. return new UndefinedFunctionException($message, $exception);
  49072. }
  49073. }
  49074. <?php
  49075. namespace Symfony\Component\Debug\FatalErrorHandler;
  49076. use Symfony\Component\Debug\Exception\FatalErrorException;
  49077. interface FatalErrorHandlerInterface
  49078. {
  49079. public function handleError(array $error, FatalErrorException $exception);
  49080. }
  49081. <?php
  49082. namespace Symfony\Component\Debug\Exception;
  49083. class FatalErrorException extends \ErrorException
  49084. {
  49085. public function __construct($message, $code, $severity, $filename, $lineno, $traceOffset = null, $traceArgs = true, array $trace = null, $previous = null)
  49086. {
  49087. parent::__construct($message, $code, $severity, $filename, $lineno, $previous);
  49088. if (null !== $trace) {
  49089. if (!$traceArgs) {
  49090. foreach ($trace as &$frame) {
  49091. unset($frame['args'], $frame['this'], $frame);
  49092. }
  49093. }
  49094. $this->setTrace($trace);
  49095. } elseif (null !== $traceOffset) {
  49096. if (\function_exists('xdebug_get_function_stack')) {
  49097. $trace = xdebug_get_function_stack();
  49098. if (0 < $traceOffset) {
  49099. array_splice($trace, -$traceOffset);
  49100. }
  49101. foreach ($trace as &$frame) {
  49102. if (!isset($frame['type'])) {
  49103. if (isset($frame['class'])) {
  49104. $frame['type'] = '::';
  49105. }
  49106. } elseif ('dynamic' === $frame['type']) {
  49107. $frame['type'] = '->';
  49108. } elseif ('static' === $frame['type']) {
  49109. $frame['type'] = '::';
  49110. }
  49111. if (!$traceArgs) {
  49112. unset($frame['params'], $frame['args']);
  49113. } elseif (isset($frame['params']) && !isset($frame['args'])) {
  49114. $frame['args'] = $frame['params'];
  49115. unset($frame['params']);
  49116. }
  49117. }
  49118. unset($frame);
  49119. $trace = array_reverse($trace);
  49120. } elseif (\function_exists('symfony_debug_backtrace')) {
  49121. $trace = symfony_debug_backtrace();
  49122. if (0 < $traceOffset) {
  49123. array_splice($trace, 0, $traceOffset);
  49124. }
  49125. } else {
  49126. $trace = [];
  49127. }
  49128. $this->setTrace($trace);
  49129. }
  49130. }
  49131. protected function setTrace($trace)
  49132. {
  49133. $traceReflector = new \ReflectionProperty('Exception', 'trace');
  49134. $traceReflector->setAccessible(true);
  49135. $traceReflector->setValue($this, $trace);
  49136. }
  49137. }
  49138. <?php
  49139. namespace Symfony\Component\Debug\Exception;
  49140. class UndefinedFunctionException extends FatalErrorException
  49141. {
  49142. public function __construct($message, \ErrorException $previous)
  49143. {
  49144. parent::__construct(
  49145. $message,
  49146. $previous->getCode(),
  49147. $previous->getSeverity(),
  49148. $previous->getFile(),
  49149. $previous->getLine(),
  49150. null,
  49151. true,
  49152. null,
  49153. $previous->getPrevious()
  49154. );
  49155. $this->setTrace($previous->getTrace());
  49156. }
  49157. }
  49158. <?php
  49159. namespace Symfony\Component\Debug\Exception;
  49160. class ContextErrorException extends \ErrorException
  49161. {
  49162. private $context = [];
  49163. public function __construct($message, $code, $severity, $filename, $lineno, $context = [])
  49164. {
  49165. parent::__construct($message, $code, $severity, $filename, $lineno);
  49166. $this->context = $context;
  49167. }
  49168. public function getContext()
  49169. {
  49170. @trigger_error(sprintf('The %s class is deprecated since Symfony 3.3 and will be removed in 4.0.', __CLASS__), E_USER_DEPRECATED);
  49171. return $this->context;
  49172. }
  49173. }
  49174. <?php
  49175. namespace Symfony\Component\Debug\Exception;
  49176. class OutOfMemoryException extends FatalErrorException
  49177. {
  49178. }
  49179. <?php
  49180. namespace Symfony\Component\Debug\Exception;
  49181. class SilencedErrorContext implements \JsonSerializable
  49182. {
  49183. public $count = 1;
  49184. private $severity;
  49185. private $file;
  49186. private $line;
  49187. private $trace;
  49188. public function __construct($severity, $file, $line, array $trace = [], $count = 1)
  49189. {
  49190. $this->severity = $severity;
  49191. $this->file = $file;
  49192. $this->line = $line;
  49193. $this->trace = $trace;
  49194. $this->count = $count;
  49195. }
  49196. public function getSeverity()
  49197. {
  49198. return $this->severity;
  49199. }
  49200. public function getFile()
  49201. {
  49202. return $this->file;
  49203. }
  49204. public function getLine()
  49205. {
  49206. return $this->line;
  49207. }
  49208. public function getTrace()
  49209. {
  49210. return $this->trace;
  49211. }
  49212. public function jsonSerialize()
  49213. {
  49214. return [
  49215. 'severity' => $this->severity,
  49216. 'file' => $this->file,
  49217. 'line' => $this->line,
  49218. 'trace' => $this->trace,
  49219. 'count' => $this->count,
  49220. ];
  49221. }
  49222. }
  49223. <?php
  49224. namespace Symfony\Component\Debug\Exception;
  49225. use Symfony\Component\HttpFoundation\Exception\RequestExceptionInterface;
  49226. use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
  49227. class FlattenException
  49228. {
  49229. private $message;
  49230. private $code;
  49231. private $previous;
  49232. private $trace;
  49233. private $class;
  49234. private $statusCode;
  49235. private $headers;
  49236. private $file;
  49237. private $line;
  49238. public static function create(\Exception $exception, $statusCode = null, array $headers = [])
  49239. {
  49240. $e = new static();
  49241. $e->setMessage($exception->getMessage());
  49242. $e->setCode($exception->getCode());
  49243. if ($exception instanceof HttpExceptionInterface) {
  49244. $statusCode = $exception->getStatusCode();
  49245. $headers = array_merge($headers, $exception->getHeaders());
  49246. } elseif ($exception instanceof RequestExceptionInterface) {
  49247. $statusCode = 400;
  49248. }
  49249. if (null === $statusCode) {
  49250. $statusCode = 500;
  49251. }
  49252. $e->setStatusCode($statusCode);
  49253. $e->setHeaders($headers);
  49254. $e->setTraceFromException($exception);
  49255. $e->setClass(\get_class($exception));
  49256. $e->setFile($exception->getFile());
  49257. $e->setLine($exception->getLine());
  49258. $previous = $exception->getPrevious();
  49259. if ($previous instanceof \Exception) {
  49260. $e->setPrevious(static::create($previous));
  49261. } elseif ($previous instanceof \Throwable) {
  49262. $e->setPrevious(static::create(new FatalThrowableError($previous)));
  49263. }
  49264. return $e;
  49265. }
  49266. public function toArray()
  49267. {
  49268. $exceptions = [];
  49269. foreach (array_merge([$this], $this->getAllPrevious()) as $exception) {
  49270. $exceptions[] = [
  49271. 'message' => $exception->getMessage(),
  49272. 'class' => $exception->getClass(),
  49273. 'trace' => $exception->getTrace(),
  49274. ];
  49275. }
  49276. return $exceptions;
  49277. }
  49278. public function getStatusCode()
  49279. {
  49280. return $this->statusCode;
  49281. }
  49282. public function setStatusCode($code)
  49283. {
  49284. $this->statusCode = $code;
  49285. }
  49286. public function getHeaders()
  49287. {
  49288. return $this->headers;
  49289. }
  49290. public function setHeaders(array $headers)
  49291. {
  49292. $this->headers = $headers;
  49293. }
  49294. public function getClass()
  49295. {
  49296. return $this->class;
  49297. }
  49298. public function setClass($class)
  49299. {
  49300. $this->class = $class;
  49301. }
  49302. public function getFile()
  49303. {
  49304. return $this->file;
  49305. }
  49306. public function setFile($file)
  49307. {
  49308. $this->file = $file;
  49309. }
  49310. public function getLine()
  49311. {
  49312. return $this->line;
  49313. }
  49314. public function setLine($line)
  49315. {
  49316. $this->line = $line;
  49317. }
  49318. public function getMessage()
  49319. {
  49320. return $this->message;
  49321. }
  49322. public function setMessage($message)
  49323. {
  49324. $this->message = $message;
  49325. }
  49326. public function getCode()
  49327. {
  49328. return $this->code;
  49329. }
  49330. public function setCode($code)
  49331. {
  49332. $this->code = $code;
  49333. }
  49334. public function getPrevious()
  49335. {
  49336. return $this->previous;
  49337. }
  49338. public function setPrevious(self $previous)
  49339. {
  49340. $this->previous = $previous;
  49341. }
  49342. public function getAllPrevious()
  49343. {
  49344. $exceptions = [];
  49345. $e = $this;
  49346. while ($e = $e->getPrevious()) {
  49347. $exceptions[] = $e;
  49348. }
  49349. return $exceptions;
  49350. }
  49351. public function getTrace()
  49352. {
  49353. return $this->trace;
  49354. }
  49355. public function setTraceFromException(\Exception $exception)
  49356. {
  49357. $this->setTrace($exception->getTrace(), $exception->getFile(), $exception->getLine());
  49358. }
  49359. public function setTrace($trace, $file, $line)
  49360. {
  49361. $this->trace = [];
  49362. $this->trace[] = [
  49363. 'namespace' => '',
  49364. 'short_class' => '',
  49365. 'class' => '',
  49366. 'type' => '',
  49367. 'function' => '',
  49368. 'file' => $file,
  49369. 'line' => $line,
  49370. 'args' => [],
  49371. ];
  49372. foreach ($trace as $entry) {
  49373. $class = '';
  49374. $namespace = '';
  49375. if (isset($entry['class'])) {
  49376. $parts = explode('\\', $entry['class']);
  49377. $class = array_pop($parts);
  49378. $namespace = implode('\\', $parts);
  49379. }
  49380. $this->trace[] = [
  49381. 'namespace' => $namespace,
  49382. 'short_class' => $class,
  49383. 'class' => isset($entry['class']) ? $entry['class'] : '',
  49384. 'type' => isset($entry['type']) ? $entry['type'] : '',
  49385. 'function' => isset($entry['function']) ? $entry['function'] : null,
  49386. 'file' => isset($entry['file']) ? $entry['file'] : null,
  49387. 'line' => isset($entry['line']) ? $entry['line'] : null,
  49388. 'args' => isset($entry['args']) ? $this->flattenArgs($entry['args']) : [],
  49389. ];
  49390. }
  49391. }
  49392. private function flattenArgs($args, $level = 0, &$count = 0)
  49393. {
  49394. $result = [];
  49395. foreach ($args as $key => $value) {
  49396. if (++$count > 1e4) {
  49397. return ['array', '*SKIPPED over 10000 entries*'];
  49398. }
  49399. if ($value instanceof \__PHP_Incomplete_Class) {
  49400. $result[$key] = ['incomplete-object', $this->getClassNameFromIncomplete($value)];
  49401. } elseif (\is_object($value)) {
  49402. $result[$key] = ['object', \get_class($value)];
  49403. } elseif (\is_array($value)) {
  49404. if ($level > 10) {
  49405. $result[$key] = ['array', '*DEEP NESTED ARRAY*'];
  49406. } else {
  49407. $result[$key] = ['array', $this->flattenArgs($value, $level + 1, $count)];
  49408. }
  49409. } elseif (null === $value) {
  49410. $result[$key] = ['null', null];
  49411. } elseif (\is_bool($value)) {
  49412. $result[$key] = ['boolean', $value];
  49413. } elseif (\is_int($value)) {
  49414. $result[$key] = ['integer', $value];
  49415. } elseif (\is_float($value)) {
  49416. $result[$key] = ['float', $value];
  49417. } elseif (\is_resource($value)) {
  49418. $result[$key] = ['resource', get_resource_type($value)];
  49419. } else {
  49420. $result[$key] = ['string', (string) $value];
  49421. }
  49422. }
  49423. return $result;
  49424. }
  49425. private function getClassNameFromIncomplete(\__PHP_Incomplete_Class $value)
  49426. {
  49427. $array = new \ArrayObject($value);
  49428. return $array['__PHP_Incomplete_Class_Name'];
  49429. }
  49430. }
  49431. <?php
  49432. namespace Symfony\Component\Debug\Exception;
  49433. class FatalThrowableError extends FatalErrorException
  49434. {
  49435. public function __construct(\Throwable $e)
  49436. {
  49437. if ($e instanceof \ParseError) {
  49438. $message = 'Parse error: '.$e->getMessage();
  49439. $severity = E_PARSE;
  49440. } elseif ($e instanceof \TypeError) {
  49441. $message = 'Type error: '.$e->getMessage();
  49442. $severity = E_RECOVERABLE_ERROR;
  49443. } else {
  49444. $message = $e->getMessage();
  49445. $severity = E_ERROR;
  49446. }
  49447. \ErrorException::__construct(
  49448. $message,
  49449. $e->getCode(),
  49450. $severity,
  49451. $e->getFile(),
  49452. $e->getLine(),
  49453. $e->getPrevious()
  49454. );
  49455. $this->setTrace($e->getTrace());
  49456. }
  49457. }
  49458. <?php
  49459. namespace Symfony\Component\Debug\Exception;
  49460. class ClassNotFoundException extends FatalErrorException
  49461. {
  49462. public function __construct($message, \ErrorException $previous)
  49463. {
  49464. parent::__construct(
  49465. $message,
  49466. $previous->getCode(),
  49467. $previous->getSeverity(),
  49468. $previous->getFile(),
  49469. $previous->getLine(),
  49470. null,
  49471. true,
  49472. null,
  49473. $previous->getPrevious()
  49474. );
  49475. $this->setTrace($previous->getTrace());
  49476. }
  49477. }
  49478. <?php
  49479. namespace Symfony\Component\Debug\Exception;
  49480. class UndefinedMethodException extends FatalErrorException
  49481. {
  49482. public function __construct($message, \ErrorException $previous)
  49483. {
  49484. parent::__construct(
  49485. $message,
  49486. $previous->getCode(),
  49487. $previous->getSeverity(),
  49488. $previous->getFile(),
  49489. $previous->getLine(),
  49490. null,
  49491. true,
  49492. null,
  49493. $previous->getPrevious()
  49494. );
  49495. $this->setTrace($previous->getTrace());
  49496. }
  49497. }
  49498. <?php
  49499. namespace Symfony\Component\Debug;
  49500. use Psr\Log\AbstractLogger;
  49501. class BufferingLogger extends AbstractLogger
  49502. {
  49503. private $logs = [];
  49504. public function log($level, $message, array $context = [])
  49505. {
  49506. $this->logs[] = [$level, $message, $context];
  49507. }
  49508. public function cleanLogs()
  49509. {
  49510. $logs = $this->logs;
  49511. $this->logs = [];
  49512. return $logs;
  49513. }
  49514. }
  49515. <?php
  49516. namespace Symfony\Component\Debug;
  49517. class Debug
  49518. {
  49519. private static $enabled = false;
  49520. public static function enable($errorReportingLevel = E_ALL, $displayErrors = true)
  49521. {
  49522. if (static::$enabled) {
  49523. return;
  49524. }
  49525. static::$enabled = true;
  49526. if (null !== $errorReportingLevel) {
  49527. error_reporting($errorReportingLevel);
  49528. } else {
  49529. error_reporting(E_ALL);
  49530. }
  49531. if (!\in_array(\PHP_SAPI, ['cli', 'phpdbg'], true)) {
  49532. ini_set('display_errors', 0);
  49533. ExceptionHandler::register();
  49534. } elseif ($displayErrors && (!filter_var(ini_get('log_errors'), FILTER_VALIDATE_BOOLEAN) || ini_get('error_log'))) {
  49535. ini_set('display_errors', 1);
  49536. }
  49537. if ($displayErrors) {
  49538. ErrorHandler::register(new ErrorHandler(new BufferingLogger()));
  49539. } else {
  49540. ErrorHandler::register()->throwAt(0, true);
  49541. }
  49542. DebugClassLoader::enable();
  49543. }
  49544. }
  49545. <?php
  49546. use Symfony\Polyfill\Php72 as p;
  49547. if (PHP_VERSION_ID >= 70200) {
  49548. return;
  49549. }
  49550. if (!defined('PHP_FLOAT_DIG')) {
  49551. define('PHP_FLOAT_DIG', 15);
  49552. }
  49553. if (!defined('PHP_FLOAT_EPSILON')) {
  49554. define('PHP_FLOAT_EPSILON', 2.2204460492503E-16);
  49555. }
  49556. if (!defined('PHP_FLOAT_MIN')) {
  49557. define('PHP_FLOAT_MIN', 2.2250738585072E-308);
  49558. }
  49559. if (!defined('PHP_FLOAT_MAX')) {
  49560. define('PHP_FLOAT_MAX', 1.7976931348623157E+308);
  49561. }
  49562. if (!defined('PHP_OS_FAMILY')) {
  49563. define('PHP_OS_FAMILY', p\Php72::php_os_family());
  49564. }
  49565. if ('\\' === DIRECTORY_SEPARATOR && !function_exists('sapi_windows_vt100_support')) {
  49566. function sapi_windows_vt100_support($stream, $enable = null) { return p\Php72::sapi_windows_vt100_support($stream, $enable); }
  49567. }
  49568. if (!function_exists('stream_isatty')) {
  49569. function stream_isatty($stream) { return p\Php72::stream_isatty($stream); }
  49570. }
  49571. if (!function_exists('utf8_encode')) {
  49572. function utf8_encode($s) { return p\Php72::utf8_encode($s); }
  49573. }
  49574. if (!function_exists('utf8_decode')) {
  49575. function utf8_decode($s) { return p\Php72::utf8_decode($s); }
  49576. }
  49577. if (!function_exists('spl_object_id')) {
  49578. function spl_object_id($s) { return p\Php72::spl_object_id($s); }
  49579. }
  49580. if (!function_exists('mb_ord')) {
  49581. function mb_ord($s, $enc = null) { return p\Php72::mb_ord($s, $enc); }
  49582. }
  49583. if (!function_exists('mb_chr')) {
  49584. function mb_chr($code, $enc = null) { return p\Php72::mb_chr($code, $enc); }
  49585. }
  49586. if (!function_exists('mb_scrub')) {
  49587. function mb_scrub($s, $enc = null) { $enc = null === $enc ? mb_internal_encoding() : $enc; return mb_convert_encoding($s, $enc, $enc); }
  49588. }
  49589. <?php
  49590. namespace Symfony\Polyfill\Php72;
  49591. /**
  49592. @gmail
  49593. */
  49594. final class Php72
  49595. {
  49596. private static $hashMask;
  49597. public static function utf8_encode($s)
  49598. {
  49599. $s .= $s;
  49600. $len = \strlen($s);
  49601. for ($i = $len >> 1, $j = 0; $i < $len; ++$i, ++$j) {
  49602. switch (true) {
  49603. case $s[$i] < "\x80": $s[$j] = $s[$i]; break;
  49604. case $s[$i] < "\xC0": $s[$j] = "\xC2"; $s[++$j] = $s[$i]; break;
  49605. default: $s[$j] = "\xC3"; $s[++$j] = \chr(\ord($s[$i]) - 64); break;
  49606. }
  49607. }
  49608. return substr($s, 0, $j);
  49609. }
  49610. public static function utf8_decode($s)
  49611. {
  49612. $s = (string) $s;
  49613. $len = \strlen($s);
  49614. for ($i = 0, $j = 0; $i < $len; ++$i, ++$j) {
  49615. switch ($s[$i] & "\xF0") {
  49616. case "\xC0":
  49617. case "\xD0":
  49618. $c = (\ord($s[$i] & "\x1F") << 6) | \ord($s[++$i] & "\x3F");
  49619. $s[$j] = $c < 256 ? \chr($c) : '?';
  49620. break;
  49621. case "\xF0":
  49622. ++$i;
  49623. case "\xE0":
  49624. $s[$j] = '?';
  49625. $i += 2;
  49626. break;
  49627. default:
  49628. $s[$j] = $s[$i];
  49629. }
  49630. }
  49631. return substr($s, 0, $j);
  49632. }
  49633. public static function php_os_family()
  49634. {
  49635. if ('\\' === \DIRECTORY_SEPARATOR) {
  49636. return 'Windows';
  49637. }
  49638. $map = array(
  49639. 'Darwin' => 'Darwin',
  49640. 'DragonFly' => 'BSD',
  49641. 'FreeBSD' => 'BSD',
  49642. 'NetBSD' => 'BSD',
  49643. 'OpenBSD' => 'BSD',
  49644. 'Linux' => 'Linux',
  49645. 'SunOS' => 'Solaris',
  49646. );
  49647. return isset($map[PHP_OS]) ? $map[PHP_OS] : 'Unknown';
  49648. }
  49649. public static function spl_object_id($object)
  49650. {
  49651. if (null === self::$hashMask) {
  49652. self::initHashMask();
  49653. }
  49654. if (null === $hash = spl_object_hash($object)) {
  49655. return;
  49656. }
  49657. return self::$hashMask ^ hexdec(substr($hash, 16 - (\PHP_INT_SIZE * 2 - 1), (\PHP_INT_SIZE * 2 - 1)));
  49658. }
  49659. public static function sapi_windows_vt100_support($stream, $enable = null)
  49660. {
  49661. if (!\is_resource($stream)) {
  49662. trigger_error('sapi_windows_vt100_support() expects parameter 1 to be resource, '.\gettype($stream).' given', E_USER_WARNING);
  49663. return false;
  49664. }
  49665. $meta = stream_get_meta_data($stream);
  49666. if ('STDIO' !== $meta['stream_type']) {
  49667. trigger_error('sapi_windows_vt100_support() was not able to analyze the specified stream', E_USER_WARNING);
  49668. return false;
  49669. }
  49670. if (false === $enable || !self::stream_isatty($stream)) {
  49671. return false;
  49672. }
  49673. $meta = array_map('strtolower', $meta);
  49674. $stdin = 'php://stdin' === $meta['uri'] || 'php://fd/0' === $meta['uri'];
  49675. return !$stdin
  49676. && (false !== getenv('ANSICON')
  49677. || 'ON' === getenv('ConEmuANSI')
  49678. || 'xterm' === getenv('TERM')
  49679. || 'Hyper' === getenv('TERM_PROGRAM'));
  49680. }
  49681. public static function stream_isatty($stream)
  49682. {
  49683. if (!\is_resource($stream)) {
  49684. trigger_error('stream_isatty() expects parameter 1 to be resource, '.\gettype($stream).' given', E_USER_WARNING);
  49685. return false;
  49686. }
  49687. if ('\\' === \DIRECTORY_SEPARATOR) {
  49688. $stat = @fstat($stream);
  49689. return $stat ? 0020000 === ($stat['mode'] & 0170000) : false;
  49690. }
  49691. return \function_exists('posix_isatty') && @posix_isatty($stream);
  49692. }
  49693. private static function initHashMask()
  49694. {
  49695. $obj = (object) array();
  49696. self::$hashMask = -1;
  49697. $obFuncs = array('ob_clean', 'ob_end_clean', 'ob_flush', 'ob_end_flush', 'ob_get_contents', 'ob_get_flush');
  49698. foreach (debug_backtrace(\PHP_VERSION_ID >= 50400 ? DEBUG_BACKTRACE_IGNORE_ARGS : false) as $frame) {
  49699. if (isset($frame['function'][0]) && !isset($frame['class']) && 'o' === $frame['function'][0] && \in_array($frame['function'], $obFuncs)) {
  49700. $frame['line'] = 0;
  49701. break;
  49702. }
  49703. }
  49704. if (!empty($frame['line'])) {
  49705. ob_start();
  49706. debug_zval_dump($obj);
  49707. self::$hashMask = (int) substr(ob_get_clean(), 17);
  49708. }
  49709. self::$hashMask ^= hexdec(substr(spl_object_hash($obj), 16 - (\PHP_INT_SIZE * 2 - 1), (\PHP_INT_SIZE * 2 - 1)));
  49710. }
  49711. public static function mb_chr($code, $encoding = null)
  49712. {
  49713. if (0x80 > $code %= 0x200000) {
  49714. $s = \chr($code);
  49715. } elseif (0x800 > $code) {
  49716. $s = \chr(0xC0 | $code >> 6).\chr(0x80 | $code & 0x3F);
  49717. } elseif (0x10000 > $code) {
  49718. $s = \chr(0xE0 | $code >> 12).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F);
  49719. } else {
  49720. $s = \chr(0xF0 | $code >> 18).\chr(0x80 | $code >> 12 & 0x3F).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F);
  49721. }
  49722. if ('UTF-8' !== $encoding) {
  49723. $s = mb_convert_encoding($s, $encoding, 'UTF-8');
  49724. }
  49725. return $s;
  49726. }
  49727. public static function mb_ord($s, $encoding = null)
  49728. {
  49729. if (null == $encoding) {
  49730. $s = mb_convert_encoding($s, 'UTF-8');
  49731. } elseif ('UTF-8' !== $encoding) {
  49732. $s = mb_convert_encoding($s, 'UTF-8', $encoding);
  49733. }
  49734. if (1 === \strlen($s)) {
  49735. return \ord($s);
  49736. }
  49737. $code = ($s = unpack('C*', substr($s, 0, 4))) ? $s[1] : 0;
  49738. if (0xF0 <= $code) {
  49739. return (($code - 0xF0) << 18) + (($s[2] - 0x80) << 12) + (($s[3] - 0x80) << 6) + $s[4] - 0x80;
  49740. }
  49741. if (0xE0 <= $code) {
  49742. return (($code - 0xE0) << 12) + (($s[2] - 0x80) << 6) + $s[3] - 0x80;
  49743. }
  49744. if (0xC0 <= $code) {
  49745. return (($code - 0xC0) << 6) + $s[2] - 0x80;
  49746. }
  49747. return $code;
  49748. }
  49749. }
  49750. <?php
  49751. use Symfony\Polyfill\Ctype as p;
  49752. if (!function_exists('ctype_alnum')) {
  49753. function ctype_alnum($text) { return p\Ctype::ctype_alnum($text); }
  49754. }
  49755. if (!function_exists('ctype_alpha')) {
  49756. function ctype_alpha($text) { return p\Ctype::ctype_alpha($text); }
  49757. }
  49758. if (!function_exists('ctype_cntrl')) {
  49759. function ctype_cntrl($text) { return p\Ctype::ctype_cntrl($text); }
  49760. }
  49761. if (!function_exists('ctype_digit')) {
  49762. function ctype_digit($text) { return p\Ctype::ctype_digit($text); }
  49763. }
  49764. if (!function_exists('ctype_graph')) {
  49765. function ctype_graph($text) { return p\Ctype::ctype_graph($text); }
  49766. }
  49767. if (!function_exists('ctype_lower')) {
  49768. function ctype_lower($text) { return p\Ctype::ctype_lower($text); }
  49769. }
  49770. if (!function_exists('ctype_print')) {
  49771. function ctype_print($text) { return p\Ctype::ctype_print($text); }
  49772. }
  49773. if (!function_exists('ctype_punct')) {
  49774. function ctype_punct($text) { return p\Ctype::ctype_punct($text); }
  49775. }
  49776. if (!function_exists('ctype_space')) {
  49777. function ctype_space($text) { return p\Ctype::ctype_space($text); }
  49778. }
  49779. if (!function_exists('ctype_upper')) {
  49780. function ctype_upper($text) { return p\Ctype::ctype_upper($text); }
  49781. }
  49782. if (!function_exists('ctype_xdigit')) {
  49783. function ctype_xdigit($text) { return p\Ctype::ctype_xdigit($text); }
  49784. }
  49785. <?php
  49786. namespace Symfony\Polyfill\Ctype;
  49787. final class Ctype
  49788. {
  49789. public static function ctype_alnum($text)
  49790. {
  49791. $text = self::convert_int_to_char_for_ctype($text);
  49792. return \is_string($text) && '' !== $text && !preg_match('/[^A-Za-z0-9]/', $text);
  49793. }
  49794. public static function ctype_alpha($text)
  49795. {
  49796. $text = self::convert_int_to_char_for_ctype($text);
  49797. return \is_string($text) && '' !== $text && !preg_match('/[^A-Za-z]/', $text);
  49798. }
  49799. public static function ctype_cntrl($text)
  49800. {
  49801. $text = self::convert_int_to_char_for_ctype($text);
  49802. return \is_string($text) && '' !== $text && !preg_match('/[^\x00-\x1f\x7f]/', $text);
  49803. }
  49804. public static function ctype_digit($text)
  49805. {
  49806. $text = self::convert_int_to_char_for_ctype($text);
  49807. return \is_string($text) && '' !== $text && !preg_match('/[^0-9]/', $text);
  49808. }
  49809. public static function ctype_graph($text)
  49810. {
  49811. $text = self::convert_int_to_char_for_ctype($text);
  49812. return \is_string($text) && '' !== $text && !preg_match('/[^!-~]/', $text);
  49813. }
  49814. public static function ctype_lower($text)
  49815. {
  49816. $text = self::convert_int_to_char_for_ctype($text);
  49817. return \is_string($text) && '' !== $text && !preg_match('/[^a-z]/', $text);
  49818. }
  49819. public static function ctype_print($text)
  49820. {
  49821. $text = self::convert_int_to_char_for_ctype($text);
  49822. return \is_string($text) && '' !== $text && !preg_match('/[^ -~]/', $text);
  49823. }
  49824. public static function ctype_punct($text)
  49825. {
  49826. $text = self::convert_int_to_char_for_ctype($text);
  49827. return \is_string($text) && '' !== $text && !preg_match('/[^!-\/\:-@\[-`\{-~]/', $text);
  49828. }
  49829. public static function ctype_space($text)
  49830. {
  49831. $text = self::convert_int_to_char_for_ctype($text);
  49832. return \is_string($text) && '' !== $text && !preg_match('/[^\s]/', $text);
  49833. }
  49834. public static function ctype_upper($text)
  49835. {
  49836. $text = self::convert_int_to_char_for_ctype($text);
  49837. return \is_string($text) && '' !== $text && !preg_match('/[^A-Z]/', $text);
  49838. }
  49839. public static function ctype_xdigit($text)
  49840. {
  49841. $text = self::convert_int_to_char_for_ctype($text);
  49842. return \is_string($text) && '' !== $text && !preg_match('/[^A-Fa-f0-9]/', $text);
  49843. }
  49844. private static function convert_int_to_char_for_ctype($int)
  49845. {
  49846. if (!\is_int($int)) {
  49847. return $int;
  49848. }
  49849. if ($int < -128 || $int > 255) {
  49850. return (string) $int;
  49851. }
  49852. if ($int < 0) {
  49853. $int += 256;
  49854. }
  49855. return \chr($int);
  49856. }
  49857. }
  49858. <?php
  49859. use Symfony\Polyfill\Mbstring as p;
  49860. if (!function_exists('mb_convert_encoding')) {
  49861. function mb_convert_encoding($s, $to, $from = null) { return p\Mbstring::mb_convert_encoding($s, $to, $from); }
  49862. }
  49863. if (!function_exists('mb_decode_mimeheader')) {
  49864. function mb_decode_mimeheader($s) { return p\Mbstring::mb_decode_mimeheader($s); }
  49865. }
  49866. if (!function_exists('mb_encode_mimeheader')) {
  49867. function mb_encode_mimeheader($s, $charset = null, $transferEnc = null, $lf = null, $indent = null) { return p\Mbstring::mb_encode_mimeheader($s, $charset, $transferEnc, $lf, $indent); }
  49868. }
  49869. if (!function_exists('mb_decode_numericentity')) {
  49870. function mb_decode_numericentity($s, $convmap, $enc = null) { return p\Mbstring::mb_decode_numericentity($s, $convmap, $enc); }
  49871. }
  49872. if (!function_exists('mb_encode_numericentity')) {
  49873. function mb_encode_numericentity($s, $convmap, $enc = null, $is_hex = false) { return p\Mbstring::mb_encode_numericentity($s, $convmap, $enc, $is_hex); }
  49874. }
  49875. if (!function_exists('mb_convert_case')) {
  49876. function mb_convert_case($s, $mode, $enc = null) { return p\Mbstring::mb_convert_case($s, $mode, $enc); }
  49877. }
  49878. if (!function_exists('mb_internal_encoding')) {
  49879. function mb_internal_encoding($enc = null) { return p\Mbstring::mb_internal_encoding($enc); }
  49880. }
  49881. if (!function_exists('mb_language')) {
  49882. function mb_language($lang = null) { return p\Mbstring::mb_language($lang); }
  49883. }
  49884. if (!function_exists('mb_list_encodings')) {
  49885. function mb_list_encodings() { return p\Mbstring::mb_list_encodings(); }
  49886. }
  49887. if (!function_exists('mb_encoding_aliases')) {
  49888. function mb_encoding_aliases($encoding) { return p\Mbstring::mb_encoding_aliases($encoding); }
  49889. }
  49890. if (!function_exists('mb_check_encoding')) {
  49891. function mb_check_encoding($var = null, $encoding = null) { return p\Mbstring::mb_check_encoding($var, $encoding); }
  49892. }
  49893. if (!function_exists('mb_detect_encoding')) {
  49894. function mb_detect_encoding($str, $encodingList = null, $strict = false) { return p\Mbstring::mb_detect_encoding($str, $encodingList, $strict); }
  49895. }
  49896. if (!function_exists('mb_detect_order')) {
  49897. function mb_detect_order($encodingList = null) { return p\Mbstring::mb_detect_order($encodingList); }
  49898. }
  49899. if (!function_exists('mb_parse_str')) {
  49900. function mb_parse_str($s, &$result = array()) { parse_str($s, $result); }
  49901. }
  49902. if (!function_exists('mb_strlen')) {
  49903. function mb_strlen($s, $enc = null) { return p\Mbstring::mb_strlen($s, $enc); }
  49904. }
  49905. if (!function_exists('mb_strpos')) {
  49906. function mb_strpos($s, $needle, $offset = 0, $enc = null) { return p\Mbstring::mb_strpos($s, $needle, $offset, $enc); }
  49907. }
  49908. if (!function_exists('mb_strtolower')) {
  49909. function mb_strtolower($s, $enc = null) { return p\Mbstring::mb_strtolower($s, $enc); }
  49910. }
  49911. if (!function_exists('mb_strtoupper')) {
  49912. function mb_strtoupper($s, $enc = null) { return p\Mbstring::mb_strtoupper($s, $enc); }
  49913. }
  49914. if (!function_exists('mb_substitute_character')) {
  49915. function mb_substitute_character($char = null) { return p\Mbstring::mb_substitute_character($char); }
  49916. }
  49917. if (!function_exists('mb_substr')) {
  49918. function mb_substr($s, $start, $length = 2147483647, $enc = null) { return p\Mbstring::mb_substr($s, $start, $length, $enc); }
  49919. }
  49920. if (!function_exists('mb_stripos')) {
  49921. function mb_stripos($s, $needle, $offset = 0, $enc = null) { return p\Mbstring::mb_stripos($s, $needle, $offset, $enc); }
  49922. }
  49923. if (!function_exists('mb_stristr')) {
  49924. function mb_stristr($s, $needle, $part = false, $enc = null) { return p\Mbstring::mb_stristr($s, $needle, $part, $enc); }
  49925. }
  49926. if (!function_exists('mb_strrchr')) {
  49927. function mb_strrchr($s, $needle, $part = false, $enc = null) { return p\Mbstring::mb_strrchr($s, $needle, $part, $enc); }
  49928. }
  49929. if (!function_exists('mb_strrichr')) {
  49930. function mb_strrichr($s, $needle, $part = false, $enc = null) { return p\Mbstring::mb_strrichr($s, $needle, $part, $enc); }
  49931. }
  49932. if (!function_exists('mb_strripos')) {
  49933. function mb_strripos($s, $needle, $offset = 0, $enc = null) { return p\Mbstring::mb_strripos($s, $needle, $offset, $enc); }
  49934. }
  49935. if (!function_exists('mb_strrpos')) {
  49936. function mb_strrpos($s, $needle, $offset = 0, $enc = null) { return p\Mbstring::mb_strrpos($s, $needle, $offset, $enc); }
  49937. }
  49938. if (!function_exists('mb_strstr')) {
  49939. function mb_strstr($s, $needle, $part = false, $enc = null) { return p\Mbstring::mb_strstr($s, $needle, $part, $enc); }
  49940. }
  49941. if (!function_exists('mb_get_info')) {
  49942. function mb_get_info($type = 'all') { return p\Mbstring::mb_get_info($type); }
  49943. }
  49944. if (!function_exists('mb_http_output')) {
  49945. function mb_http_output($enc = null) { return p\Mbstring::mb_http_output($enc); }
  49946. }
  49947. if (!function_exists('mb_strwidth')) {
  49948. function mb_strwidth($s, $enc = null) { return p\Mbstring::mb_strwidth($s, $enc); }
  49949. }
  49950. if (!function_exists('mb_substr_count')) {
  49951. function mb_substr_count($haystack, $needle, $enc = null) { return p\Mbstring::mb_substr_count($haystack, $needle, $enc); }
  49952. }
  49953. if (!function_exists('mb_output_handler')) {
  49954. function mb_output_handler($contents, $status) { return p\Mbstring::mb_output_handler($contents, $status); }
  49955. }
  49956. if (!function_exists('mb_http_input')) {
  49957. function mb_http_input($type = '') { return p\Mbstring::mb_http_input($type); }
  49958. }
  49959. if (!function_exists('mb_convert_variables')) {
  49960. function mb_convert_variables($toEncoding, $fromEncoding, &$a = null, &$b = null, &$c = null, &$d = null, &$e = null, &$f = null) { return p\Mbstring::mb_convert_variables($toEncoding, $fromEncoding, $a, $b, $c, $d, $e, $f); }
  49961. }
  49962. if (!function_exists('mb_ord')) {
  49963. function mb_ord($s, $enc = null) { return p\Mbstring::mb_ord($s, $enc); }
  49964. }
  49965. if (!function_exists('mb_chr')) {
  49966. function mb_chr($code, $enc = null) { return p\Mbstring::mb_chr($code, $enc); }
  49967. }
  49968. if (!function_exists('mb_scrub')) {
  49969. function mb_scrub($s, $enc = null) { $enc = null === $enc ? mb_internal_encoding() : $enc; return mb_convert_encoding($s, $enc, $enc); }
  49970. }
  49971. if (!function_exists('mb_str_split')) {
  49972. function mb_str_split($string, $split_length = 1, $encoding = null) { return p\Mbstring::mb_str_split($string, $split_length, $encoding); }
  49973. }
  49974. if (extension_loaded('mbstring')) {
  49975. return;
  49976. }
  49977. if (!defined('MB_CASE_UPPER')) {
  49978. define('MB_CASE_UPPER', 0);
  49979. }
  49980. if (!defined('MB_CASE_LOWER')) {
  49981. define('MB_CASE_LOWER', 1);
  49982. }
  49983. if (!defined('MB_CASE_TITLE')) {
  49984. define('MB_CASE_TITLE', 2);
  49985. }
  49986. <?php
  49987. namespace Symfony\Polyfill\Mbstring;
  49988. final class Mbstring
  49989. {
  49990. const MB_CASE_FOLD = PHP_INT_MAX;
  49991. private static $encodingList = array('ASCII', 'UTF-8');
  49992. private static $language = 'neutral';
  49993. private static $internalEncoding = 'UTF-8';
  49994. private static $caseFold = array(
  49995. array('µ', 'ſ', "\xCD\x85", 'ς', "\xCF\x90", "\xCF\x91", "\xCF\x95", "\xCF\x96", "\xCF\xB0", "\xCF\xB1", "\xCF\xB5", "\xE1\xBA\x9B", "\xE1\xBE\xBE"),
  49996. array('μ', 's', 'ι', 'σ', 'β', 'θ', 'φ', 'π', 'κ', '�', 'ε', "\xE1\xB9\xA1", 'ι'),
  49997. );
  49998. public static function mb_convert_encoding($s, $toEncoding, $fromEncoding = null)
  49999. {
  50000. if (\is_array($fromEncoding) || false !== strpos($fromEncoding, ',')) {
  50001. $fromEncoding = self::mb_detect_encoding($s, $fromEncoding);
  50002. } else {
  50003. $fromEncoding = self::getEncoding($fromEncoding);
  50004. }
  50005. $toEncoding = self::getEncoding($toEncoding);
  50006. if ('BASE64' === $fromEncoding) {
  50007. $s = base64_decode($s);
  50008. $fromEncoding = $toEncoding;
  50009. }
  50010. if ('BASE64' === $toEncoding) {
  50011. return base64_encode($s);
  50012. }
  50013. if ('HTML-ENTITIES' === $toEncoding || 'HTML' === $toEncoding) {
  50014. if ('HTML-ENTITIES' === $fromEncoding || 'HTML' === $fromEncoding) {
  50015. $fromEncoding = 'Windows-1252';
  50016. }
  50017. if ('UTF-8' !== $fromEncoding) {
  50018. $s = iconv($fromEncoding, 'UTF-8//IGNORE', $s);
  50019. }
  50020. return preg_replace_callback('/[\x80-\xFF]+/', array(__CLASS__, 'html_encoding_callback'), $s);
  50021. }
  50022. if ('HTML-ENTITIES' === $fromEncoding) {
  50023. $s = html_entity_decode($s, ENT_COMPAT, 'UTF-8');
  50024. $fromEncoding = 'UTF-8';
  50025. }
  50026. return iconv($fromEncoding, $toEncoding.'//IGNORE', $s);
  50027. }
  50028. public static function mb_convert_variables($toEncoding, $fromEncoding, &$a = null, &$b = null, &$c = null, &$d = null, &$e = null, &$f = null)
  50029. {
  50030. $vars = array(&$a, &$b, &$c, &$d, &$e, &$f);
  50031. $ok = true;
  50032. array_walk_recursive($vars, function (&$v) use (&$ok, $toEncoding, $fromEncoding) {
  50033. if (false === $v = Mbstring::mb_convert_encoding($v, $toEncoding, $fromEncoding)) {
  50034. $ok = false;
  50035. }
  50036. });
  50037. return $ok ? $fromEncoding : false;
  50038. }
  50039. public static function mb_decode_mimeheader($s)
  50040. {
  50041. return iconv_mime_decode($s, 2, self::$internalEncoding);
  50042. }
  50043. public static function mb_encode_mimeheader($s, $charset = null, $transferEncoding = null, $linefeed = null, $indent = null)
  50044. {
  50045. trigger_error('mb_encode_mimeheader() is bugged. Please use iconv_mime_encode() instead', E_USER_WARNING);
  50046. }
  50047. public static function mb_decode_numericentity($s, $convmap, $encoding = null)
  50048. {
  50049. if (null !== $s && !\is_scalar($s) && !(\is_object($s) && \method_exists($s, '__toString'))) {
  50050. trigger_error('mb_decode_numericentity() expects parameter 1 to be string, '.\gettype($s).' given', E_USER_WARNING);
  50051. return null;
  50052. }
  50053. if (!\is_array($convmap) || !$convmap) {
  50054. return false;
  50055. }
  50056. if (null !== $encoding && !\is_scalar($encoding)) {
  50057. trigger_error('mb_decode_numericentity() expects parameter 3 to be string, '.\gettype($s).' given', E_USER_WARNING);
  50058. return '';
  50059. }
  50060. $s = (string) $s;
  50061. if ('' === $s) {
  50062. return '';
  50063. }
  50064. $encoding = self::getEncoding($encoding);
  50065. if ('UTF-8' === $encoding) {
  50066. $encoding = null;
  50067. if (!preg_match('//u', $s)) {
  50068. $s = @iconv('UTF-8', 'UTF-8//IGNORE', $s);
  50069. }
  50070. } else {
  50071. $s = iconv($encoding, 'UTF-8//IGNORE', $s);
  50072. }
  50073. $cnt = floor(\count($convmap) / 4) * 4;
  50074. for ($i = 0; $i < $cnt; $i += 4) {
  50075. $convmap[$i] += $convmap[$i + 2];
  50076. $convmap[$i + 1] += $convmap[$i + 2];
  50077. }
  50078. $s = preg_replace_callback('/&#(?:0*([0-9]+)|x0*([0-9a-fA-F]+))(?!&);?/', function (array $m) use ($cnt, $convmap) {
  50079. $c = isset($m[2]) ? (int) hexdec($m[2]) : $m[1];
  50080. for ($i = 0; $i < $cnt; $i += 4) {
  50081. if ($c >= $convmap[$i] && $c <= $convmap[$i + 1]) {
  50082. return Mbstring::mb_chr($c - $convmap[$i + 2]);
  50083. }
  50084. }
  50085. return $m[0];
  50086. }, $s);
  50087. if (null === $encoding) {
  50088. return $s;
  50089. }
  50090. return iconv('UTF-8', $encoding.'//IGNORE', $s);
  50091. }
  50092. public static function mb_encode_numericentity($s, $convmap, $encoding = null, $is_hex = false)
  50093. {
  50094. if (null !== $s && !\is_scalar($s) && !(\is_object($s) && \method_exists($s, '__toString'))) {
  50095. trigger_error('mb_encode_numericentity() expects parameter 1 to be string, '.\gettype($s).' given', E_USER_WARNING);
  50096. return null;
  50097. }
  50098. if (!\is_array($convmap) || !$convmap) {
  50099. return false;
  50100. }
  50101. if (null !== $encoding && !\is_scalar($encoding)) {
  50102. trigger_error('mb_encode_numericentity() expects parameter 3 to be string, '.\gettype($s).' given', E_USER_WARNING);
  50103. return null;
  50104. }
  50105. if (null !== $is_hex && !\is_scalar($is_hex)) {
  50106. trigger_error('mb_encode_numericentity() expects parameter 4 to be boolean, '.\gettype($s).' given', E_USER_WARNING);
  50107. return null;
  50108. }
  50109. $s = (string) $s;
  50110. if ('' === $s) {
  50111. return '';
  50112. }
  50113. $encoding = self::getEncoding($encoding);
  50114. if ('UTF-8' === $encoding) {
  50115. $encoding = null;
  50116. if (!preg_match('//u', $s)) {
  50117. $s = @iconv('UTF-8', 'UTF-8//IGNORE', $s);
  50118. }
  50119. } else {
  50120. $s = iconv($encoding, 'UTF-8//IGNORE', $s);
  50121. }
  50122. static $ulenMask = array("\xC0" => 2, "\xD0" => 2, "\xE0" => 3, "\xF0" => 4);
  50123. $cnt = floor(\count($convmap) / 4) * 4;
  50124. $i = 0;
  50125. $len = \strlen($s);
  50126. $result = '';
  50127. while ($i < $len) {
  50128. $ulen = $s[$i] < "\x80" ? 1 : $ulenMask[$s[$i] & "\xF0"];
  50129. $uchr = substr($s, $i, $ulen);
  50130. $i += $ulen;
  50131. $c = self::mb_ord($uchr);
  50132. for ($j = 0; $j < $cnt; $j += 4) {
  50133. if ($c >= $convmap[$j] && $c <= $convmap[$j + 1]) {
  50134. $cOffset = ($c + $convmap[$j + 2]) & $convmap[$j + 3];
  50135. $result .= $is_hex ? sprintf('&#x%X;', $cOffset) : '&#'.$cOffset.';';
  50136. continue 2;
  50137. }
  50138. }
  50139. $result .= $uchr;
  50140. }
  50141. if (null === $encoding) {
  50142. return $result;
  50143. }
  50144. return iconv('UTF-8', $encoding.'//IGNORE', $result);
  50145. }
  50146. public static function mb_convert_case($s, $mode, $encoding = null)
  50147. {
  50148. $s = (string) $s;
  50149. if ('' === $s) {
  50150. return '';
  50151. }
  50152. $encoding = self::getEncoding($encoding);
  50153. if ('UTF-8' === $encoding) {
  50154. $encoding = null;
  50155. if (!preg_match('//u', $s)) {
  50156. $s = @iconv('UTF-8', 'UTF-8//IGNORE', $s);
  50157. }
  50158. } else {
  50159. $s = iconv($encoding, 'UTF-8//IGNORE', $s);
  50160. }
  50161. if (MB_CASE_TITLE == $mode) {
  50162. static $titleRegexp = null;
  50163. if (null === $titleRegexp) {
  50164. $titleRegexp = self::getData('titleCaseRegexp');
  50165. }
  50166. $s = preg_replace_callback($titleRegexp, array(__CLASS__, 'title_case'), $s);
  50167. } else {
  50168. if (MB_CASE_UPPER == $mode) {
  50169. static $upper = null;
  50170. if (null === $upper) {
  50171. $upper = self::getData('upperCase');
  50172. }
  50173. $map = $upper;
  50174. } else {
  50175. if (self::MB_CASE_FOLD === $mode) {
  50176. $s = str_replace(self::$caseFold[0], self::$caseFold[1], $s);
  50177. }
  50178. static $lower = null;
  50179. if (null === $lower) {
  50180. $lower = self::getData('lowerCase');
  50181. }
  50182. $map = $lower;
  50183. }
  50184. static $ulenMask = array("\xC0" => 2, "\xD0" => 2, "\xE0" => 3, "\xF0" => 4);
  50185. $i = 0;
  50186. $len = \strlen($s);
  50187. while ($i < $len) {
  50188. $ulen = $s[$i] < "\x80" ? 1 : $ulenMask[$s[$i] & "\xF0"];
  50189. $uchr = substr($s, $i, $ulen);
  50190. $i += $ulen;
  50191. if (isset($map[$uchr])) {
  50192. $uchr = $map[$uchr];
  50193. $nlen = \strlen($uchr);
  50194. if ($nlen == $ulen) {
  50195. $nlen = $i;
  50196. do {
  50197. $s[--$nlen] = $uchr[--$ulen];
  50198. } while ($ulen);
  50199. } else {
  50200. $s = substr_replace($s, $uchr, $i - $ulen, $ulen);
  50201. $len += $nlen - $ulen;
  50202. $i += $nlen - $ulen;
  50203. }
  50204. }
  50205. }
  50206. }
  50207. if (null === $encoding) {
  50208. return $s;
  50209. }
  50210. return iconv('UTF-8', $encoding.'//IGNORE', $s);
  50211. }
  50212. public static function mb_internal_encoding($encoding = null)
  50213. {
  50214. if (null === $encoding) {
  50215. return self::$internalEncoding;
  50216. }
  50217. $encoding = self::getEncoding($encoding);
  50218. if ('UTF-8' === $encoding || false !== @iconv($encoding, $encoding, ' ')) {
  50219. self::$internalEncoding = $encoding;
  50220. return true;
  50221. }
  50222. return false;
  50223. }
  50224. public static function mb_language($lang = null)
  50225. {
  50226. if (null === $lang) {
  50227. return self::$language;
  50228. }
  50229. switch ($lang = strtolower($lang)) {
  50230. case 'uni':
  50231. case 'neutral':
  50232. self::$language = $lang;
  50233. return true;
  50234. }
  50235. return false;
  50236. }
  50237. public static function mb_list_encodings()
  50238. {
  50239. return array('UTF-8');
  50240. }
  50241. public static function mb_encoding_aliases($encoding)
  50242. {
  50243. switch (strtoupper($encoding)) {
  50244. case 'UTF8':
  50245. case 'UTF-8':
  50246. return array('utf8');
  50247. }
  50248. return false;
  50249. }
  50250. public static function mb_check_encoding($var = null, $encoding = null)
  50251. {
  50252. if (null === $encoding) {
  50253. if (null === $var) {
  50254. return false;
  50255. }
  50256. $encoding = self::$internalEncoding;
  50257. }
  50258. return self::mb_detect_encoding($var, array($encoding)) || false !== @iconv($encoding, $encoding, $var);
  50259. }
  50260. public static function mb_detect_encoding($str, $encodingList = null, $strict = false)
  50261. {
  50262. if (null === $encodingList) {
  50263. $encodingList = self::$encodingList;
  50264. } else {
  50265. if (!\is_array($encodingList)) {
  50266. $encodingList = array_map('trim', explode(',', $encodingList));
  50267. }
  50268. $encodingList = array_map('strtoupper', $encodingList);
  50269. }
  50270. foreach ($encodingList as $enc) {
  50271. switch ($enc) {
  50272. case 'ASCII':
  50273. if (!preg_match('/[\x80-\xFF]/', $str)) {
  50274. return $enc;
  50275. }
  50276. break;
  50277. case 'UTF8':
  50278. case 'UTF-8':
  50279. if (preg_match('//u', $str)) {
  50280. return 'UTF-8';
  50281. }
  50282. break;
  50283. default:
  50284. if (0 === strncmp($enc, 'ISO-8859-', 9)) {
  50285. return $enc;
  50286. }
  50287. }
  50288. }
  50289. return false;
  50290. }
  50291. public static function mb_detect_order($encodingList = null)
  50292. {
  50293. if (null === $encodingList) {
  50294. return self::$encodingList;
  50295. }
  50296. if (!\is_array($encodingList)) {
  50297. $encodingList = array_map('trim', explode(',', $encodingList));
  50298. }
  50299. $encodingList = array_map('strtoupper', $encodingList);
  50300. foreach ($encodingList as $enc) {
  50301. switch ($enc) {
  50302. default:
  50303. if (strncmp($enc, 'ISO-8859-', 9)) {
  50304. return false;
  50305. }
  50306. case 'ASCII':
  50307. case 'UTF8':
  50308. case 'UTF-8':
  50309. }
  50310. }
  50311. self::$encodingList = $encodingList;
  50312. return true;
  50313. }
  50314. public static function mb_strlen($s, $encoding = null)
  50315. {
  50316. $encoding = self::getEncoding($encoding);
  50317. if ('CP850' === $encoding || 'ASCII' === $encoding) {
  50318. return \strlen($s);
  50319. }
  50320. return @iconv_strlen($s, $encoding);
  50321. }
  50322. public static function mb_strpos($haystack, $needle, $offset = 0, $encoding = null)
  50323. {
  50324. $encoding = self::getEncoding($encoding);
  50325. if ('CP850' === $encoding || 'ASCII' === $encoding) {
  50326. return strpos($haystack, $needle, $offset);
  50327. }
  50328. $needle = (string) $needle;
  50329. if ('' === $needle) {
  50330. trigger_error(__METHOD__.': Empty delimiter', E_USER_WARNING);
  50331. return false;
  50332. }
  50333. return iconv_strpos($haystack, $needle, $offset, $encoding);
  50334. }
  50335. public static function mb_strrpos($haystack, $needle, $offset = 0, $encoding = null)
  50336. {
  50337. $encoding = self::getEncoding($encoding);
  50338. if ('CP850' === $encoding || 'ASCII' === $encoding) {
  50339. return strrpos($haystack, $needle, $offset);
  50340. }
  50341. if ($offset != (int) $offset) {
  50342. $offset = 0;
  50343. } elseif ($offset = (int) $offset) {
  50344. if ($offset < 0) {
  50345. if (0 > $offset += self::mb_strlen($needle)) {
  50346. $haystack = self::mb_substr($haystack, 0, $offset, $encoding);
  50347. }
  50348. $offset = 0;
  50349. } else {
  50350. $haystack = self::mb_substr($haystack, $offset, 2147483647, $encoding);
  50351. }
  50352. }
  50353. $pos = iconv_strrpos($haystack, $needle, $encoding);
  50354. return false !== $pos ? $offset + $pos : false;
  50355. }
  50356. public static function mb_str_split($string, $split_length = 1, $encoding = null)
  50357. {
  50358. if (null !== $string && !\is_scalar($string) && !(\is_object($string) && \method_exists($string, '__toString'))) {
  50359. trigger_error('mb_str_split() expects parameter 1 to be string, '.\gettype($string).' given', E_USER_WARNING);
  50360. return null;
  50361. }
  50362. if (1 > $split_length = (int) $split_length) {
  50363. trigger_error('The length of each segment must be greater than zero', E_USER_WARNING);
  50364. return false;
  50365. }
  50366. if (null === $encoding) {
  50367. $encoding = mb_internal_encoding();
  50368. }
  50369. if ('UTF-8' === $encoding = self::getEncoding($encoding)) {
  50370. $rx = '/(';
  50371. while (65535 < $split_length) {
  50372. $rx .= '.{65535}';
  50373. $split_length -= 65535;
  50374. }
  50375. $rx .= '.{'.$split_length.'})/us';
  50376. return preg_split($rx, $string, null, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
  50377. }
  50378. $result = array();
  50379. $length = mb_strlen($string, $encoding);
  50380. for ($i = 0; $i < $length; $i += $split_length) {
  50381. $result[] = mb_substr($string, $i, $split_length, $encoding);
  50382. }
  50383. return $result;
  50384. }
  50385. public static function mb_strtolower($s, $encoding = null)
  50386. {
  50387. return self::mb_convert_case($s, MB_CASE_LOWER, $encoding);
  50388. }
  50389. public static function mb_strtoupper($s, $encoding = null)
  50390. {
  50391. return self::mb_convert_case($s, MB_CASE_UPPER, $encoding);
  50392. }
  50393. public static function mb_substitute_character($c = null)
  50394. {
  50395. if (0 === strcasecmp($c, 'none')) {
  50396. return true;
  50397. }
  50398. return null !== $c ? false : 'none';
  50399. }
  50400. public static function mb_substr($s, $start, $length = null, $encoding = null)
  50401. {
  50402. $encoding = self::getEncoding($encoding);
  50403. if ('CP850' === $encoding || 'ASCII' === $encoding) {
  50404. return (string) substr($s, $start, null === $length ? 2147483647 : $length);
  50405. }
  50406. if ($start < 0) {
  50407. $start = iconv_strlen($s, $encoding) + $start;
  50408. if ($start < 0) {
  50409. $start = 0;
  50410. }
  50411. }
  50412. if (null === $length) {
  50413. $length = 2147483647;
  50414. } elseif ($length < 0) {
  50415. $length = iconv_strlen($s, $encoding) + $length - $start;
  50416. if ($length < 0) {
  50417. return '';
  50418. }
  50419. }
  50420. return (string) iconv_substr($s, $start, $length, $encoding);
  50421. }
  50422. public static function mb_stripos($haystack, $needle, $offset = 0, $encoding = null)
  50423. {
  50424. $haystack = self::mb_convert_case($haystack, self::MB_CASE_FOLD, $encoding);
  50425. $needle = self::mb_convert_case($needle, self::MB_CASE_FOLD, $encoding);
  50426. return self::mb_strpos($haystack, $needle, $offset, $encoding);
  50427. }
  50428. public static function mb_stristr($haystack, $needle, $part = false, $encoding = null)
  50429. {
  50430. $pos = self::mb_stripos($haystack, $needle, 0, $encoding);
  50431. return self::getSubpart($pos, $part, $haystack, $encoding);
  50432. }
  50433. public static function mb_strrchr($haystack, $needle, $part = false, $encoding = null)
  50434. {
  50435. $encoding = self::getEncoding($encoding);
  50436. if ('CP850' === $encoding || 'ASCII' === $encoding) {
  50437. return strrchr($haystack, $needle, $part);
  50438. }
  50439. $needle = self::mb_substr($needle, 0, 1, $encoding);
  50440. $pos = iconv_strrpos($haystack, $needle, $encoding);
  50441. return self::getSubpart($pos, $part, $haystack, $encoding);
  50442. }
  50443. public static function mb_strrichr($haystack, $needle, $part = false, $encoding = null)
  50444. {
  50445. $needle = self::mb_substr($needle, 0, 1, $encoding);
  50446. $pos = self::mb_strripos($haystack, $needle, $encoding);
  50447. return self::getSubpart($pos, $part, $haystack, $encoding);
  50448. }
  50449. public static function mb_strripos($haystack, $needle, $offset = 0, $encoding = null)
  50450. {
  50451. $haystack = self::mb_convert_case($haystack, self::MB_CASE_FOLD, $encoding);
  50452. $needle = self::mb_convert_case($needle, self::MB_CASE_FOLD, $encoding);
  50453. return self::mb_strrpos($haystack, $needle, $offset, $encoding);
  50454. }
  50455. public static function mb_strstr($haystack, $needle, $part = false, $encoding = null)
  50456. {
  50457. $pos = strpos($haystack, $needle);
  50458. if (false === $pos) {
  50459. return false;
  50460. }
  50461. if ($part) {
  50462. return substr($haystack, 0, $pos);
  50463. }
  50464. return substr($haystack, $pos);
  50465. }
  50466. public static function mb_get_info($type = 'all')
  50467. {
  50468. $info = array(
  50469. 'internal_encoding' => self::$internalEncoding,
  50470. 'http_output' => 'pass',
  50471. 'http_output_conv_mimetypes' => '^(text/|application/xhtml\+xml)',
  50472. 'func_overload' => 0,
  50473. 'func_overload_list' => 'no overload',
  50474. 'mail_charset' => 'UTF-8',
  50475. 'mail_header_encoding' => 'BASE64',
  50476. 'mail_body_encoding' => 'BASE64',
  50477. 'illegal_chars' => 0,
  50478. 'encoding_translation' => 'Off',
  50479. 'language' => self::$language,
  50480. 'detect_order' => self::$encodingList,
  50481. 'substitute_character' => 'none',
  50482. 'strict_detection' => 'Off',
  50483. );
  50484. if ('all' === $type) {
  50485. return $info;
  50486. }
  50487. if (isset($info[$type])) {
  50488. return $info[$type];
  50489. }
  50490. return false;
  50491. }
  50492. public static function mb_http_input($type = '')
  50493. {
  50494. return false;
  50495. }
  50496. public static function mb_http_output($encoding = null)
  50497. {
  50498. return null !== $encoding ? 'pass' === $encoding : 'pass';
  50499. }
  50500. public static function mb_strwidth($s, $encoding = null)
  50501. {
  50502. $encoding = self::getEncoding($encoding);
  50503. if ('UTF-8' !== $encoding) {
  50504. $s = iconv($encoding, 'UTF-8//IGNORE', $s);
  50505. }
  50506. $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);
  50507. return ($wide << 1) + iconv_strlen($s, 'UTF-8');
  50508. }
  50509. public static function mb_substr_count($haystack, $needle, $encoding = null)
  50510. {
  50511. return substr_count($haystack, $needle);
  50512. }
  50513. public static function mb_output_handler($contents, $status)
  50514. {
  50515. return $contents;
  50516. }
  50517. public static function mb_chr($code, $encoding = null)
  50518. {
  50519. if (0x80 > $code %= 0x200000) {
  50520. $s = \chr($code);
  50521. } elseif (0x800 > $code) {
  50522. $s = \chr(0xC0 | $code >> 6).\chr(0x80 | $code & 0x3F);
  50523. } elseif (0x10000 > $code) {
  50524. $s = \chr(0xE0 | $code >> 12).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F);
  50525. } else {
  50526. $s = \chr(0xF0 | $code >> 18).\chr(0x80 | $code >> 12 & 0x3F).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F);
  50527. }
  50528. if ('UTF-8' !== $encoding = self::getEncoding($encoding)) {
  50529. $s = mb_convert_encoding($s, $encoding, 'UTF-8');
  50530. }
  50531. return $s;
  50532. }
  50533. public static function mb_ord($s, $encoding = null)
  50534. {
  50535. if ('UTF-8' !== $encoding = self::getEncoding($encoding)) {
  50536. $s = mb_convert_encoding($s, 'UTF-8', $encoding);
  50537. }
  50538. if (1 === \strlen($s)) {
  50539. return \ord($s);
  50540. }
  50541. $code = ($s = unpack('C*', substr($s, 0, 4))) ? $s[1] : 0;
  50542. if (0xF0 <= $code) {
  50543. return (($code - 0xF0) << 18) + (($s[2] - 0x80) << 12) + (($s[3] - 0x80) << 6) + $s[4] - 0x80;
  50544. }
  50545. if (0xE0 <= $code) {
  50546. return (($code - 0xE0) << 12) + (($s[2] - 0x80) << 6) + $s[3] - 0x80;
  50547. }
  50548. if (0xC0 <= $code) {
  50549. return (($code - 0xC0) << 6) + $s[2] - 0x80;
  50550. }
  50551. return $code;
  50552. }
  50553. private static function getSubpart($pos, $part, $haystack, $encoding)
  50554. {
  50555. if (false === $pos) {
  50556. return false;
  50557. }
  50558. if ($part) {
  50559. return self::mb_substr($haystack, 0, $pos, $encoding);
  50560. }
  50561. return self::mb_substr($haystack, $pos, null, $encoding);
  50562. }
  50563. private static function html_encoding_callback(array $m)
  50564. {
  50565. $i = 1;
  50566. $entities = '';
  50567. $m = unpack('C*', htmlentities($m[0], ENT_COMPAT, 'UTF-8'));
  50568. while (isset($m[$i])) {
  50569. if (0x80 > $m[$i]) {
  50570. $entities .= \chr($m[$i++]);
  50571. continue;
  50572. }
  50573. if (0xF0 <= $m[$i]) {
  50574. $c = (($m[$i++] - 0xF0) << 18) + (($m[$i++] - 0x80) << 12) + (($m[$i++] - 0x80) << 6) + $m[$i++] - 0x80;
  50575. } elseif (0xE0 <= $m[$i]) {
  50576. $c = (($m[$i++] - 0xE0) << 12) + (($m[$i++] - 0x80) << 6) + $m[$i++] - 0x80;
  50577. } else {
  50578. $c = (($m[$i++] - 0xC0) << 6) + $m[$i++] - 0x80;
  50579. }
  50580. $entities .= '&#'.$c.';';
  50581. }
  50582. return $entities;
  50583. }
  50584. private static function title_case(array $s)
  50585. {
  50586. return self::mb_convert_case($s[1], MB_CASE_UPPER, 'UTF-8').self::mb_convert_case($s[2], MB_CASE_LOWER, 'UTF-8');
  50587. }
  50588. private static function getData($file)
  50589. {
  50590. if (file_exists($file = __DIR__.'/Resources/unidata/'.$file.'.php')) {
  50591. return require $file;
  50592. }
  50593. return false;
  50594. }
  50595. private static function getEncoding($encoding)
  50596. {
  50597. if (null === $encoding) {
  50598. return self::$internalEncoding;
  50599. }
  50600. if ('UTF-8' === $encoding) {
  50601. return 'UTF-8';
  50602. }
  50603. $encoding = strtoupper($encoding);
  50604. if ('8BIT' === $encoding || 'BINARY' === $encoding) {
  50605. return 'CP850';
  50606. }
  50607. if ('UTF8' === $encoding) {
  50608. return 'UTF-8';
  50609. }
  50610. return $encoding;
  50611. }
  50612. }
  50613. <?php
  50614. return array (
  50615. 'a' => 'A',
  50616. 'b' => 'B',
  50617. 'c' => 'C',
  50618. 'd' => 'D',
  50619. 'e' => 'E',
  50620. 'f' => 'F',
  50621. 'g' => 'G',
  50622. 'h' => 'H',
  50623. 'i' => 'I',
  50624. 'j' => 'J',
  50625. 'k' => 'K',
  50626. 'l' => 'L',
  50627. 'm' => 'M',
  50628. 'n' => 'N',
  50629. 'o' => 'O',
  50630. 'p' => 'P',
  50631. 'q' => 'Q',
  50632. 'r' => 'R',
  50633. 's' => 'S',
  50634. 't' => 'T',
  50635. 'u' => 'U',
  50636. 'v' => 'V',
  50637. 'w' => 'W',
  50638. 'x' => 'X',
  50639. 'y' => 'Y',
  50640. 'z' => 'Z',
  50641. 'µ' => 'Μ',
  50642. 'à' => 'À',
  50643. 'á' => '�',
  50644. 'â' => 'Â',
  50645. 'ã' => 'Ã',
  50646. 'ä' => 'Ä',
  50647. 'Ã¥' => 'Ã…',
  50648. 'æ' => 'Æ',
  50649. 'ç' => 'Ç',
  50650. 'è' => 'È',
  50651. 'é' => 'É',
  50652. 'ê' => 'Ê',
  50653. 'ë' => 'Ë',
  50654. 'ì' => 'Ì',
  50655. 'í' => '�',
  50656. 'î' => 'Î',
  50657. 'ï' => '�',
  50658. 'ð' => '�',
  50659. 'ñ' => 'Ñ',
  50660. 'ò' => 'Ò',
  50661. 'ó' => 'Ó',
  50662. 'ô' => 'Ô',
  50663. 'õ' => 'Õ',
  50664. 'ö' => 'Ö',
  50665. 'ø' => 'Ø',
  50666. 'ù' => 'Ù',
  50667. 'ú' => 'Ú',
  50668. 'û' => 'Û',
  50669. 'ü' => 'Ü',
  50670. 'ý' => '�',
  50671. 'þ' => 'Þ',
  50672. 'ÿ' => 'Ÿ',
  50673. '�' => 'Ā',
  50674. 'ă' => 'Ă',
  50675. 'Ä…' => 'Ä„',
  50676. 'ć' => 'Ć',
  50677. 'ĉ' => 'Ĉ',
  50678. 'Ä‹' => 'ÄŠ',
  50679. '�' => 'Č',
  50680. '�' => 'Ď',
  50681. 'đ' => '�',
  50682. 'Ä“' => 'Ä’',
  50683. 'Ä•' => 'Ä”',
  50684. 'Ä—' => 'Ä–',
  50685. 'ę' => 'Ę',
  50686. 'Ä›' => 'Äš',
  50687. '�' => 'Ĝ',
  50688. 'ÄŸ' => 'Äž',
  50689. 'Ä¡' => 'Ä ',
  50690. 'Ä£' => 'Ä¢',
  50691. 'ĥ' => 'Ĥ',
  50692. 'ħ' => 'Ħ',
  50693. 'ĩ' => 'Ĩ',
  50694. 'ī' => 'Ī',
  50695. 'ĭ' => 'Ĭ',
  50696. 'į' => 'Į',
  50697. 'ı' => 'I',
  50698. 'ij' => 'IJ',
  50699. 'ĵ' => 'Ĵ',
  50700. 'ķ' => 'Ķ',
  50701. 'ĺ' => 'Ĺ',
  50702. 'ļ' => 'Ļ',
  50703. 'ľ' => 'Ľ',
  50704. 'Å€' => 'Ä¿',
  50705. 'ł' => '�',
  50706. 'ń' => 'Ń',
  50707. 'ņ' => 'Ņ',
  50708. 'ň' => 'Ň',
  50709. 'Å‹' => 'ÅŠ',
  50710. '�' => 'Ō',
  50711. '�' => 'Ŏ',
  50712. 'ő' => '�',
  50713. 'Å“' => 'Å’',
  50714. 'Å•' => 'Å”',
  50715. 'Å—' => 'Å–',
  50716. 'ř' => 'Ř',
  50717. 'Å›' => 'Åš',
  50718. '�' => 'Ŝ',
  50719. 'ÅŸ' => 'Åž',
  50720. 'Å¡' => 'Å ',
  50721. 'Å£' => 'Å¢',
  50722. 'ť' => 'Ť',
  50723. 'ŧ' => 'Ŧ',
  50724. 'ũ' => 'Ũ',
  50725. 'ū' => 'Ū',
  50726. 'ŭ' => 'Ŭ',
  50727. 'ů' => 'Ů',
  50728. 'ű' => 'Ű',
  50729. 'ų' => 'Ų',
  50730. 'ŵ' => 'Ŵ',
  50731. 'ŷ' => 'Ŷ',
  50732. 'ź' => 'Ź',
  50733. 'ż' => 'Ż',
  50734. 'ž' => 'Ž',
  50735. 'Å¿' => 'S',
  50736. 'ƀ' => 'Ƀ',
  50737. 'ƃ' => 'Ƃ',
  50738. 'Æ…' => 'Æ„',
  50739. 'ƈ' => 'Ƈ',
  50740. 'ƌ' => 'Ƌ',
  50741. 'Æ’' => 'Æ‘',
  50742. 'ƕ' => 'Ƕ',
  50743. 'ƙ' => 'Ƙ',
  50744. 'ƚ' => 'Ƚ',
  50745. 'Æž' => 'È ',
  50746. 'Æ¡' => 'Æ ',
  50747. 'Æ£' => 'Æ¢',
  50748. 'ƥ' => 'Ƥ',
  50749. 'ƨ' => 'Ƨ',
  50750. 'ƭ' => 'Ƭ',
  50751. 'ư' => 'Ư',
  50752. 'ƴ' => 'Ƴ',
  50753. 'ƶ' => 'Ƶ',
  50754. 'ƹ' => 'Ƹ',
  50755. 'ƽ' => 'Ƽ',
  50756. 'Æ¿' => 'Ç·',
  50757. 'Ç…' => 'Ç„',
  50758. 'dž' => 'DŽ',
  50759. 'Lj' => 'LJ',
  50760. 'lj' => 'LJ',
  50761. 'Ç‹' => 'ÇŠ',
  50762. 'nj' => 'NJ',
  50763. 'ǎ' => '�',
  50764. '�' => '�',
  50765. 'Ç’' => 'Ç‘',
  50766. 'Ç”' => 'Ç“',
  50767. 'Ç–' => 'Ç•',
  50768. 'ǘ' => 'Ǘ',
  50769. 'Çš' => 'Ç™',
  50770. 'ǜ' => 'Ǜ',
  50771. '�' => 'Ǝ',
  50772. 'ÇŸ' => 'Çž',
  50773. 'Ç¡' => 'Ç ',
  50774. 'Ç£' => 'Ç¢',
  50775. 'ǥ' => 'Ǥ',
  50776. 'ǧ' => 'Ǧ',
  50777. 'ǩ' => 'Ǩ',
  50778. 'ǫ' => 'Ǫ',
  50779. 'ǭ' => 'Ǭ',
  50780. 'ǯ' => 'Ǯ',
  50781. 'Dz' => 'DZ',
  50782. 'dz' => 'DZ',
  50783. 'ǵ' => 'Ǵ',
  50784. 'ǹ' => 'Ǹ',
  50785. 'ǻ' => 'Ǻ',
  50786. 'ǽ' => 'Ǽ',
  50787. 'ǿ' => 'Ǿ',
  50788. '�' => 'Ȁ',
  50789. 'ȃ' => 'Ȃ',
  50790. 'È…' => 'È„',
  50791. 'ȇ' => 'Ȇ',
  50792. 'ȉ' => 'Ȉ',
  50793. 'È‹' => 'ÈŠ',
  50794. '�' => 'Ȍ',
  50795. '�' => 'Ȏ',
  50796. 'ȑ' => '�',
  50797. 'È“' => 'È’',
  50798. 'È•' => 'È”',
  50799. 'È—' => 'È–',
  50800. 'ș' => 'Ș',
  50801. 'È›' => 'Èš',
  50802. '�' => 'Ȝ',
  50803. 'ÈŸ' => 'Èž',
  50804. 'È£' => 'È¢',
  50805. 'ȥ' => 'Ȥ',
  50806. 'ȧ' => 'Ȧ',
  50807. 'ȩ' => 'Ȩ',
  50808. 'ȫ' => 'Ȫ',
  50809. 'ȭ' => 'Ȭ',
  50810. 'ȯ' => 'Ȯ',
  50811. 'ȱ' => 'Ȱ',
  50812. 'ȳ' => 'Ȳ',
  50813. 'ȼ' => 'Ȼ',
  50814. 'È¿' => 'â±¾',
  50815. 'ɀ' => 'Ɀ',
  50816. 'ɂ' => '�',
  50817. 'ɇ' => 'Ɇ',
  50818. 'ɉ' => 'Ɉ',
  50819. 'É‹' => 'ÉŠ',
  50820. '�' => 'Ɍ',
  50821. '�' => 'Ɏ',
  50822. '�' => 'Ɐ',
  50823. 'É‘' => 'â±­',
  50824. 'É’' => 'â±°',
  50825. 'ɓ' => '�',
  50826. 'ɔ' => 'Ɔ',
  50827. 'ɖ' => 'Ɖ',
  50828. 'É—' => 'ÆŠ',
  50829. 'ə' => '�',
  50830. 'ɛ' => '�',
  50831. 'ɜ' => 'Ɜ',
  50832. 'É ' => 'Æ“',
  50833. 'ɡ' => 'Ɡ',
  50834. 'É£' => 'Æ”',
  50835. 'ɥ' => '�',
  50836. 'ɦ' => 'Ɦ',
  50837. 'ɨ' => 'Ɨ',
  50838. 'É©' => 'Æ–',
  50839. 'ɪ' => 'Ɪ',
  50840. 'É«' => 'â±¢',
  50841. 'ɬ' => 'Ɬ',
  50842. 'ɯ' => 'Ɯ',
  50843. 'ɱ' => 'Ɱ',
  50844. 'ɲ' => '�',
  50845. 'ɵ' => 'Ɵ',
  50846. 'ɽ' => 'Ɽ',
  50847. 'ʀ' => 'Ʀ',
  50848. 'ʂ' => 'Ʂ',
  50849. 'ʃ' => 'Ʃ',
  50850. 'ʇ' => 'Ʇ',
  50851. 'ʈ' => 'Ʈ',
  50852. 'ʉ' => 'Ʉ',
  50853. 'ʊ' => 'Ʊ',
  50854. 'ʋ' => 'Ʋ',
  50855. 'ʌ' => 'Ʌ',
  50856. 'Ê’' => 'Æ·',
  50857. '�' => 'Ʝ',
  50858. 'Êž' => 'êž°',
  50859. 'ͅ' => 'Ι',
  50860. 'ͱ' => 'Ͱ',
  50861. 'ͳ' => 'Ͳ',
  50862. 'ͷ' => 'Ͷ',
  50863. 'ͻ' => 'Ͻ',
  50864. 'ͼ' => 'Ͼ',
  50865. 'ͽ' => 'Ͽ',
  50866. 'ά' => 'Ά',
  50867. 'έ' => 'Έ',
  50868. 'ή' => 'Ή',
  50869. 'ί' => 'Ί',
  50870. 'α' => 'Α',
  50871. 'β' => 'Β',
  50872. 'γ' => 'Γ',
  50873. 'δ' => 'Δ',
  50874. 'ε' => 'Ε',
  50875. 'ζ' => 'Ζ',
  50876. 'η' => 'Η',
  50877. 'θ' => 'Θ',
  50878. 'ι' => 'Ι',
  50879. 'κ' => 'Κ',
  50880. 'λ' => 'Λ',
  50881. 'μ' => 'Μ',
  50882. 'ν' => '�',
  50883. 'ξ' => 'Ξ',
  50884. 'ο' => 'Ο',
  50885. 'π' => 'Π',
  50886. '�' => 'Ρ',
  50887. 'ς' => 'Σ',
  50888. 'σ' => 'Σ',
  50889. 'τ' => 'Τ',
  50890. 'Ï…' => 'Î¥',
  50891. 'φ' => 'Φ',
  50892. 'χ' => 'Χ',
  50893. 'ψ' => 'Ψ',
  50894. 'ω' => 'Ω',
  50895. 'ϊ' => 'Ϊ',
  50896. 'ϋ' => 'Ϋ',
  50897. 'ό' => 'Ό',
  50898. '�' => 'Ύ',
  50899. 'ώ' => '�',
  50900. '�' => 'Β',
  50901. 'ϑ' => 'Θ',
  50902. 'ϕ' => 'Φ',
  50903. 'ϖ' => 'Π',
  50904. 'ϗ' => '�',
  50905. 'ϙ' => 'Ϙ',
  50906. 'Ï›' => 'Ïš',
  50907. '�' => 'Ϝ',
  50908. 'ÏŸ' => 'Ïž',
  50909. 'Ï¡' => 'Ï ',
  50910. 'Ï£' => 'Ï¢',
  50911. 'ϥ' => 'Ϥ',
  50912. 'ϧ' => 'Ϧ',
  50913. 'ϩ' => 'Ϩ',
  50914. 'ϫ' => 'Ϫ',
  50915. 'ϭ' => 'Ϭ',
  50916. 'ϯ' => 'Ϯ',
  50917. 'ϰ' => 'Κ',
  50918. 'ϱ' => 'Ρ',
  50919. 'ϲ' => 'Ϲ',
  50920. 'ϳ' => 'Ϳ',
  50921. 'ϵ' => 'Ε',
  50922. 'ϸ' => 'Ϸ',
  50923. 'ϻ' => 'Ϻ',
  50924. 'а' => '�',
  50925. 'б' => 'Б',
  50926. 'в' => 'В',
  50927. 'г' => 'Г',
  50928. 'д' => 'Д',
  50929. 'е' => 'Е',
  50930. 'ж' => 'Ж',
  50931. 'з' => 'З',
  50932. 'и' => 'И',
  50933. 'й' => 'Й',
  50934. 'к' => 'К',
  50935. 'л' => 'Л',
  50936. 'м' => 'М',
  50937. 'н' => '�',
  50938. 'о' => 'О',
  50939. 'п' => 'П',
  50940. 'р' => 'Р',
  50941. '�' => 'С',
  50942. 'т' => 'Т',
  50943. 'у' => 'У',
  50944. 'ф' => 'Ф',
  50945. 'Ñ…' => 'Ð¥',
  50946. 'ц' => 'Ц',
  50947. 'ч' => 'Ч',
  50948. 'ш' => 'Ш',
  50949. 'щ' => 'Щ',
  50950. 'ъ' => 'Ъ',
  50951. 'ы' => 'Ы',
  50952. 'ь' => 'Ь',
  50953. '�' => 'Э',
  50954. 'ю' => 'Ю',
  50955. '�' => 'Я',
  50956. '�' => 'Ѐ',
  50957. 'ё' => '�',
  50958. 'ђ' => 'Ђ',
  50959. 'ѓ' => 'Ѓ',
  50960. 'є' => 'Є',
  50961. 'Ñ•' => 'Ð…',
  50962. 'і' => 'І',
  50963. 'ї' => 'Ї',
  50964. 'ј' => 'Ј',
  50965. 'љ' => 'Љ',
  50966. 'њ' => 'Њ',
  50967. 'ћ' => 'Ћ',
  50968. 'ќ' => 'Ќ',
  50969. '�' => '�',
  50970. 'Ñž' => 'ÐŽ',
  50971. 'џ' => '�',
  50972. 'Ñ¡' => 'Ñ ',
  50973. 'Ñ£' => 'Ñ¢',
  50974. 'ѥ' => 'Ѥ',
  50975. 'ѧ' => 'Ѧ',
  50976. 'ѩ' => 'Ѩ',
  50977. 'ѫ' => 'Ѫ',
  50978. 'ѭ' => 'Ѭ',
  50979. 'ѯ' => 'Ѯ',
  50980. 'ѱ' => 'Ѱ',
  50981. 'ѳ' => 'Ѳ',
  50982. 'ѵ' => 'Ѵ',
  50983. 'ѷ' => 'Ѷ',
  50984. 'ѹ' => 'Ѹ',
  50985. 'ѻ' => 'Ѻ',
  50986. 'ѽ' => 'Ѽ',
  50987. 'ѿ' => 'Ѿ',
  50988. 'Ò�' => 'Ò€',
  50989. 'Ò‹' => 'ÒŠ',
  50990. '�' => 'Ҍ',
  50991. 'Ò�' => 'ÒŽ',
  50992. 'Ò‘' => 'Ò�',
  50993. 'Ò“' => 'Ò’',
  50994. 'Ò•' => 'Ò”',
  50995. 'Ò—' => 'Ò–',
  50996. 'Ò™' => 'Ò˜',
  50997. 'Ò›' => 'Òš',
  50998. '�' => 'Ҝ',
  50999. 'ÒŸ' => 'Òž',
  51000. 'Ò¡' => 'Ò ',
  51001. 'Ò£' => 'Ò¢',
  51002. 'Ò¥' => 'Ò¤',
  51003. 'Ò§' => 'Ò¦',
  51004. 'Ò©' => 'Ò¨',
  51005. 'Ò«' => 'Òª',
  51006. 'Ò­' => 'Ò¬',
  51007. 'Ò¯' => 'Ò®',
  51008. 'Ò±' => 'Ò°',
  51009. 'Ò³' => 'Ò²',
  51010. 'Òµ' => 'Ò´',
  51011. 'Ò·' => 'Ò¶',
  51012. 'Ò¹' => 'Ò¸',
  51013. 'Ò»' => 'Òº',
  51014. 'Ò½' => 'Ò¼',
  51015. 'Ò¿' => 'Ò¾',
  51016. 'Ó‚' => 'Ó�',
  51017. 'Ó„' => 'Óƒ',
  51018. 'Ó†' => 'Ó…',
  51019. 'Óˆ' => 'Ó‡',
  51020. 'ÓŠ' => 'Ó‰',
  51021. 'ӌ' => 'Ӌ',
  51022. 'ÓŽ' => 'Ó�',
  51023. 'Ó�' => 'Ó€',
  51024. 'Ó‘' => 'Ó�',
  51025. 'Ó“' => 'Ó’',
  51026. 'Ó•' => 'Ó”',
  51027. 'Ó—' => 'Ó–',
  51028. 'Ó™' => 'Ó˜',
  51029. 'Ó›' => 'Óš',
  51030. '�' => 'Ӝ',
  51031. 'ÓŸ' => 'Óž',
  51032. 'Ó¡' => 'Ó ',
  51033. 'Ó£' => 'Ó¢',
  51034. 'Ó¥' => 'Ó¤',
  51035. 'Ó§' => 'Ó¦',
  51036. 'Ó©' => 'Ó¨',
  51037. 'Ó«' => 'Óª',
  51038. 'Ó­' => 'Ó¬',
  51039. 'Ó¯' => 'Ó®',
  51040. 'Ó±' => 'Ó°',
  51041. 'Ó³' => 'Ó²',
  51042. 'Óµ' => 'Ó´',
  51043. 'Ó·' => 'Ó¶',
  51044. 'Ó¹' => 'Ó¸',
  51045. 'Ó»' => 'Óº',
  51046. 'Ó½' => 'Ó¼',
  51047. 'Ó¿' => 'Ó¾',
  51048. 'Ô�' => 'Ô€',
  51049. 'Ôƒ' => 'Ô‚',
  51050. 'Ô…' => 'Ô„',
  51051. 'Ô‡' => 'Ô†',
  51052. 'Ô‰' => 'Ôˆ',
  51053. 'Ô‹' => 'ÔŠ',
  51054. '�' => 'Ԍ',
  51055. 'Ô�' => 'ÔŽ',
  51056. 'Ô‘' => 'Ô�',
  51057. 'Ô“' => 'Ô’',
  51058. 'Ô•' => 'Ô”',
  51059. 'Ô—' => 'Ô–',
  51060. 'Ô™' => 'Ô˜',
  51061. 'Ô›' => 'Ôš',
  51062. '�' => 'Ԝ',
  51063. 'ÔŸ' => 'Ôž',
  51064. 'Ô¡' => 'Ô ',
  51065. 'Ô£' => 'Ô¢',
  51066. 'Ô¥' => 'Ô¤',
  51067. 'Ô§' => 'Ô¦',
  51068. 'Ô©' => 'Ô¨',
  51069. 'Ô«' => 'Ôª',
  51070. 'Ô­' => 'Ô¬',
  51071. 'Ô¯' => 'Ô®',
  51072. 'Õ¡' => 'Ô±',
  51073. 'Õ¢' => 'Ô²',
  51074. 'Õ£' => 'Ô³',
  51075. 'Õ¤' => 'Ô´',
  51076. 'Õ¥' => 'Ôµ',
  51077. 'Õ¦' => 'Ô¶',
  51078. 'Õ§' => 'Ô·',
  51079. 'Õ¨' => 'Ô¸',
  51080. 'Õ©' => 'Ô¹',
  51081. 'Õª' => 'Ôº',
  51082. 'Õ«' => 'Ô»',
  51083. 'Õ¬' => 'Ô¼',
  51084. 'Õ­' => 'Ô½',
  51085. 'Õ®' => 'Ô¾',
  51086. 'Õ¯' => 'Ô¿',
  51087. 'Õ°' => 'Õ€',
  51088. 'Õ±' => 'Õ�',
  51089. 'Õ²' => 'Õ‚',
  51090. 'Õ³' => 'Õƒ',
  51091. 'Õ´' => 'Õ„',
  51092. 'Õµ' => 'Õ…',
  51093. 'Õ¶' => 'Õ†',
  51094. 'Õ·' => 'Õ‡',
  51095. 'Õ¸' => 'Õˆ',
  51096. 'Õ¹' => 'Õ‰',
  51097. 'Õº' => 'ÕŠ',
  51098. 'Õ»' => 'Õ‹',
  51099. 'ռ' => 'Ռ',
  51100. 'Õ½' => 'Õ�',
  51101. 'Õ¾' => 'ÕŽ',
  51102. 'Õ¿' => 'Õ�',
  51103. 'Ö€' => 'Õ�',
  51104. 'Ö�' => 'Õ‘',
  51105. 'Ö‚' => 'Õ’',
  51106. 'Öƒ' => 'Õ“',
  51107. 'Ö„' => 'Õ”',
  51108. 'Ö…' => 'Õ•',
  51109. 'Ö†' => 'Õ–',
  51110. '�' => '�',
  51111. 'ბ' => 'Ბ',
  51112. 'გ' => 'Გ',
  51113. 'დ' => 'Დ',
  51114. 'ე' => 'Ე',
  51115. 'ვ' => 'Ვ',
  51116. 'ზ' => 'Ზ',
  51117. 'თ' => 'Თ',
  51118. 'ი' => 'Ი',
  51119. 'კ' => 'Კ',
  51120. 'ლ' => 'Ლ',
  51121. 'მ' => 'Მ',
  51122. 'ნ' => 'Ნ',
  51123. '�' => '�',
  51124. 'პ' => 'Პ',
  51125. 'ჟ' => 'Ჟ',
  51126. 'რ' => 'Რ',
  51127. 'ს' => 'Ს',
  51128. 'ტ' => 'Ტ',
  51129. 'უ' => 'Უ',
  51130. 'ფ' => 'Ფ',
  51131. 'ქ' => 'Ქ',
  51132. 'ღ' => 'Ღ',
  51133. 'ყ' => 'Ყ',
  51134. 'შ' => 'Შ',
  51135. 'ჩ' => 'Ჩ',
  51136. 'ც' => 'Ც',
  51137. 'ძ' => 'Ძ',
  51138. 'წ' => 'Წ',
  51139. 'ჭ' => 'Ჭ',
  51140. 'ხ' => 'Ხ',
  51141. 'ჯ' => 'Ჯ',
  51142. 'ჰ' => 'Ჰ',
  51143. 'ჱ' => 'Ჱ',
  51144. 'ჲ' => 'Ჲ',
  51145. 'ჳ' => 'Ჳ',
  51146. 'ჴ' => 'Ჴ',
  51147. 'ჵ' => 'Ჵ',
  51148. 'ჶ' => 'Ჶ',
  51149. 'ჷ' => 'Ჷ',
  51150. 'ჸ' => 'Ჸ',
  51151. 'ჹ' => 'Ჹ',
  51152. 'ჺ' => 'Ჺ',
  51153. 'ჽ' => 'Ჽ',
  51154. 'ჾ' => 'Ჾ',
  51155. 'ჿ' => 'Ჿ',
  51156. '�' => '�',
  51157. '�' => '�',
  51158. '�' => '�',
  51159. '�' => '�',
  51160. '�' => '�',
  51161. '�' => '�',
  51162. 'á²€' => 'Ð’',
  51163. '�' => 'Д',
  51164. 'ᲂ' => 'О',
  51165. 'ᲃ' => 'С',
  51166. 'ᲄ' => 'Т',
  51167. 'ᲅ' => 'Т',
  51168. 'ᲆ' => 'Ъ',
  51169. 'ᲇ' => 'Ѣ',
  51170. 'ᲈ' => 'Ꙋ',
  51171. 'ᵹ' => '�',
  51172. 'áµ½' => 'â±£',
  51173. 'ᶎ' => 'Ᶎ',
  51174. '�' => 'Ḁ',
  51175. 'ḃ' => 'Ḃ',
  51176. 'ḅ' => 'Ḅ',
  51177. 'ḇ' => 'Ḇ',
  51178. 'ḉ' => 'Ḉ',
  51179. 'ḋ' => 'Ḋ',
  51180. '�' => 'Ḍ',
  51181. '�' => 'Ḏ',
  51182. 'ḑ' => '�',
  51183. 'ḓ' => 'Ḓ',
  51184. 'ḕ' => 'Ḕ',
  51185. 'ḗ' => 'Ḗ',
  51186. 'ḙ' => 'Ḙ',
  51187. 'ḛ' => 'Ḛ',
  51188. '�' => 'Ḝ',
  51189. 'ḟ' => 'Ḟ',
  51190. 'ḡ' => 'Ḡ',
  51191. 'ḣ' => 'Ḣ',
  51192. 'ḥ' => 'Ḥ',
  51193. 'ḧ' => 'Ḧ',
  51194. 'ḩ' => 'Ḩ',
  51195. 'ḫ' => 'Ḫ',
  51196. 'ḭ' => 'Ḭ',
  51197. 'ḯ' => 'Ḯ',
  51198. 'ḱ' => 'Ḱ',
  51199. 'ḳ' => 'Ḳ',
  51200. 'ḵ' => 'Ḵ',
  51201. 'ḷ' => 'Ḷ',
  51202. 'ḹ' => 'Ḹ',
  51203. 'ḻ' => 'Ḻ',
  51204. 'ḽ' => 'Ḽ',
  51205. 'ḿ' => 'Ḿ',
  51206. '�' => 'Ṁ',
  51207. 'ṃ' => 'Ṃ',
  51208. 'ṅ' => 'Ṅ',
  51209. 'ṇ' => 'Ṇ',
  51210. 'ṉ' => 'Ṉ',
  51211. 'ṋ' => 'Ṋ',
  51212. '�' => 'Ṍ',
  51213. '�' => 'Ṏ',
  51214. 'ṑ' => '�',
  51215. 'ṓ' => 'Ṓ',
  51216. 'ṕ' => 'Ṕ',
  51217. 'á¹—' => 'á¹–',
  51218. 'ṙ' => 'Ṙ',
  51219. 'ṛ' => 'Ṛ',
  51220. '�' => 'Ṝ',
  51221. 'ṟ' => 'Ṟ',
  51222. 'ṡ' => 'Ṡ',
  51223. 'á¹£' => 'á¹¢',
  51224. 'ṥ' => 'Ṥ',
  51225. 'ṧ' => 'Ṧ',
  51226. 'ṩ' => 'Ṩ',
  51227. 'ṫ' => 'Ṫ',
  51228. 'ṭ' => 'Ṭ',
  51229. 'ṯ' => 'Ṯ',
  51230. 'á¹±' => 'á¹°',
  51231. 'á¹³' => 'á¹²',
  51232. 'á¹µ' => 'á¹´',
  51233. 'á¹·' => 'á¹¶',
  51234. 'ṹ' => 'Ṹ',
  51235. 'ṻ' => 'Ṻ',
  51236. 'á¹½' => 'á¹¼',
  51237. 'ṿ' => 'Ṿ',
  51238. '�' => 'Ẁ',
  51239. 'ẃ' => 'Ẃ',
  51240. 'ẅ' => 'Ẅ',
  51241. 'ẇ' => 'Ẇ',
  51242. 'ẉ' => 'Ẉ',
  51243. 'ẋ' => 'Ẋ',
  51244. '�' => 'Ẍ',
  51245. '�' => 'Ẏ',
  51246. 'ẑ' => '�',
  51247. 'ẓ' => 'Ẓ',
  51248. 'ẕ' => 'Ẕ',
  51249. 'ẛ' => 'Ṡ',
  51250. 'ạ' => 'Ạ',
  51251. 'ả' => 'Ả',
  51252. 'ấ' => 'Ấ',
  51253. 'ầ' => 'Ầ',
  51254. 'ẩ' => 'Ẩ',
  51255. 'ẫ' => 'Ẫ',
  51256. 'ậ' => 'Ậ',
  51257. 'ắ' => 'Ắ',
  51258. 'ằ' => 'Ằ',
  51259. 'ẳ' => 'Ẳ',
  51260. 'ẵ' => 'Ẵ',
  51261. 'ặ' => 'Ặ',
  51262. 'ẹ' => 'Ẹ',
  51263. 'ẻ' => 'Ẻ',
  51264. 'ẽ' => 'Ẽ',
  51265. 'ế' => 'Ế',
  51266. '�' => 'Ề',
  51267. 'ể' => 'Ể',
  51268. 'ễ' => 'Ễ',
  51269. 'ệ' => 'Ệ',
  51270. 'ỉ' => 'Ỉ',
  51271. 'ị' => 'Ị',
  51272. '�' => 'Ọ',
  51273. '�' => 'Ỏ',
  51274. 'ố' => '�',
  51275. 'ồ' => 'Ồ',
  51276. 'ổ' => 'Ổ',
  51277. 'á»—' => 'á»–',
  51278. 'ộ' => 'Ộ',
  51279. 'ớ' => 'Ớ',
  51280. '�' => 'Ờ',
  51281. 'ở' => 'Ở',
  51282. 'ỡ' => 'Ỡ',
  51283. 'ợ' => 'Ợ',
  51284. 'ụ' => 'Ụ',
  51285. 'ủ' => 'Ủ',
  51286. 'ứ' => 'Ứ',
  51287. 'ừ' => 'Ừ',
  51288. 'ử' => 'Ử',
  51289. 'ữ' => 'Ữ',
  51290. 'á»±' => 'á»°',
  51291. 'ỳ' => 'Ỳ',
  51292. 'ỵ' => 'Ỵ',
  51293. 'á»·' => 'á»¶',
  51294. 'ỹ' => 'Ỹ',
  51295. 'ỻ' => 'Ỻ',
  51296. 'ỽ' => 'Ỽ',
  51297. 'ỿ' => 'Ỿ',
  51298. 'ἀ' => 'Ἀ',
  51299. '�' => 'Ἁ',
  51300. 'ἂ' => 'Ἂ',
  51301. 'ἃ' => 'Ἃ',
  51302. 'ἄ' => 'Ἄ',
  51303. 'ἅ' => '�',
  51304. 'ἆ' => 'Ἆ',
  51305. 'ἇ' => '�',
  51306. '�' => 'Ἐ',
  51307. 'ἑ' => 'Ἑ',
  51308. 'ἒ' => 'Ἒ',
  51309. 'ἓ' => 'Ἓ',
  51310. 'ἔ' => 'Ἔ',
  51311. 'ἕ' => '�',
  51312. 'ἠ' => 'Ἠ',
  51313. 'ἡ' => 'Ἡ',
  51314. 'ἢ' => 'Ἢ',
  51315. 'ἣ' => 'Ἣ',
  51316. 'ἤ' => 'Ἤ',
  51317. 'á¼¥' => 'á¼­',
  51318. 'ἦ' => 'Ἦ',
  51319. 'ἧ' => 'Ἧ',
  51320. 'ἰ' => 'Ἰ',
  51321. 'á¼±' => 'á¼¹',
  51322. 'ἲ' => 'Ἲ',
  51323. 'á¼³' => 'á¼»',
  51324. 'á¼´' => 'á¼¼',
  51325. 'á¼µ' => 'á¼½',
  51326. 'á¼¶' => 'á¼¾',
  51327. 'ἷ' => 'Ἷ',
  51328. 'ὀ' => 'Ὀ',
  51329. '�' => 'Ὁ',
  51330. 'ὂ' => 'Ὂ',
  51331. 'ὃ' => 'Ὃ',
  51332. 'ὄ' => 'Ὄ',
  51333. 'ὅ' => '�',
  51334. 'ὑ' => 'Ὑ',
  51335. 'ὓ' => 'Ὓ',
  51336. 'ὕ' => '�',
  51337. 'ὗ' => 'Ὗ',
  51338. 'ὠ' => 'Ὠ',
  51339. 'ὡ' => 'Ὡ',
  51340. 'ὢ' => 'Ὢ',
  51341. 'ὣ' => 'Ὣ',
  51342. 'ὤ' => 'Ὤ',
  51343. 'á½¥' => 'á½­',
  51344. 'ὦ' => 'Ὦ',
  51345. 'ὧ' => 'Ὧ',
  51346. 'ὰ' => 'Ὰ',
  51347. 'á½±' => 'á¾»',
  51348. 'ὲ' => 'Ὲ',
  51349. 'έ' => 'Έ',
  51350. 'ὴ' => 'Ὴ',
  51351. 'á½µ' => 'á¿‹',
  51352. 'ὶ' => 'Ὶ',
  51353. 'á½·' => 'á¿›',
  51354. 'ὸ' => 'Ὸ',
  51355. 'ό' => 'Ό',
  51356. 'ὺ' => 'Ὺ',
  51357. 'á½»' => 'á¿«',
  51358. 'ὼ' => 'Ὼ',
  51359. 'á½½' => 'á¿»',
  51360. 'ᾀ' => 'ᾈ',
  51361. '�' => 'ᾉ',
  51362. 'ᾂ' => 'ᾊ',
  51363. 'ᾃ' => 'ᾋ',
  51364. 'ᾄ' => 'ᾌ',
  51365. 'ᾅ' => '�',
  51366. 'ᾆ' => 'ᾎ',
  51367. 'ᾇ' => '�',
  51368. '�' => 'ᾘ',
  51369. 'ᾑ' => 'ᾙ',
  51370. 'ᾒ' => 'ᾚ',
  51371. 'ᾓ' => 'ᾛ',
  51372. 'ᾔ' => 'ᾜ',
  51373. 'ᾕ' => '�',
  51374. 'ᾖ' => 'ᾞ',
  51375. 'ᾗ' => 'ᾟ',
  51376. 'ᾠ' => 'ᾨ',
  51377. 'ᾡ' => 'ᾩ',
  51378. 'ᾢ' => 'ᾪ',
  51379. 'ᾣ' => 'ᾫ',
  51380. 'ᾤ' => 'ᾬ',
  51381. 'á¾¥' => 'á¾­',
  51382. 'ᾦ' => 'ᾮ',
  51383. 'ᾧ' => 'ᾯ',
  51384. 'ᾰ' => 'Ᾰ',
  51385. 'á¾±' => 'á¾¹',
  51386. 'á¾³' => 'á¾¼',
  51387. 'ι' => 'Ι',
  51388. 'ῃ' => 'ῌ',
  51389. '�' => 'Ῐ',
  51390. 'á¿‘' => 'á¿™',
  51391. 'ῠ' => 'Ῠ',
  51392. 'á¿¡' => 'á¿©',
  51393. 'ῥ' => 'Ῥ',
  51394. 'ῳ' => 'ῼ',
  51395. 'ⅎ' => 'Ⅎ',
  51396. 'â…°' => 'â… ',
  51397. 'â…±' => 'â…¡',
  51398. 'â…²' => 'â…¢',
  51399. 'â…³' => 'â…£',
  51400. 'â…´' => 'â…¤',
  51401. 'â…µ' => 'â…¥',
  51402. 'â…¶' => 'â…¦',
  51403. 'â…·' => 'â…§',
  51404. 'â…¸' => 'â…¨',
  51405. 'â…¹' => 'â…©',
  51406. 'â…º' => 'â…ª',
  51407. 'â…»' => 'â…«',
  51408. 'â…¼' => 'â…¬',
  51409. 'â…½' => 'â…­',
  51410. 'â…¾' => 'â…®',
  51411. 'â…¿' => 'â…¯',
  51412. 'ↄ' => 'Ↄ',
  51413. '�' => 'Ⓐ',
  51414. 'â“‘' => 'â’·',
  51415. 'â“’' => 'â’¸',
  51416. 'â““' => 'â’¹',
  51417. 'â“”' => 'â’º',
  51418. 'â“•' => 'â’»',
  51419. 'â“–' => 'â’¼',
  51420. 'â“—' => 'â’½',
  51421. 'ⓘ' => 'Ⓘ',
  51422. 'â“™' => 'â’¿',
  51423. 'ⓚ' => 'Ⓚ',
  51424. 'ⓛ' => '�',
  51425. 'ⓜ' => 'Ⓜ',
  51426. '�' => 'Ⓝ',
  51427. 'ⓞ' => 'Ⓞ',
  51428. 'ⓟ' => 'Ⓟ',
  51429. 'ⓠ' => 'Ⓠ',
  51430. 'ⓡ' => 'Ⓡ',
  51431. 'ⓢ' => 'Ⓢ',
  51432. 'ⓣ' => 'Ⓣ',
  51433. 'ⓤ' => 'Ⓤ',
  51434. 'â“¥' => 'â“‹',
  51435. 'ⓦ' => 'Ⓦ',
  51436. 'ⓧ' => '�',
  51437. 'ⓨ' => 'Ⓨ',
  51438. 'ⓩ' => '�',
  51439. 'â°°' => 'â°€',
  51440. 'â°±' => 'â°�',
  51441. 'â°²' => 'â°‚',
  51442. 'â°³' => 'â°ƒ',
  51443. 'â°´' => 'â°„',
  51444. 'â°µ' => 'â°…',
  51445. 'â°¶' => 'â°†',
  51446. 'â°·' => 'â°‡',
  51447. 'â°¸' => 'â°ˆ',
  51448. 'â°¹' => 'â°‰',
  51449. 'â°º' => 'â°Š',
  51450. 'â°»' => 'â°‹',
  51451. 'ⰼ' => 'Ⰼ',
  51452. 'â°½' => 'â°�',
  51453. 'â°¾' => 'â°Ž',
  51454. 'â°¿' => 'â°�',
  51455. 'â±€' => 'â°�',
  51456. '�' => 'Ⱁ',
  51457. 'ⱂ' => 'Ⱂ',
  51458. 'ⱃ' => 'Ⱃ',
  51459. 'ⱄ' => 'Ⱄ',
  51460. 'â±…' => 'â°•',
  51461. 'ⱆ' => 'Ⱆ',
  51462. 'ⱇ' => 'Ⱇ',
  51463. 'ⱈ' => 'Ⱈ',
  51464. 'ⱉ' => 'Ⱉ',
  51465. 'ⱊ' => 'Ⱊ',
  51466. 'ⱋ' => 'Ⱋ',
  51467. 'ⱌ' => 'Ⱌ',
  51468. '�' => '�',
  51469. 'ⱎ' => 'Ⱎ',
  51470. '�' => 'Ⱏ',
  51471. '�' => 'Ⱐ',
  51472. 'ⱑ' => 'Ⱑ',
  51473. 'â±’' => 'â°¢',
  51474. 'ⱓ' => 'Ⱓ',
  51475. 'â±”' => 'â°¤',
  51476. 'ⱕ' => 'Ⱕ',
  51477. 'â±–' => 'â°¦',
  51478. 'â±—' => 'â°§',
  51479. 'ⱘ' => 'Ⱘ',
  51480. 'â±™' => 'â°©',
  51481. 'ⱚ' => 'Ⱚ',
  51482. 'â±›' => 'â°«',
  51483. 'ⱜ' => 'Ⱜ',
  51484. '�' => 'Ⱝ',
  51485. 'ⱞ' => 'Ⱞ',
  51486. 'ⱡ' => 'Ⱡ',
  51487. 'ⱥ' => 'Ⱥ',
  51488. 'ⱦ' => 'Ⱦ',
  51489. 'ⱨ' => 'Ⱨ',
  51490. 'ⱪ' => 'Ⱪ',
  51491. 'ⱬ' => 'Ⱬ',
  51492. 'â±³' => 'â±²',
  51493. 'â±¶' => 'â±µ',
  51494. '�' => 'Ⲁ',
  51495. 'ⲃ' => 'Ⲃ',
  51496. 'ⲅ' => 'Ⲅ',
  51497. 'ⲇ' => 'Ⲇ',
  51498. 'ⲉ' => 'Ⲉ',
  51499. 'ⲋ' => 'Ⲋ',
  51500. '�' => 'Ⲍ',
  51501. '�' => 'Ⲏ',
  51502. 'ⲑ' => '�',
  51503. 'ⲓ' => 'Ⲓ',
  51504. 'ⲕ' => 'Ⲕ',
  51505. 'â²—' => 'â²–',
  51506. 'ⲙ' => 'Ⲙ',
  51507. 'ⲛ' => 'Ⲛ',
  51508. '�' => 'Ⲝ',
  51509. 'ⲟ' => 'Ⲟ',
  51510. 'ⲡ' => 'Ⲡ',
  51511. 'â²£' => 'â²¢',
  51512. 'ⲥ' => 'Ⲥ',
  51513. 'ⲧ' => 'Ⲧ',
  51514. 'ⲩ' => 'Ⲩ',
  51515. 'ⲫ' => 'Ⲫ',
  51516. 'ⲭ' => 'Ⲭ',
  51517. 'ⲯ' => 'Ⲯ',
  51518. 'â²±' => 'â²°',
  51519. 'â²³' => 'â²²',
  51520. 'â²µ' => 'â²´',
  51521. 'â²·' => 'â²¶',
  51522. 'ⲹ' => 'Ⲹ',
  51523. 'ⲻ' => 'Ⲻ',
  51524. 'â²½' => 'â²¼',
  51525. 'ⲿ' => 'Ⲿ',
  51526. '�' => 'Ⳁ',
  51527. 'ⳃ' => 'Ⳃ',
  51528. 'ⳅ' => 'Ⳅ',
  51529. 'ⳇ' => 'Ⳇ',
  51530. 'ⳉ' => 'Ⳉ',
  51531. 'ⳋ' => 'Ⳋ',
  51532. '�' => 'Ⳍ',
  51533. '�' => 'Ⳏ',
  51534. 'ⳑ' => '�',
  51535. 'ⳓ' => 'Ⳓ',
  51536. 'ⳕ' => 'Ⳕ',
  51537. 'â³—' => 'â³–',
  51538. 'ⳙ' => 'Ⳙ',
  51539. 'ⳛ' => 'Ⳛ',
  51540. '�' => 'Ⳝ',
  51541. 'ⳟ' => 'Ⳟ',
  51542. 'ⳡ' => 'Ⳡ',
  51543. 'â³£' => 'â³¢',
  51544. 'ⳬ' => 'Ⳬ',
  51545. 'â³®' => 'â³­',
  51546. 'â³³' => 'â³²',
  51547. 'â´€' => 'á‚ ',
  51548. 'â´�' => 'á‚¡',
  51549. 'â´‚' => 'á‚¢',
  51550. 'â´ƒ' => 'á‚£',
  51551. 'ⴄ' => 'Ⴄ',
  51552. 'â´…' => 'á‚¥',
  51553. 'ⴆ' => 'Ⴆ',
  51554. 'â´‡' => 'á‚§',
  51555. 'ⴈ' => 'Ⴈ',
  51556. 'â´‰' => 'á‚©',
  51557. 'ⴊ' => 'Ⴊ',
  51558. 'â´‹' => 'á‚«',
  51559. 'ⴌ' => 'Ⴌ',
  51560. 'â´�' => 'á‚­',
  51561. 'â´Ž' => 'á‚®',
  51562. '�' => 'Ⴏ',
  51563. 'â´�' => 'á‚°',
  51564. 'ⴑ' => 'Ⴑ',
  51565. 'ⴒ' => 'Ⴒ',
  51566. 'ⴓ' => 'Ⴓ',
  51567. 'â´”' => 'á‚´',
  51568. 'ⴕ' => 'Ⴕ',
  51569. 'â´–' => 'á‚¶',
  51570. 'â´—' => 'á‚·',
  51571. 'ⴘ' => 'Ⴘ',
  51572. 'ⴙ' => 'Ⴙ',
  51573. 'ⴚ' => 'Ⴚ',
  51574. 'â´›' => 'á‚»',
  51575. 'ⴜ' => 'Ⴜ',
  51576. '�' => 'Ⴝ',
  51577. 'ⴞ' => 'Ⴞ',
  51578. 'â´Ÿ' => 'á‚¿',
  51579. 'ⴠ' => 'Ⴠ',
  51580. 'ⴡ' => '�',
  51581. 'ⴢ' => 'Ⴢ',
  51582. 'ⴣ' => 'Ⴣ',
  51583. 'ⴤ' => 'Ⴤ',
  51584. 'ⴥ' => 'Ⴥ',
  51585. 'ⴧ' => 'Ⴧ',
  51586. 'ⴭ' => '�',
  51587. '�' => 'Ꙁ',
  51588. 'ꙃ' => 'Ꙃ',
  51589. 'ꙅ' => 'Ꙅ',
  51590. 'ꙇ' => 'Ꙇ',
  51591. 'ꙉ' => 'Ꙉ',
  51592. 'ꙋ' => 'Ꙋ',
  51593. '�' => 'Ꙍ',
  51594. '�' => 'Ꙏ',
  51595. 'ꙑ' => '�',
  51596. 'ꙓ' => 'Ꙓ',
  51597. 'ꙕ' => 'Ꙕ',
  51598. 'ê™—' => 'ê™–',
  51599. 'ꙙ' => 'Ꙙ',
  51600. 'ꙛ' => 'Ꙛ',
  51601. '�' => 'Ꙝ',
  51602. 'ꙟ' => 'Ꙟ',
  51603. 'ꙡ' => 'Ꙡ',
  51604. 'ꙣ' => 'Ꙣ',
  51605. 'ꙥ' => 'Ꙥ',
  51606. 'ꙧ' => 'Ꙧ',
  51607. 'ꙩ' => 'Ꙩ',
  51608. 'ꙫ' => 'Ꙫ',
  51609. 'ꙭ' => 'Ꙭ',
  51610. '�' => 'Ꚁ',
  51611. 'ꚃ' => 'Ꚃ',
  51612. 'êš…' => 'êš„',
  51613. 'ꚇ' => 'Ꚇ',
  51614. 'ꚉ' => 'Ꚉ',
  51615. 'ꚋ' => 'Ꚋ',
  51616. '�' => 'Ꚍ',
  51617. '�' => 'Ꚏ',
  51618. 'ꚑ' => '�',
  51619. 'êš“' => 'êš’',
  51620. 'êš•' => 'êš”',
  51621. 'êš—' => 'êš–',
  51622. 'ꚙ' => 'Ꚙ',
  51623. 'êš›' => 'êšš',
  51624. 'ꜣ' => 'Ꜣ',
  51625. 'ꜥ' => 'Ꜥ',
  51626. 'ꜧ' => 'Ꜧ',
  51627. 'ꜩ' => 'Ꜩ',
  51628. 'ꜫ' => 'Ꜫ',
  51629. 'ꜭ' => 'Ꜭ',
  51630. 'ꜯ' => 'Ꜯ',
  51631. 'ꜳ' => 'Ꜳ',
  51632. 'ꜵ' => 'Ꜵ',
  51633. 'ꜷ' => 'Ꜷ',
  51634. 'ꜹ' => 'Ꜹ',
  51635. 'ꜻ' => 'Ꜻ',
  51636. 'ꜽ' => 'Ꜽ',
  51637. 'ꜿ' => 'Ꜿ',
  51638. '�' => '�',
  51639. '�' => '�',
  51640. '�' => '�',
  51641. '�' => '�',
  51642. '�' => '�',
  51643. '�' => '�',
  51644. '�' => '�',
  51645. '�' => '�',
  51646. '�' => '�',
  51647. '�' => '�',
  51648. '�' => '�',
  51649. '�' => '�',
  51650. '�' => '�',
  51651. '�' => '�',
  51652. '�' => '�',
  51653. '�' => '�',
  51654. '�' => '�',
  51655. '�' => '�',
  51656. '�' => '�',
  51657. '�' => '�',
  51658. '�' => '�',
  51659. '�' => '�',
  51660. '�' => '�',
  51661. '�' => '�',
  51662. '�' => '�',
  51663. '�' => '�',
  51664. '�' => '�',
  51665. '�' => 'Ꞁ',
  51666. 'ꞃ' => 'Ꞃ',
  51667. 'êž…' => 'êž„',
  51668. 'ꞇ' => 'Ꞇ',
  51669. 'ꞌ' => 'Ꞌ',
  51670. 'ꞑ' => '�',
  51671. 'êž“' => 'êž’',
  51672. 'ꞔ' => 'Ꞔ',
  51673. 'êž—' => 'êž–',
  51674. 'ꞙ' => 'Ꞙ',
  51675. 'êž›' => 'êžš',
  51676. '�' => 'Ꞝ',
  51677. 'ꞟ' => 'Ꞟ',
  51678. 'êž¡' => 'êž ',
  51679. 'ꞣ' => 'Ꞣ',
  51680. 'ꞥ' => 'Ꞥ',
  51681. 'ꞧ' => 'Ꞧ',
  51682. 'ꞩ' => 'Ꞩ',
  51683. 'êžµ' => 'êž´',
  51684. 'êž·' => 'êž¶',
  51685. 'ꞹ' => 'Ꞹ',
  51686. 'ꞻ' => 'Ꞻ',
  51687. 'êž½' => 'êž¼',
  51688. 'êž¿' => 'êž¾',
  51689. 'ꟃ' => 'Ꟃ',
  51690. 'ꟈ' => 'Ꟈ',
  51691. 'ꟊ' => 'Ꟊ',
  51692. 'ꟶ' => 'Ꟶ',
  51693. 'ê­“' => 'êž³',
  51694. 'ꭰ' => 'Ꭰ',
  51695. 'ꭱ' => 'Ꭱ',
  51696. 'ꭲ' => 'Ꭲ',
  51697. 'ꭳ' => 'Ꭳ',
  51698. 'ꭴ' => 'Ꭴ',
  51699. 'ꭵ' => 'Ꭵ',
  51700. 'ꭶ' => 'Ꭶ',
  51701. 'ꭷ' => 'Ꭷ',
  51702. 'ꭸ' => 'Ꭸ',
  51703. 'ꭹ' => 'Ꭹ',
  51704. 'ꭺ' => 'Ꭺ',
  51705. 'ꭻ' => 'Ꭻ',
  51706. 'ꭼ' => 'Ꭼ',
  51707. 'ꭽ' => 'Ꭽ',
  51708. 'ꭾ' => 'Ꭾ',
  51709. 'ꭿ' => 'Ꭿ',
  51710. 'ꮀ' => 'Ꮀ',
  51711. '�' => 'Ꮁ',
  51712. 'ꮂ' => 'Ꮂ',
  51713. 'ꮃ' => 'Ꮃ',
  51714. 'ꮄ' => 'Ꮄ',
  51715. 'ꮅ' => 'Ꮅ',
  51716. 'ꮆ' => 'Ꮆ',
  51717. 'ꮇ' => 'Ꮇ',
  51718. 'ꮈ' => 'Ꮈ',
  51719. 'ꮉ' => 'Ꮉ',
  51720. 'ꮊ' => 'Ꮊ',
  51721. 'ꮋ' => 'Ꮋ',
  51722. 'ꮌ' => 'Ꮌ',
  51723. '�' => 'Ꮍ',
  51724. 'ꮎ' => 'Ꮎ',
  51725. '�' => 'Ꮏ',
  51726. '�' => '�',
  51727. 'ꮑ' => '�',
  51728. 'ꮒ' => '�',
  51729. 'ꮓ' => '�',
  51730. 'ꮔ' => '�',
  51731. 'ꮕ' => '�',
  51732. 'ꮖ' => '�',
  51733. 'ꮗ' => '�',
  51734. 'ꮘ' => '�',
  51735. 'ꮙ' => '�',
  51736. 'ꮚ' => '�',
  51737. 'ꮛ' => '�',
  51738. 'ꮜ' => '�',
  51739. '�' => '�',
  51740. 'ꮞ' => '�',
  51741. 'ꮟ' => '�',
  51742. 'ꮠ' => '�',
  51743. 'ꮡ' => '�',
  51744. 'ꮢ' => '�',
  51745. 'ꮣ' => '�',
  51746. 'ꮤ' => '�',
  51747. 'ꮥ' => '�',
  51748. 'ꮦ' => '�',
  51749. 'ꮧ' => '�',
  51750. 'ꮨ' => '�',
  51751. 'ꮩ' => '�',
  51752. 'ꮪ' => '�',
  51753. 'ꮫ' => '�',
  51754. 'ꮬ' => '�',
  51755. 'ꮭ' => '�',
  51756. 'ꮮ' => '�',
  51757. 'ꮯ' => '�',
  51758. 'ꮰ' => '�',
  51759. 'ꮱ' => '�',
  51760. 'ꮲ' => '�',
  51761. 'ꮳ' => '�',
  51762. 'ꮴ' => '�',
  51763. 'ꮵ' => '�',
  51764. 'ꮶ' => '�',
  51765. 'ꮷ' => '�',
  51766. 'ꮸ' => '�',
  51767. 'ꮹ' => '�',
  51768. 'ꮺ' => '�',
  51769. 'ꮻ' => '�',
  51770. 'ꮼ' => '�',
  51771. 'ꮽ' => '�',
  51772. 'ꮾ' => '�',
  51773. 'ꮿ' => '�',
  51774. '�' => 'A',
  51775. 'b' => 'B',
  51776. 'c' => 'C',
  51777. 'd' => 'D',
  51778. 'ï½…' => 'ï¼¥',
  51779. 'f' => 'F',
  51780. 'g' => 'G',
  51781. 'h' => 'H',
  51782. 'i' => 'I',
  51783. 'j' => 'J',
  51784. 'k' => 'K',
  51785. 'l' => 'L',
  51786. '�' => 'M',
  51787. 'n' => 'N',
  51788. '�' => 'O',
  51789. '�' => 'P',
  51790. 'q' => 'Q',
  51791. 'ï½’' => 'ï¼²',
  51792. 's' => 'S',
  51793. 'ï½”' => 'ï¼´',
  51794. 'u' => 'U',
  51795. 'ï½–' => 'ï¼¶',
  51796. 'ï½—' => 'ï¼·',
  51797. 'x' => 'X',
  51798. 'ï½™' => 'ï¼¹',
  51799. 'z' => 'Z',
  51800. '�' => '�',
  51801. '�' => '�',
  51802. '�' => '�',
  51803. '�' => '�',
  51804. '�' => '�',
  51805. '�' => '�',
  51806. '�' => '�',
  51807. '�' => '�',
  51808. '�' => '�',
  51809. '�' => '�',
  51810. '�' => '�',
  51811. '�' => '�',
  51812. '�' => '�',
  51813. '�' => '�',
  51814. '�' => '�',
  51815. '�' => '�',
  51816. '�' => '�',
  51817. '�' => '�',
  51818. '�' => '�',
  51819. '�' => '�',
  51820. '�' => '�',
  51821. '�' => '�',
  51822. '�' => '�',
  51823. '�' => '�',
  51824. '�' => '�',
  51825. '�' => '�',
  51826. '�' => '�',
  51827. '�' => '�',
  51828. '�' => '�',
  51829. '�' => '�',
  51830. '�' => '�',
  51831. '�' => '�',
  51832. '�' => '�',
  51833. '�' => '�',
  51834. '�' => '�',
  51835. '�' => '�',
  51836. '�' => '�',
  51837. '�' => '�',
  51838. '�' => '�',
  51839. '�' => '�',
  51840. '�' => '�',
  51841. '�' => '�',
  51842. '�' => '�',
  51843. '�' => '�',
  51844. '�' => '�',
  51845. '�' => '�',
  51846. '�' => '�',
  51847. '�' => '�',
  51848. '�' => '�',
  51849. '�' => '�',
  51850. '�' => '�',
  51851. '�' => '�',
  51852. '�' => '�',
  51853. '�' => '�',
  51854. '�' => '�',
  51855. '�' => '�',
  51856. '�' => '�',
  51857. '�' => '�',
  51858. '�' => '�',
  51859. '�' => '�',
  51860. '�' => '�',
  51861. '�' => '�',
  51862. '�' => '�',
  51863. '�' => '�',
  51864. '�' => '�',
  51865. '�' => '�',
  51866. '�' => '�',
  51867. '�' => '�',
  51868. '�' => '�',
  51869. '�' => '�',
  51870. '�' => '�',
  51871. '�' => '�',
  51872. '�' => '�',
  51873. '�' => '�',
  51874. '�' => '�',
  51875. '�' => '�',
  51876. '�' => '�',
  51877. '�' => '�',
  51878. '�' => '�',
  51879. '�' => '�',
  51880. '�' => '�',
  51881. '�' => '�',
  51882. '�' => '�',
  51883. '�' => '�',
  51884. '�' => '�',
  51885. '�' => '�',
  51886. '�' => '�',
  51887. '�' => '�',
  51888. '�' => '�',
  51889. '�' => '�',
  51890. '�' => '�',
  51891. '�' => '�',
  51892. '�' => '�',
  51893. '�' => '�',
  51894. '�' => '�',
  51895. '�' => '�',
  51896. '�' => '�',
  51897. '�' => '�',
  51898. '�' => '�',
  51899. '�' => '�',
  51900. '�' => '�',
  51901. '�' => '�',
  51902. '�' => '�',
  51903. '�' => '�',
  51904. '�' => '�',
  51905. '�' => '�',
  51906. '�' => '�',
  51907. '�' => '�',
  51908. '�' => '�',
  51909. '�' => '�',
  51910. '�' => '�',
  51911. '�' => '�',
  51912. '�' => '�',
  51913. '�' => '�',
  51914. '�' => '�',
  51915. '�' => '�',
  51916. '�' => '�',
  51917. '�' => '�',
  51918. '�' => '�',
  51919. '�' => '�',
  51920. '�' => '�',
  51921. '�' => '�',
  51922. '�' => '�',
  51923. '�' => '�',
  51924. '�' => '�',
  51925. '�' => '�',
  51926. '�' => '�',
  51927. 'ð‘£€' => 'ð‘¢ ',
  51928. '�' => '𑢡',
  51929. '𑣂' => '𑢢',
  51930. '𑣃' => '𑢣',
  51931. '𑣄' => '𑢤',
  51932. 'ð‘£…' => 'ð‘¢¥',
  51933. '𑣆' => '𑢦',
  51934. '𑣇' => '𑢧',
  51935. '𑣈' => '𑢨',
  51936. '𑣉' => '𑢩',
  51937. '𑣊' => '𑢪',
  51938. '𑣋' => '𑢫',
  51939. '𑣌' => '𑢬',
  51940. '�' => '𑢭',
  51941. '𑣎' => '𑢮',
  51942. '�' => '𑢯',
  51943. '�' => '𑢰',
  51944. '𑣑' => '𑢱',
  51945. 'ð‘£’' => 'ð‘¢²',
  51946. '𑣓' => '𑢳',
  51947. 'ð‘£”' => 'ð‘¢´',
  51948. '𑣕' => '𑢵',
  51949. 'ð‘£–' => 'ð‘¢¶',
  51950. 'ð‘£—' => 'ð‘¢·',
  51951. '𑣘' => '𑢸',
  51952. 'ð‘£™' => 'ð‘¢¹',
  51953. '𑣚' => '𑢺',
  51954. 'ð‘£›' => 'ð‘¢»',
  51955. '𑣜' => '𑢼',
  51956. '�' => '𑢽',
  51957. '𑣞' => '𑢾',
  51958. '𑣟' => '𑢿',
  51959. 'ð–¹ ' => 'ð–¹€',
  51960. '𖹡' => '�',
  51961. '𖹢' => '𖹂',
  51962. '𖹣' => '𖹃',
  51963. '𖹤' => '𖹄',
  51964. 'ð–¹¥' => 'ð–¹…',
  51965. '𖹦' => '𖹆',
  51966. '𖹧' => '𖹇',
  51967. '𖹨' => '𖹈',
  51968. '𖹩' => '𖹉',
  51969. '𖹪' => '𖹊',
  51970. '𖹫' => '𖹋',
  51971. '𖹬' => '𖹌',
  51972. '𖹭' => '�',
  51973. '𖹮' => '𖹎',
  51974. '𖹯' => '�',
  51975. '𖹰' => '�',
  51976. '𖹱' => '𖹑',
  51977. 'ð–¹²' => 'ð–¹’',
  51978. '𖹳' => '𖹓',
  51979. 'ð–¹´' => 'ð–¹”',
  51980. '𖹵' => '𖹕',
  51981. 'ð–¹¶' => 'ð–¹–',
  51982. 'ð–¹·' => 'ð–¹—',
  51983. '𖹸' => '𖹘',
  51984. 'ð–¹¹' => 'ð–¹™',
  51985. '𖹺' => '𖹚',
  51986. 'ð–¹»' => 'ð–¹›',
  51987. '𖹼' => '𖹜',
  51988. '𖹽' => '�',
  51989. '𖹾' => '𖹞',
  51990. '𖹿' => '𖹟',
  51991. '𞤢' => '𞤀',
  51992. '𞤣' => '�',
  51993. '𞤤' => '𞤂',
  51994. '𞤥' => '𞤃',
  51995. '𞤦' => '𞤄',
  51996. '𞤧' => '𞤅',
  51997. '𞤨' => '𞤆',
  51998. '𞤩' => '𞤇',
  51999. '𞤪' => '𞤈',
  52000. '𞤫' => '𞤉',
  52001. '𞤬' => '𞤊',
  52002. '𞤭' => '𞤋',
  52003. '𞤮' => '𞤌',
  52004. '𞤯' => '�',
  52005. '𞤰' => '𞤎',
  52006. '𞤱' => '�',
  52007. '𞤲' => '�',
  52008. '𞤳' => '𞤑',
  52009. '𞤴' => '𞤒',
  52010. '𞤵' => '𞤓',
  52011. '𞤶' => '𞤔',
  52012. '𞤷' => '𞤕',
  52013. '𞤸' => '𞤖',
  52014. '𞤹' => '𞤗',
  52015. '𞤺' => '𞤘',
  52016. '𞤻' => '𞤙',
  52017. '𞤼' => '𞤚',
  52018. '𞤽' => '𞤛',
  52019. '𞤾' => '𞤜',
  52020. '𞤿' => '�',
  52021. '𞥀' => '𞤞',
  52022. '�' => '𞤟',
  52023. '𞥂' => '𞤠',
  52024. '𞥃' => '𞤡',
  52025. );
  52026. <?php
  52027. 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';
  52028. <?php
  52029. return array (
  52030. 'A' => 'a',
  52031. 'B' => 'b',
  52032. 'C' => 'c',
  52033. 'D' => 'd',
  52034. 'E' => 'e',
  52035. 'F' => 'f',
  52036. 'G' => 'g',
  52037. 'H' => 'h',
  52038. 'I' => 'i',
  52039. 'J' => 'j',
  52040. 'K' => 'k',
  52041. 'L' => 'l',
  52042. 'M' => 'm',
  52043. 'N' => 'n',
  52044. 'O' => 'o',
  52045. 'P' => 'p',
  52046. 'Q' => 'q',
  52047. 'R' => 'r',
  52048. 'S' => 's',
  52049. 'T' => 't',
  52050. 'U' => 'u',
  52051. 'V' => 'v',
  52052. 'W' => 'w',
  52053. 'X' => 'x',
  52054. 'Y' => 'y',
  52055. 'Z' => 'z',
  52056. 'À' => 'à',
  52057. '�' => 'á',
  52058. 'Â' => 'â',
  52059. 'Ã' => 'ã',
  52060. 'Ä' => 'ä',
  52061. 'Ã…' => 'Ã¥',
  52062. 'Æ' => 'æ',
  52063. 'Ç' => 'ç',
  52064. 'È' => 'è',
  52065. 'É' => 'é',
  52066. 'Ê' => 'ê',
  52067. 'Ë' => 'ë',
  52068. 'Ì' => 'ì',
  52069. '�' => 'í',
  52070. 'Î' => 'î',
  52071. '�' => 'ï',
  52072. '�' => 'ð',
  52073. 'Ñ' => 'ñ',
  52074. 'Ò' => 'ò',
  52075. 'Ó' => 'ó',
  52076. 'Ô' => 'ô',
  52077. 'Õ' => 'õ',
  52078. 'Ö' => 'ö',
  52079. 'Ø' => 'ø',
  52080. 'Ù' => 'ù',
  52081. 'Ú' => 'ú',
  52082. 'Û' => 'û',
  52083. 'Ü' => 'ü',
  52084. '�' => 'ý',
  52085. 'Þ' => 'þ',
  52086. 'Ā' => '�',
  52087. 'Ă' => 'ă',
  52088. 'Ä„' => 'Ä…',
  52089. 'Ć' => 'ć',
  52090. 'Ĉ' => 'ĉ',
  52091. 'ÄŠ' => 'Ä‹',
  52092. 'Č' => '�',
  52093. 'Ď' => '�',
  52094. '�' => 'đ',
  52095. 'Ä’' => 'Ä“',
  52096. 'Ä”' => 'Ä•',
  52097. 'Ä–' => 'Ä—',
  52098. 'Ę' => 'ę',
  52099. 'Äš' => 'Ä›',
  52100. 'Ĝ' => '�',
  52101. 'Äž' => 'ÄŸ',
  52102. 'Ä ' => 'Ä¡',
  52103. 'Ä¢' => 'Ä£',
  52104. 'Ĥ' => 'ĥ',
  52105. 'Ħ' => 'ħ',
  52106. 'Ĩ' => 'ĩ',
  52107. 'Ī' => 'ī',
  52108. 'Ĭ' => 'ĭ',
  52109. 'Į' => 'į',
  52110. 'İ' => 'i',
  52111. 'IJ' => 'ij',
  52112. 'Ĵ' => 'ĵ',
  52113. 'Ķ' => 'ķ',
  52114. 'Ĺ' => 'ĺ',
  52115. 'Ļ' => 'ļ',
  52116. 'Ľ' => 'ľ',
  52117. 'Ä¿' => 'Å€',
  52118. '�' => 'ł',
  52119. 'Ń' => 'ń',
  52120. 'Ņ' => 'ņ',
  52121. 'Ň' => 'ň',
  52122. 'ÅŠ' => 'Å‹',
  52123. 'Ō' => '�',
  52124. 'Ŏ' => '�',
  52125. '�' => 'ő',
  52126. 'Å’' => 'Å“',
  52127. 'Å”' => 'Å•',
  52128. 'Å–' => 'Å—',
  52129. 'Ř' => 'ř',
  52130. 'Åš' => 'Å›',
  52131. 'Ŝ' => '�',
  52132. 'Åž' => 'ÅŸ',
  52133. 'Å ' => 'Å¡',
  52134. 'Å¢' => 'Å£',
  52135. 'Ť' => 'ť',
  52136. 'Ŧ' => 'ŧ',
  52137. 'Ũ' => 'ũ',
  52138. 'Ū' => 'ū',
  52139. 'Ŭ' => 'ŭ',
  52140. 'Ů' => 'ů',
  52141. 'Ű' => 'ű',
  52142. 'Ų' => 'ų',
  52143. 'Ŵ' => 'ŵ',
  52144. 'Ŷ' => 'ŷ',
  52145. 'Ÿ' => 'ÿ',
  52146. 'Ź' => 'ź',
  52147. 'Ż' => 'ż',
  52148. 'Ž' => 'ž',
  52149. '�' => 'ɓ',
  52150. 'Ƃ' => 'ƃ',
  52151. 'Æ„' => 'Æ…',
  52152. 'Ɔ' => 'ɔ',
  52153. 'Ƈ' => 'ƈ',
  52154. 'Ɖ' => 'ɖ',
  52155. 'ÆŠ' => 'É—',
  52156. 'Ƌ' => 'ƌ',
  52157. 'Ǝ' => '�',
  52158. '�' => 'ə',
  52159. '�' => 'ɛ',
  52160. 'Æ‘' => 'Æ’',
  52161. 'Æ“' => 'É ',
  52162. 'Æ”' => 'É£',
  52163. 'Æ–' => 'É©',
  52164. 'Ɨ' => 'ɨ',
  52165. 'Ƙ' => 'ƙ',
  52166. 'Ɯ' => 'ɯ',
  52167. '�' => 'ɲ',
  52168. 'Ɵ' => 'ɵ',
  52169. 'Æ ' => 'Æ¡',
  52170. 'Æ¢' => 'Æ£',
  52171. 'Ƥ' => 'ƥ',
  52172. 'Ʀ' => 'ʀ',
  52173. 'Ƨ' => 'ƨ',
  52174. 'Ʃ' => 'ʃ',
  52175. 'Ƭ' => 'ƭ',
  52176. 'Ʈ' => 'ʈ',
  52177. 'Ư' => 'ư',
  52178. 'Ʊ' => 'ʊ',
  52179. 'Ʋ' => 'ʋ',
  52180. 'Ƴ' => 'ƴ',
  52181. 'Ƶ' => 'ƶ',
  52182. 'Æ·' => 'Ê’',
  52183. 'Ƹ' => 'ƹ',
  52184. 'Ƽ' => 'ƽ',
  52185. 'DŽ' => 'dž',
  52186. 'Dž' => 'dž',
  52187. 'LJ' => 'lj',
  52188. 'Lj' => 'lj',
  52189. 'NJ' => 'nj',
  52190. 'Nj' => 'nj',
  52191. '�' => 'ǎ',
  52192. '�' => '�',
  52193. 'Ç‘' => 'Ç’',
  52194. 'Ç“' => 'Ç”',
  52195. 'Ç•' => 'Ç–',
  52196. 'Ǘ' => 'ǘ',
  52197. 'Ç™' => 'Çš',
  52198. 'Ǜ' => 'ǜ',
  52199. 'Çž' => 'ÇŸ',
  52200. 'Ç ' => 'Ç¡',
  52201. 'Ç¢' => 'Ç£',
  52202. 'Ǥ' => 'ǥ',
  52203. 'Ǧ' => 'ǧ',
  52204. 'Ǩ' => 'ǩ',
  52205. 'Ǫ' => 'ǫ',
  52206. 'Ǭ' => 'ǭ',
  52207. 'Ǯ' => 'ǯ',
  52208. 'DZ' => 'dz',
  52209. 'Dz' => 'dz',
  52210. 'Ǵ' => 'ǵ',
  52211. 'Ƕ' => 'ƕ',
  52212. 'Ç·' => 'Æ¿',
  52213. 'Ǹ' => 'ǹ',
  52214. 'Ǻ' => 'ǻ',
  52215. 'Ǽ' => 'ǽ',
  52216. 'Ǿ' => 'ǿ',
  52217. 'Ȁ' => '�',
  52218. 'Ȃ' => 'ȃ',
  52219. 'È„' => 'È…',
  52220. 'Ȇ' => 'ȇ',
  52221. 'Ȉ' => 'ȉ',
  52222. 'ÈŠ' => 'È‹',
  52223. 'Ȍ' => '�',
  52224. 'Ȏ' => '�',
  52225. '�' => 'ȑ',
  52226. 'È’' => 'È“',
  52227. 'È”' => 'È•',
  52228. 'È–' => 'È—',
  52229. 'Ș' => 'ș',
  52230. 'Èš' => 'È›',
  52231. 'Ȝ' => '�',
  52232. 'Èž' => 'ÈŸ',
  52233. 'È ' => 'Æž',
  52234. 'È¢' => 'È£',
  52235. 'Ȥ' => 'ȥ',
  52236. 'Ȧ' => 'ȧ',
  52237. 'Ȩ' => 'ȩ',
  52238. 'Ȫ' => 'ȫ',
  52239. 'Ȭ' => 'ȭ',
  52240. 'Ȯ' => 'ȯ',
  52241. 'Ȱ' => 'ȱ',
  52242. 'Ȳ' => 'ȳ',
  52243. 'Ⱥ' => 'ⱥ',
  52244. 'Ȼ' => 'ȼ',
  52245. 'Ƚ' => 'ƚ',
  52246. 'Ⱦ' => 'ⱦ',
  52247. '�' => 'ɂ',
  52248. 'Ƀ' => 'ƀ',
  52249. 'Ʉ' => 'ʉ',
  52250. 'Ʌ' => 'ʌ',
  52251. 'Ɇ' => 'ɇ',
  52252. 'Ɉ' => 'ɉ',
  52253. 'ÉŠ' => 'É‹',
  52254. 'Ɍ' => '�',
  52255. 'Ɏ' => '�',
  52256. 'Ͱ' => 'ͱ',
  52257. 'Ͳ' => 'ͳ',
  52258. 'Ͷ' => 'ͷ',
  52259. 'Ϳ' => 'ϳ',
  52260. 'Ά' => 'ά',
  52261. 'Έ' => 'έ',
  52262. 'Ή' => 'ή',
  52263. 'Ί' => 'ί',
  52264. 'Ό' => 'ό',
  52265. 'Ύ' => '�',
  52266. '�' => 'ώ',
  52267. 'Α' => 'α',
  52268. 'Β' => 'β',
  52269. 'Γ' => 'γ',
  52270. 'Δ' => 'δ',
  52271. 'Ε' => 'ε',
  52272. 'Ζ' => 'ζ',
  52273. 'Η' => 'η',
  52274. 'Θ' => 'θ',
  52275. 'Ι' => 'ι',
  52276. 'Κ' => 'κ',
  52277. 'Λ' => 'λ',
  52278. 'Μ' => 'μ',
  52279. '�' => 'ν',
  52280. 'Ξ' => 'ξ',
  52281. 'Ο' => 'ο',
  52282. 'Π' => 'π',
  52283. 'Ρ' => '�',
  52284. 'Σ' => 'σ',
  52285. 'Τ' => 'τ',
  52286. 'Î¥' => 'Ï…',
  52287. 'Φ' => 'φ',
  52288. 'Χ' => 'χ',
  52289. 'Ψ' => 'ψ',
  52290. 'Ω' => 'ω',
  52291. 'Ϊ' => 'ϊ',
  52292. 'Ϋ' => 'ϋ',
  52293. '�' => 'ϗ',
  52294. 'Ϙ' => 'ϙ',
  52295. 'Ïš' => 'Ï›',
  52296. 'Ϝ' => '�',
  52297. 'Ïž' => 'ÏŸ',
  52298. 'Ï ' => 'Ï¡',
  52299. 'Ï¢' => 'Ï£',
  52300. 'Ϥ' => 'ϥ',
  52301. 'Ϧ' => 'ϧ',
  52302. 'Ϩ' => 'ϩ',
  52303. 'Ϫ' => 'ϫ',
  52304. 'Ϭ' => 'ϭ',
  52305. 'Ϯ' => 'ϯ',
  52306. 'ϴ' => 'θ',
  52307. 'Ϸ' => 'ϸ',
  52308. 'Ϲ' => 'ϲ',
  52309. 'Ϻ' => 'ϻ',
  52310. 'Ͻ' => 'ͻ',
  52311. 'Ͼ' => 'ͼ',
  52312. 'Ͽ' => 'ͽ',
  52313. 'Ѐ' => '�',
  52314. '�' => 'ё',
  52315. 'Ђ' => 'ђ',
  52316. 'Ѓ' => 'ѓ',
  52317. 'Є' => 'є',
  52318. 'Ð…' => 'Ñ•',
  52319. 'І' => 'і',
  52320. 'Ї' => 'ї',
  52321. 'Ј' => 'ј',
  52322. 'Љ' => 'љ',
  52323. 'Њ' => 'њ',
  52324. 'Ћ' => 'ћ',
  52325. 'Ќ' => 'ќ',
  52326. '�' => '�',
  52327. 'ÐŽ' => 'Ñž',
  52328. '�' => 'џ',
  52329. '�' => 'а',
  52330. 'Б' => 'б',
  52331. 'В' => 'в',
  52332. 'Г' => 'г',
  52333. 'Д' => 'д',
  52334. 'Е' => 'е',
  52335. 'Ж' => 'ж',
  52336. 'З' => 'з',
  52337. 'И' => 'и',
  52338. 'Й' => 'й',
  52339. 'К' => 'к',
  52340. 'Л' => 'л',
  52341. 'М' => 'м',
  52342. '�' => 'н',
  52343. 'О' => 'о',
  52344. 'П' => 'п',
  52345. 'Р' => 'р',
  52346. 'С' => '�',
  52347. 'Т' => 'т',
  52348. 'У' => 'у',
  52349. 'Ф' => 'ф',
  52350. 'Ð¥' => 'Ñ…',
  52351. 'Ц' => 'ц',
  52352. 'Ч' => 'ч',
  52353. 'Ш' => 'ш',
  52354. 'Щ' => 'щ',
  52355. 'Ъ' => 'ъ',
  52356. 'Ы' => 'ы',
  52357. 'Ь' => 'ь',
  52358. 'Э' => '�',
  52359. 'Ю' => 'ю',
  52360. 'Я' => '�',
  52361. 'Ñ ' => 'Ñ¡',
  52362. 'Ñ¢' => 'Ñ£',
  52363. 'Ѥ' => 'ѥ',
  52364. 'Ѧ' => 'ѧ',
  52365. 'Ѩ' => 'ѩ',
  52366. 'Ѫ' => 'ѫ',
  52367. 'Ѭ' => 'ѭ',
  52368. 'Ѯ' => 'ѯ',
  52369. 'Ѱ' => 'ѱ',
  52370. 'Ѳ' => 'ѳ',
  52371. 'Ѵ' => 'ѵ',
  52372. 'Ѷ' => 'ѷ',
  52373. 'Ѹ' => 'ѹ',
  52374. 'Ѻ' => 'ѻ',
  52375. 'Ѽ' => 'ѽ',
  52376. 'Ѿ' => 'ѿ',
  52377. 'Ò€' => 'Ò�',
  52378. 'ÒŠ' => 'Ò‹',
  52379. 'Ҍ' => '�',
  52380. 'ÒŽ' => 'Ò�',
  52381. 'Ò�' => 'Ò‘',
  52382. 'Ò’' => 'Ò“',
  52383. 'Ò”' => 'Ò•',
  52384. 'Ò–' => 'Ò—',
  52385. 'Ò˜' => 'Ò™',
  52386. 'Òš' => 'Ò›',
  52387. 'Ҝ' => '�',
  52388. 'Òž' => 'ÒŸ',
  52389. 'Ò ' => 'Ò¡',
  52390. 'Ò¢' => 'Ò£',
  52391. 'Ò¤' => 'Ò¥',
  52392. 'Ò¦' => 'Ò§',
  52393. 'Ò¨' => 'Ò©',
  52394. 'Òª' => 'Ò«',
  52395. 'Ò¬' => 'Ò­',
  52396. 'Ò®' => 'Ò¯',
  52397. 'Ò°' => 'Ò±',
  52398. 'Ò²' => 'Ò³',
  52399. 'Ò´' => 'Òµ',
  52400. 'Ò¶' => 'Ò·',
  52401. 'Ò¸' => 'Ò¹',
  52402. 'Òº' => 'Ò»',
  52403. 'Ò¼' => 'Ò½',
  52404. 'Ò¾' => 'Ò¿',
  52405. 'Ó€' => 'Ó�',
  52406. 'Ó�' => 'Ó‚',
  52407. 'Óƒ' => 'Ó„',
  52408. 'Ó…' => 'Ó†',
  52409. 'Ó‡' => 'Óˆ',
  52410. 'Ó‰' => 'ÓŠ',
  52411. 'Ӌ' => 'ӌ',
  52412. 'Ó�' => 'ÓŽ',
  52413. 'Ó�' => 'Ó‘',
  52414. 'Ó’' => 'Ó“',
  52415. 'Ó”' => 'Ó•',
  52416. 'Ó–' => 'Ó—',
  52417. 'Ó˜' => 'Ó™',
  52418. 'Óš' => 'Ó›',
  52419. 'Ӝ' => '�',
  52420. 'Óž' => 'ÓŸ',
  52421. 'Ó ' => 'Ó¡',
  52422. 'Ó¢' => 'Ó£',
  52423. 'Ó¤' => 'Ó¥',
  52424. 'Ó¦' => 'Ó§',
  52425. 'Ó¨' => 'Ó©',
  52426. 'Óª' => 'Ó«',
  52427. 'Ó¬' => 'Ó­',
  52428. 'Ó®' => 'Ó¯',
  52429. 'Ó°' => 'Ó±',
  52430. 'Ó²' => 'Ó³',
  52431. 'Ó´' => 'Óµ',
  52432. 'Ó¶' => 'Ó·',
  52433. 'Ó¸' => 'Ó¹',
  52434. 'Óº' => 'Ó»',
  52435. 'Ó¼' => 'Ó½',
  52436. 'Ó¾' => 'Ó¿',
  52437. 'Ô€' => 'Ô�',
  52438. 'Ô‚' => 'Ôƒ',
  52439. 'Ô„' => 'Ô…',
  52440. 'Ô†' => 'Ô‡',
  52441. 'Ôˆ' => 'Ô‰',
  52442. 'ÔŠ' => 'Ô‹',
  52443. 'Ԍ' => '�',
  52444. 'ÔŽ' => 'Ô�',
  52445. 'Ô�' => 'Ô‘',
  52446. 'Ô’' => 'Ô“',
  52447. 'Ô”' => 'Ô•',
  52448. 'Ô–' => 'Ô—',
  52449. 'Ô˜' => 'Ô™',
  52450. 'Ôš' => 'Ô›',
  52451. 'Ԝ' => '�',
  52452. 'Ôž' => 'ÔŸ',
  52453. 'Ô ' => 'Ô¡',
  52454. 'Ô¢' => 'Ô£',
  52455. 'Ô¤' => 'Ô¥',
  52456. 'Ô¦' => 'Ô§',
  52457. 'Ô¨' => 'Ô©',
  52458. 'Ôª' => 'Ô«',
  52459. 'Ô¬' => 'Ô­',
  52460. 'Ô®' => 'Ô¯',
  52461. 'Ô±' => 'Õ¡',
  52462. 'Ô²' => 'Õ¢',
  52463. 'Ô³' => 'Õ£',
  52464. 'Ô´' => 'Õ¤',
  52465. 'Ôµ' => 'Õ¥',
  52466. 'Ô¶' => 'Õ¦',
  52467. 'Ô·' => 'Õ§',
  52468. 'Ô¸' => 'Õ¨',
  52469. 'Ô¹' => 'Õ©',
  52470. 'Ôº' => 'Õª',
  52471. 'Ô»' => 'Õ«',
  52472. 'Ô¼' => 'Õ¬',
  52473. 'Ô½' => 'Õ­',
  52474. 'Ô¾' => 'Õ®',
  52475. 'Ô¿' => 'Õ¯',
  52476. 'Õ€' => 'Õ°',
  52477. 'Õ�' => 'Õ±',
  52478. 'Õ‚' => 'Õ²',
  52479. 'Õƒ' => 'Õ³',
  52480. 'Õ„' => 'Õ´',
  52481. 'Õ…' => 'Õµ',
  52482. 'Õ†' => 'Õ¶',
  52483. 'Õ‡' => 'Õ·',
  52484. 'Õˆ' => 'Õ¸',
  52485. 'Õ‰' => 'Õ¹',
  52486. 'ÕŠ' => 'Õº',
  52487. 'Õ‹' => 'Õ»',
  52488. 'Ռ' => 'ռ',
  52489. 'Õ�' => 'Õ½',
  52490. 'ÕŽ' => 'Õ¾',
  52491. 'Õ�' => 'Õ¿',
  52492. 'Õ�' => 'Ö€',
  52493. 'Õ‘' => 'Ö�',
  52494. 'Õ’' => 'Ö‚',
  52495. 'Õ“' => 'Öƒ',
  52496. 'Õ”' => 'Ö„',
  52497. 'Õ•' => 'Ö…',
  52498. 'Õ–' => 'Ö†',
  52499. 'á‚ ' => 'â´€',
  52500. 'á‚¡' => 'â´�',
  52501. 'á‚¢' => 'â´‚',
  52502. 'á‚£' => 'â´ƒ',
  52503. 'Ⴄ' => 'ⴄ',
  52504. 'á‚¥' => 'â´…',
  52505. 'Ⴆ' => 'ⴆ',
  52506. 'á‚§' => 'â´‡',
  52507. 'Ⴈ' => 'ⴈ',
  52508. 'á‚©' => 'â´‰',
  52509. 'Ⴊ' => 'ⴊ',
  52510. 'á‚«' => 'â´‹',
  52511. 'Ⴌ' => 'ⴌ',
  52512. 'á‚­' => 'â´�',
  52513. 'á‚®' => 'â´Ž',
  52514. 'Ⴏ' => '�',
  52515. 'á‚°' => 'â´�',
  52516. 'Ⴑ' => 'ⴑ',
  52517. 'Ⴒ' => 'ⴒ',
  52518. 'Ⴓ' => 'ⴓ',
  52519. 'á‚´' => 'â´”',
  52520. 'Ⴕ' => 'ⴕ',
  52521. 'á‚¶' => 'â´–',
  52522. 'á‚·' => 'â´—',
  52523. 'Ⴘ' => 'ⴘ',
  52524. 'Ⴙ' => 'ⴙ',
  52525. 'Ⴚ' => 'ⴚ',
  52526. 'á‚»' => 'â´›',
  52527. 'Ⴜ' => 'ⴜ',
  52528. 'Ⴝ' => '�',
  52529. 'Ⴞ' => 'ⴞ',
  52530. 'á‚¿' => 'â´Ÿ',
  52531. 'Ⴠ' => 'ⴠ',
  52532. '�' => 'ⴡ',
  52533. 'Ⴢ' => 'ⴢ',
  52534. 'Ⴣ' => 'ⴣ',
  52535. 'Ⴤ' => 'ⴤ',
  52536. 'Ⴥ' => 'ⴥ',
  52537. 'Ⴧ' => 'ⴧ',
  52538. '�' => 'ⴭ',
  52539. 'Ꭰ' => 'ꭰ',
  52540. 'Ꭱ' => 'ꭱ',
  52541. 'Ꭲ' => 'ꭲ',
  52542. 'Ꭳ' => 'ꭳ',
  52543. 'Ꭴ' => 'ꭴ',
  52544. 'Ꭵ' => 'ꭵ',
  52545. 'Ꭶ' => 'ꭶ',
  52546. 'Ꭷ' => 'ꭷ',
  52547. 'Ꭸ' => 'ꭸ',
  52548. 'Ꭹ' => 'ꭹ',
  52549. 'Ꭺ' => 'ꭺ',
  52550. 'Ꭻ' => 'ꭻ',
  52551. 'Ꭼ' => 'ꭼ',
  52552. 'Ꭽ' => 'ꭽ',
  52553. 'Ꭾ' => 'ꭾ',
  52554. 'Ꭿ' => 'ꭿ',
  52555. 'Ꮀ' => 'ꮀ',
  52556. 'Ꮁ' => '�',
  52557. 'Ꮂ' => 'ꮂ',
  52558. 'Ꮃ' => 'ꮃ',
  52559. 'Ꮄ' => 'ꮄ',
  52560. 'Ꮅ' => 'ꮅ',
  52561. 'Ꮆ' => 'ꮆ',
  52562. 'Ꮇ' => 'ꮇ',
  52563. 'Ꮈ' => 'ꮈ',
  52564. 'Ꮉ' => 'ꮉ',
  52565. 'Ꮊ' => 'ꮊ',
  52566. 'Ꮋ' => 'ꮋ',
  52567. 'Ꮌ' => 'ꮌ',
  52568. 'Ꮍ' => '�',
  52569. 'Ꮎ' => 'ꮎ',
  52570. 'Ꮏ' => '�',
  52571. '�' => '�',
  52572. '�' => 'ꮑ',
  52573. '�' => 'ꮒ',
  52574. '�' => 'ꮓ',
  52575. '�' => 'ꮔ',
  52576. '�' => 'ꮕ',
  52577. '�' => 'ꮖ',
  52578. '�' => 'ꮗ',
  52579. '�' => 'ꮘ',
  52580. '�' => 'ꮙ',
  52581. '�' => 'ꮚ',
  52582. '�' => 'ꮛ',
  52583. '�' => 'ꮜ',
  52584. '�' => '�',
  52585. '�' => 'ꮞ',
  52586. '�' => 'ꮟ',
  52587. '�' => 'ꮠ',
  52588. '�' => 'ꮡ',
  52589. '�' => 'ꮢ',
  52590. '�' => 'ꮣ',
  52591. '�' => 'ꮤ',
  52592. '�' => 'ꮥ',
  52593. '�' => 'ꮦ',
  52594. '�' => 'ꮧ',
  52595. '�' => 'ꮨ',
  52596. '�' => 'ꮩ',
  52597. '�' => 'ꮪ',
  52598. '�' => 'ꮫ',
  52599. '�' => 'ꮬ',
  52600. '�' => 'ꮭ',
  52601. '�' => 'ꮮ',
  52602. '�' => 'ꮯ',
  52603. '�' => 'ꮰ',
  52604. '�' => 'ꮱ',
  52605. '�' => 'ꮲ',
  52606. '�' => 'ꮳ',
  52607. '�' => 'ꮴ',
  52608. '�' => 'ꮵ',
  52609. '�' => 'ꮶ',
  52610. '�' => 'ꮷ',
  52611. '�' => 'ꮸ',
  52612. '�' => 'ꮹ',
  52613. '�' => 'ꮺ',
  52614. '�' => 'ꮻ',
  52615. '�' => 'ꮼ',
  52616. '�' => 'ꮽ',
  52617. '�' => 'ꮾ',
  52618. '�' => 'ꮿ',
  52619. '�' => '�',
  52620. '�' => '�',
  52621. '�' => '�',
  52622. '�' => '�',
  52623. '�' => '�',
  52624. '�' => '�',
  52625. '�' => '�',
  52626. 'Ბ' => 'ბ',
  52627. 'Გ' => 'გ',
  52628. 'Დ' => 'დ',
  52629. 'Ე' => 'ე',
  52630. 'Ვ' => 'ვ',
  52631. 'Ზ' => 'ზ',
  52632. 'Თ' => 'თ',
  52633. 'Ი' => 'ი',
  52634. 'Კ' => 'კ',
  52635. 'Ლ' => 'ლ',
  52636. 'Მ' => 'მ',
  52637. 'Ნ' => 'ნ',
  52638. '�' => '�',
  52639. 'Პ' => 'პ',
  52640. 'Ჟ' => 'ჟ',
  52641. 'Რ' => 'რ',
  52642. 'Ს' => 'ს',
  52643. 'Ტ' => 'ტ',
  52644. 'Უ' => 'უ',
  52645. 'Ფ' => 'ფ',
  52646. 'Ქ' => 'ქ',
  52647. 'Ღ' => 'ღ',
  52648. 'Ყ' => 'ყ',
  52649. 'Შ' => 'შ',
  52650. 'Ჩ' => 'ჩ',
  52651. 'Ც' => 'ც',
  52652. 'Ძ' => 'ძ',
  52653. 'Წ' => 'წ',
  52654. 'Ჭ' => 'ჭ',
  52655. 'Ხ' => 'ხ',
  52656. 'Ჯ' => 'ჯ',
  52657. 'Ჰ' => 'ჰ',
  52658. 'Ჱ' => 'ჱ',
  52659. 'Ჲ' => 'ჲ',
  52660. 'Ჳ' => 'ჳ',
  52661. 'Ჴ' => 'ჴ',
  52662. 'Ჵ' => 'ჵ',
  52663. 'Ჶ' => 'ჶ',
  52664. 'Ჷ' => 'ჷ',
  52665. 'Ჸ' => 'ჸ',
  52666. 'Ჹ' => 'ჹ',
  52667. 'Ჺ' => 'ჺ',
  52668. 'Ჽ' => 'ჽ',
  52669. 'Ჾ' => 'ჾ',
  52670. 'Ჿ' => 'ჿ',
  52671. 'Ḁ' => '�',
  52672. 'Ḃ' => 'ḃ',
  52673. 'Ḅ' => 'ḅ',
  52674. 'Ḇ' => 'ḇ',
  52675. 'Ḉ' => 'ḉ',
  52676. 'Ḋ' => 'ḋ',
  52677. 'Ḍ' => '�',
  52678. 'Ḏ' => '�',
  52679. '�' => 'ḑ',
  52680. 'Ḓ' => 'ḓ',
  52681. 'Ḕ' => 'ḕ',
  52682. 'Ḗ' => 'ḗ',
  52683. 'Ḙ' => 'ḙ',
  52684. 'Ḛ' => 'ḛ',
  52685. 'Ḝ' => '�',
  52686. 'Ḟ' => 'ḟ',
  52687. 'Ḡ' => 'ḡ',
  52688. 'Ḣ' => 'ḣ',
  52689. 'Ḥ' => 'ḥ',
  52690. 'Ḧ' => 'ḧ',
  52691. 'Ḩ' => 'ḩ',
  52692. 'Ḫ' => 'ḫ',
  52693. 'Ḭ' => 'ḭ',
  52694. 'Ḯ' => 'ḯ',
  52695. 'Ḱ' => 'ḱ',
  52696. 'Ḳ' => 'ḳ',
  52697. 'Ḵ' => 'ḵ',
  52698. 'Ḷ' => 'ḷ',
  52699. 'Ḹ' => 'ḹ',
  52700. 'Ḻ' => 'ḻ',
  52701. 'Ḽ' => 'ḽ',
  52702. 'Ḿ' => 'ḿ',
  52703. 'Ṁ' => '�',
  52704. 'Ṃ' => 'ṃ',
  52705. 'Ṅ' => 'ṅ',
  52706. 'Ṇ' => 'ṇ',
  52707. 'Ṉ' => 'ṉ',
  52708. 'Ṋ' => 'ṋ',
  52709. 'Ṍ' => '�',
  52710. 'Ṏ' => '�',
  52711. '�' => 'ṑ',
  52712. 'Ṓ' => 'ṓ',
  52713. 'Ṕ' => 'ṕ',
  52714. 'á¹–' => 'á¹—',
  52715. 'Ṙ' => 'ṙ',
  52716. 'Ṛ' => 'ṛ',
  52717. 'Ṝ' => '�',
  52718. 'Ṟ' => 'ṟ',
  52719. 'Ṡ' => 'ṡ',
  52720. 'á¹¢' => 'á¹£',
  52721. 'Ṥ' => 'ṥ',
  52722. 'Ṧ' => 'ṧ',
  52723. 'Ṩ' => 'ṩ',
  52724. 'Ṫ' => 'ṫ',
  52725. 'Ṭ' => 'ṭ',
  52726. 'Ṯ' => 'ṯ',
  52727. 'á¹°' => 'á¹±',
  52728. 'á¹²' => 'á¹³',
  52729. 'á¹´' => 'á¹µ',
  52730. 'á¹¶' => 'á¹·',
  52731. 'Ṹ' => 'ṹ',
  52732. 'Ṻ' => 'ṻ',
  52733. 'á¹¼' => 'á¹½',
  52734. 'Ṿ' => 'ṿ',
  52735. 'Ẁ' => '�',
  52736. 'Ẃ' => 'ẃ',
  52737. 'Ẅ' => 'ẅ',
  52738. 'Ẇ' => 'ẇ',
  52739. 'Ẉ' => 'ẉ',
  52740. 'Ẋ' => 'ẋ',
  52741. 'Ẍ' => '�',
  52742. 'Ẏ' => '�',
  52743. '�' => 'ẑ',
  52744. 'Ẓ' => 'ẓ',
  52745. 'Ẕ' => 'ẕ',
  52746. 'ẞ' => 'ß',
  52747. 'Ạ' => 'ạ',
  52748. 'Ả' => 'ả',
  52749. 'Ấ' => 'ấ',
  52750. 'Ầ' => 'ầ',
  52751. 'Ẩ' => 'ẩ',
  52752. 'Ẫ' => 'ẫ',
  52753. 'Ậ' => 'ậ',
  52754. 'Ắ' => 'ắ',
  52755. 'Ằ' => 'ằ',
  52756. 'Ẳ' => 'ẳ',
  52757. 'Ẵ' => 'ẵ',
  52758. 'Ặ' => 'ặ',
  52759. 'Ẹ' => 'ẹ',
  52760. 'Ẻ' => 'ẻ',
  52761. 'Ẽ' => 'ẽ',
  52762. 'Ế' => 'ế',
  52763. 'Ề' => '�',
  52764. 'Ể' => 'ể',
  52765. 'Ễ' => 'ễ',
  52766. 'Ệ' => 'ệ',
  52767. 'Ỉ' => 'ỉ',
  52768. 'Ị' => 'ị',
  52769. 'Ọ' => '�',
  52770. 'Ỏ' => '�',
  52771. '�' => 'ố',
  52772. 'Ồ' => 'ồ',
  52773. 'Ổ' => 'ổ',
  52774. 'á»–' => 'á»—',
  52775. 'Ộ' => 'ộ',
  52776. 'Ớ' => 'ớ',
  52777. 'Ờ' => '�',
  52778. 'Ở' => 'ở',
  52779. 'Ỡ' => 'ỡ',
  52780. 'Ợ' => 'ợ',
  52781. 'Ụ' => 'ụ',
  52782. 'Ủ' => 'ủ',
  52783. 'Ứ' => 'ứ',
  52784. 'Ừ' => 'ừ',
  52785. 'Ử' => 'ử',
  52786. 'Ữ' => 'ữ',
  52787. 'á»°' => 'á»±',
  52788. 'Ỳ' => 'ỳ',
  52789. 'Ỵ' => 'ỵ',
  52790. 'á»¶' => 'á»·',
  52791. 'Ỹ' => 'ỹ',
  52792. 'Ỻ' => 'ỻ',
  52793. 'Ỽ' => 'ỽ',
  52794. 'Ỿ' => 'ỿ',
  52795. 'Ἀ' => 'ἀ',
  52796. 'Ἁ' => '�',
  52797. 'Ἂ' => 'ἂ',
  52798. 'Ἃ' => 'ἃ',
  52799. 'Ἄ' => 'ἄ',
  52800. '�' => 'ἅ',
  52801. 'Ἆ' => 'ἆ',
  52802. '�' => 'ἇ',
  52803. 'Ἐ' => '�',
  52804. 'Ἑ' => 'ἑ',
  52805. 'Ἒ' => 'ἒ',
  52806. 'Ἓ' => 'ἓ',
  52807. 'Ἔ' => 'ἔ',
  52808. '�' => 'ἕ',
  52809. 'Ἠ' => 'ἠ',
  52810. 'Ἡ' => 'ἡ',
  52811. 'Ἢ' => 'ἢ',
  52812. 'Ἣ' => 'ἣ',
  52813. 'Ἤ' => 'ἤ',
  52814. 'á¼­' => 'á¼¥',
  52815. 'Ἦ' => 'ἦ',
  52816. 'Ἧ' => 'ἧ',
  52817. 'Ἰ' => 'ἰ',
  52818. 'á¼¹' => 'á¼±',
  52819. 'Ἲ' => 'ἲ',
  52820. 'á¼»' => 'á¼³',
  52821. 'á¼¼' => 'á¼´',
  52822. 'á¼½' => 'á¼µ',
  52823. 'á¼¾' => 'á¼¶',
  52824. 'Ἷ' => 'ἷ',
  52825. 'Ὀ' => 'ὀ',
  52826. 'Ὁ' => '�',
  52827. 'Ὂ' => 'ὂ',
  52828. 'Ὃ' => 'ὃ',
  52829. 'Ὄ' => 'ὄ',
  52830. '�' => 'ὅ',
  52831. 'Ὑ' => 'ὑ',
  52832. 'Ὓ' => 'ὓ',
  52833. '�' => 'ὕ',
  52834. 'Ὗ' => 'ὗ',
  52835. 'Ὠ' => 'ὠ',
  52836. 'Ὡ' => 'ὡ',
  52837. 'Ὢ' => 'ὢ',
  52838. 'Ὣ' => 'ὣ',
  52839. 'Ὤ' => 'ὤ',
  52840. 'á½­' => 'á½¥',
  52841. 'Ὦ' => 'ὦ',
  52842. 'Ὧ' => 'ὧ',
  52843. 'ᾈ' => 'ᾀ',
  52844. 'ᾉ' => '�',
  52845. 'ᾊ' => 'ᾂ',
  52846. 'ᾋ' => 'ᾃ',
  52847. 'ᾌ' => 'ᾄ',
  52848. '�' => 'ᾅ',
  52849. 'ᾎ' => 'ᾆ',
  52850. '�' => 'ᾇ',
  52851. 'ᾘ' => '�',
  52852. 'ᾙ' => 'ᾑ',
  52853. 'ᾚ' => 'ᾒ',
  52854. 'ᾛ' => 'ᾓ',
  52855. 'ᾜ' => 'ᾔ',
  52856. '�' => 'ᾕ',
  52857. 'ᾞ' => 'ᾖ',
  52858. 'ᾟ' => 'ᾗ',
  52859. 'ᾨ' => 'ᾠ',
  52860. 'ᾩ' => 'ᾡ',
  52861. 'ᾪ' => 'ᾢ',
  52862. 'ᾫ' => 'ᾣ',
  52863. 'ᾬ' => 'ᾤ',
  52864. 'á¾­' => 'á¾¥',
  52865. 'ᾮ' => 'ᾦ',
  52866. 'ᾯ' => 'ᾧ',
  52867. 'Ᾰ' => 'ᾰ',
  52868. 'á¾¹' => 'á¾±',
  52869. 'Ὰ' => 'ὰ',
  52870. 'á¾»' => 'á½±',
  52871. 'á¾¼' => 'á¾³',
  52872. 'Ὲ' => 'ὲ',
  52873. 'Έ' => 'έ',
  52874. 'Ὴ' => 'ὴ',
  52875. 'á¿‹' => 'á½µ',
  52876. 'ῌ' => 'ῃ',
  52877. 'Ῐ' => '�',
  52878. 'á¿™' => 'á¿‘',
  52879. 'Ὶ' => 'ὶ',
  52880. 'á¿›' => 'á½·',
  52881. 'Ῠ' => 'ῠ',
  52882. 'á¿©' => 'á¿¡',
  52883. 'Ὺ' => 'ὺ',
  52884. 'á¿«' => 'á½»',
  52885. 'Ῥ' => 'ῥ',
  52886. 'Ὸ' => 'ὸ',
  52887. 'Ό' => 'ό',
  52888. 'Ὼ' => 'ὼ',
  52889. 'á¿»' => 'á½½',
  52890. 'ῼ' => 'ῳ',
  52891. 'Ω' => 'ω',
  52892. 'K' => 'k',
  52893. 'â„«' => 'Ã¥',
  52894. 'Ⅎ' => 'ⅎ',
  52895. 'â… ' => 'â…°',
  52896. 'â…¡' => 'â…±',
  52897. 'â…¢' => 'â…²',
  52898. 'â…£' => 'â…³',
  52899. 'â…¤' => 'â…´',
  52900. 'â…¥' => 'â…µ',
  52901. 'â…¦' => 'â…¶',
  52902. 'â…§' => 'â…·',
  52903. 'â…¨' => 'â…¸',
  52904. 'â…©' => 'â…¹',
  52905. 'â…ª' => 'â…º',
  52906. 'â…«' => 'â…»',
  52907. 'â…¬' => 'â…¼',
  52908. 'â…­' => 'â…½',
  52909. 'â…®' => 'â…¾',
  52910. 'â…¯' => 'â…¿',
  52911. 'Ↄ' => 'ↄ',
  52912. 'Ⓐ' => '�',
  52913. 'â’·' => 'â“‘',
  52914. 'â’¸' => 'â“’',
  52915. 'â’¹' => 'â““',
  52916. 'â’º' => 'â“”',
  52917. 'â’»' => 'â“•',
  52918. 'â’¼' => 'â“–',
  52919. 'â’½' => 'â“—',
  52920. 'Ⓘ' => 'ⓘ',
  52921. 'â’¿' => 'â“™',
  52922. 'Ⓚ' => 'ⓚ',
  52923. '�' => 'ⓛ',
  52924. 'Ⓜ' => 'ⓜ',
  52925. 'Ⓝ' => '�',
  52926. 'Ⓞ' => 'ⓞ',
  52927. 'Ⓟ' => 'ⓟ',
  52928. 'Ⓠ' => 'ⓠ',
  52929. 'Ⓡ' => 'ⓡ',
  52930. 'Ⓢ' => 'ⓢ',
  52931. 'Ⓣ' => 'ⓣ',
  52932. 'Ⓤ' => 'ⓤ',
  52933. 'â“‹' => 'â“¥',
  52934. 'Ⓦ' => 'ⓦ',
  52935. '�' => 'ⓧ',
  52936. 'Ⓨ' => 'ⓨ',
  52937. '�' => 'ⓩ',
  52938. 'â°€' => 'â°°',
  52939. 'â°�' => 'â°±',
  52940. 'â°‚' => 'â°²',
  52941. 'â°ƒ' => 'â°³',
  52942. 'â°„' => 'â°´',
  52943. 'â°…' => 'â°µ',
  52944. 'â°†' => 'â°¶',
  52945. 'â°‡' => 'â°·',
  52946. 'â°ˆ' => 'â°¸',
  52947. 'â°‰' => 'â°¹',
  52948. 'â°Š' => 'â°º',
  52949. 'â°‹' => 'â°»',
  52950. 'Ⰼ' => 'ⰼ',
  52951. 'â°�' => 'â°½',
  52952. 'â°Ž' => 'â°¾',
  52953. 'â°�' => 'â°¿',
  52954. 'â°�' => 'â±€',
  52955. 'Ⱁ' => '�',
  52956. 'Ⱂ' => 'ⱂ',
  52957. 'Ⱃ' => 'ⱃ',
  52958. 'Ⱄ' => 'ⱄ',
  52959. 'â°•' => 'â±…',
  52960. 'Ⱆ' => 'ⱆ',
  52961. 'Ⱇ' => 'ⱇ',
  52962. 'Ⱈ' => 'ⱈ',
  52963. 'Ⱉ' => 'ⱉ',
  52964. 'Ⱊ' => 'ⱊ',
  52965. 'Ⱋ' => 'ⱋ',
  52966. 'Ⱌ' => 'ⱌ',
  52967. '�' => '�',
  52968. 'Ⱎ' => 'ⱎ',
  52969. 'Ⱏ' => '�',
  52970. 'Ⱐ' => '�',
  52971. 'Ⱑ' => 'ⱑ',
  52972. 'â°¢' => 'â±’',
  52973. 'Ⱓ' => 'ⱓ',
  52974. 'â°¤' => 'â±”',
  52975. 'Ⱕ' => 'ⱕ',
  52976. 'â°¦' => 'â±–',
  52977. 'â°§' => 'â±—',
  52978. 'Ⱘ' => 'ⱘ',
  52979. 'â°©' => 'â±™',
  52980. 'Ⱚ' => 'ⱚ',
  52981. 'â°«' => 'â±›',
  52982. 'Ⱜ' => 'ⱜ',
  52983. 'Ⱝ' => '�',
  52984. 'Ⱞ' => 'ⱞ',
  52985. 'Ⱡ' => 'ⱡ',
  52986. 'â±¢' => 'É«',
  52987. 'â±£' => 'áµ½',
  52988. 'Ɽ' => 'ɽ',
  52989. 'Ⱨ' => 'ⱨ',
  52990. 'Ⱪ' => 'ⱪ',
  52991. 'Ⱬ' => 'ⱬ',
  52992. 'â±­' => 'É‘',
  52993. 'Ɱ' => 'ɱ',
  52994. 'Ɐ' => '�',
  52995. 'â±°' => 'É’',
  52996. 'â±²' => 'â±³',
  52997. 'â±µ' => 'â±¶',
  52998. 'â±¾' => 'È¿',
  52999. 'Ɀ' => 'ɀ',
  53000. 'Ⲁ' => '�',
  53001. 'Ⲃ' => 'ⲃ',
  53002. 'Ⲅ' => 'ⲅ',
  53003. 'Ⲇ' => 'ⲇ',
  53004. 'Ⲉ' => 'ⲉ',
  53005. 'Ⲋ' => 'ⲋ',
  53006. 'Ⲍ' => '�',
  53007. 'Ⲏ' => '�',
  53008. '�' => 'ⲑ',
  53009. 'Ⲓ' => 'ⲓ',
  53010. 'Ⲕ' => 'ⲕ',
  53011. 'â²–' => 'â²—',
  53012. 'Ⲙ' => 'ⲙ',
  53013. 'Ⲛ' => 'ⲛ',
  53014. 'Ⲝ' => '�',
  53015. 'Ⲟ' => 'ⲟ',
  53016. 'Ⲡ' => 'ⲡ',
  53017. 'â²¢' => 'â²£',
  53018. 'Ⲥ' => 'ⲥ',
  53019. 'Ⲧ' => 'ⲧ',
  53020. 'Ⲩ' => 'ⲩ',
  53021. 'Ⲫ' => 'ⲫ',
  53022. 'Ⲭ' => 'ⲭ',
  53023. 'Ⲯ' => 'ⲯ',
  53024. 'â²°' => 'â²±',
  53025. 'â²²' => 'â²³',
  53026. 'â²´' => 'â²µ',
  53027. 'â²¶' => 'â²·',
  53028. 'Ⲹ' => 'ⲹ',
  53029. 'Ⲻ' => 'ⲻ',
  53030. 'â²¼' => 'â²½',
  53031. 'Ⲿ' => 'ⲿ',
  53032. 'Ⳁ' => '�',
  53033. 'Ⳃ' => 'ⳃ',
  53034. 'Ⳅ' => 'ⳅ',
  53035. 'Ⳇ' => 'ⳇ',
  53036. 'Ⳉ' => 'ⳉ',
  53037. 'Ⳋ' => 'ⳋ',
  53038. 'Ⳍ' => '�',
  53039. 'Ⳏ' => '�',
  53040. '�' => 'ⳑ',
  53041. 'Ⳓ' => 'ⳓ',
  53042. 'Ⳕ' => 'ⳕ',
  53043. 'â³–' => 'â³—',
  53044. 'Ⳙ' => 'ⳙ',
  53045. 'Ⳛ' => 'ⳛ',
  53046. 'Ⳝ' => '�',
  53047. 'Ⳟ' => 'ⳟ',
  53048. 'Ⳡ' => 'ⳡ',
  53049. 'â³¢' => 'â³£',
  53050. 'Ⳬ' => 'ⳬ',
  53051. 'â³­' => 'â³®',
  53052. 'â³²' => 'â³³',
  53053. 'Ꙁ' => '�',
  53054. 'Ꙃ' => 'ꙃ',
  53055. 'Ꙅ' => 'ꙅ',
  53056. 'Ꙇ' => 'ꙇ',
  53057. 'Ꙉ' => 'ꙉ',
  53058. 'Ꙋ' => 'ꙋ',
  53059. 'Ꙍ' => '�',
  53060. 'Ꙏ' => '�',
  53061. '�' => 'ꙑ',
  53062. 'Ꙓ' => 'ꙓ',
  53063. 'Ꙕ' => 'ꙕ',
  53064. 'ê™–' => 'ê™—',
  53065. 'Ꙙ' => 'ꙙ',
  53066. 'Ꙛ' => 'ꙛ',
  53067. 'Ꙝ' => '�',
  53068. 'Ꙟ' => 'ꙟ',
  53069. 'Ꙡ' => 'ꙡ',
  53070. 'Ꙣ' => 'ꙣ',
  53071. 'Ꙥ' => 'ꙥ',
  53072. 'Ꙧ' => 'ꙧ',
  53073. 'Ꙩ' => 'ꙩ',
  53074. 'Ꙫ' => 'ꙫ',
  53075. 'Ꙭ' => 'ꙭ',
  53076. 'Ꚁ' => '�',
  53077. 'Ꚃ' => 'ꚃ',
  53078. 'êš„' => 'êš…',
  53079. 'Ꚇ' => 'ꚇ',
  53080. 'Ꚉ' => 'ꚉ',
  53081. 'Ꚋ' => 'ꚋ',
  53082. 'Ꚍ' => '�',
  53083. 'Ꚏ' => '�',
  53084. '�' => 'ꚑ',
  53085. 'êš’' => 'êš“',
  53086. 'êš”' => 'êš•',
  53087. 'êš–' => 'êš—',
  53088. 'Ꚙ' => 'ꚙ',
  53089. 'êšš' => 'êš›',
  53090. 'Ꜣ' => 'ꜣ',
  53091. 'Ꜥ' => 'ꜥ',
  53092. 'Ꜧ' => 'ꜧ',
  53093. 'Ꜩ' => 'ꜩ',
  53094. 'Ꜫ' => 'ꜫ',
  53095. 'Ꜭ' => 'ꜭ',
  53096. 'Ꜯ' => 'ꜯ',
  53097. 'Ꜳ' => 'ꜳ',
  53098. 'Ꜵ' => 'ꜵ',
  53099. 'Ꜷ' => 'ꜷ',
  53100. 'Ꜹ' => 'ꜹ',
  53101. 'Ꜻ' => 'ꜻ',
  53102. 'Ꜽ' => 'ꜽ',
  53103. 'Ꜿ' => 'ꜿ',
  53104. '�' => '�',
  53105. '�' => '�',
  53106. '�' => '�',
  53107. '�' => '�',
  53108. '�' => '�',
  53109. '�' => '�',
  53110. '�' => '�',
  53111. '�' => '�',
  53112. '�' => '�',
  53113. '�' => '�',
  53114. '�' => '�',
  53115. '�' => '�',
  53116. '�' => '�',
  53117. '�' => '�',
  53118. '�' => '�',
  53119. '�' => '�',
  53120. '�' => '�',
  53121. '�' => '�',
  53122. '�' => '�',
  53123. '�' => '�',
  53124. '�' => '�',
  53125. '�' => '�',
  53126. '�' => '�',
  53127. '�' => '�',
  53128. '�' => '�',
  53129. '�' => '�',
  53130. '�' => 'ᵹ',
  53131. '�' => '�',
  53132. 'Ꞁ' => '�',
  53133. 'Ꞃ' => 'ꞃ',
  53134. 'êž„' => 'êž…',
  53135. 'Ꞇ' => 'ꞇ',
  53136. 'Ꞌ' => 'ꞌ',
  53137. '�' => 'ɥ',
  53138. '�' => 'ꞑ',
  53139. 'êž’' => 'êž“',
  53140. 'êž–' => 'êž—',
  53141. 'Ꞙ' => 'ꞙ',
  53142. 'êžš' => 'êž›',
  53143. 'Ꞝ' => '�',
  53144. 'Ꞟ' => 'ꞟ',
  53145. 'êž ' => 'êž¡',
  53146. 'Ꞣ' => 'ꞣ',
  53147. 'Ꞥ' => 'ꞥ',
  53148. 'Ꞧ' => 'ꞧ',
  53149. 'Ꞩ' => 'ꞩ',
  53150. 'Ɦ' => 'ɦ',
  53151. 'Ɜ' => 'ɜ',
  53152. 'Ɡ' => 'ɡ',
  53153. 'Ɬ' => 'ɬ',
  53154. 'Ɪ' => 'ɪ',
  53155. 'êž°' => 'Êž',
  53156. 'Ʇ' => 'ʇ',
  53157. 'Ʝ' => '�',
  53158. 'êž³' => 'ê­“',
  53159. 'êž´' => 'êžµ',
  53160. 'êž¶' => 'êž·',
  53161. 'Ꞹ' => 'ꞹ',
  53162. 'Ꞻ' => 'ꞻ',
  53163. 'êž¼' => 'êž½',
  53164. 'êž¾' => 'êž¿',
  53165. 'Ꟃ' => 'ꟃ',
  53166. 'Ꞔ' => 'ꞔ',
  53167. 'Ʂ' => 'ʂ',
  53168. 'Ᶎ' => 'ᶎ',
  53169. 'Ꟈ' => 'ꟈ',
  53170. 'Ꟊ' => 'ꟊ',
  53171. 'Ꟶ' => 'ꟶ',
  53172. 'A' => '�',
  53173. 'B' => 'b',
  53174. 'C' => 'c',
  53175. 'D' => 'd',
  53176. 'ï¼¥' => 'ï½…',
  53177. 'F' => 'f',
  53178. 'G' => 'g',
  53179. 'H' => 'h',
  53180. 'I' => 'i',
  53181. 'J' => 'j',
  53182. 'K' => 'k',
  53183. 'L' => 'l',
  53184. 'M' => '�',
  53185. 'N' => 'n',
  53186. 'O' => '�',
  53187. 'P' => '�',
  53188. 'Q' => 'q',
  53189. 'ï¼²' => 'ï½’',
  53190. 'S' => 's',
  53191. 'ï¼´' => 'ï½”',
  53192. 'U' => 'u',
  53193. 'ï¼¶' => 'ï½–',
  53194. 'ï¼·' => 'ï½—',
  53195. 'X' => 'x',
  53196. 'ï¼¹' => 'ï½™',
  53197. 'Z' => 'z',
  53198. '�' => '�',
  53199. '�' => '�',
  53200. '�' => '�',
  53201. '�' => '�',
  53202. '�' => '�',
  53203. '�' => '�',
  53204. '�' => '�',
  53205. '�' => '�',
  53206. '�' => '�',
  53207. '�' => '�',
  53208. '�' => '�',
  53209. '�' => '�',
  53210. '�' => '�',
  53211. '�' => '�',
  53212. '�' => '�',
  53213. '�' => '�',
  53214. '�' => '�',
  53215. '�' => '�',
  53216. '�' => '�',
  53217. '�' => '�',
  53218. '�' => '�',
  53219. '�' => '�',
  53220. '�' => '�',
  53221. '�' => '�',
  53222. '�' => '�',
  53223. '�' => '�',
  53224. '�' => '�',
  53225. '�' => '�',
  53226. '�' => '�',
  53227. '�' => '�',
  53228. '�' => '�',
  53229. '�' => '�',
  53230. '�' => '�',
  53231. '�' => '�',
  53232. '�' => '�',
  53233. '�' => '�',
  53234. '�' => '�',
  53235. '�' => '�',
  53236. '�' => '�',
  53237. '�' => '�',
  53238. '�' => '�',
  53239. '�' => '�',
  53240. '�' => '�',
  53241. '�' => '�',
  53242. '�' => '�',
  53243. '�' => '�',
  53244. '�' => '�',
  53245. '�' => '�',
  53246. '�' => '�',
  53247. '�' => '�',
  53248. '�' => '�',
  53249. '�' => '�',
  53250. '�' => '�',
  53251. '�' => '�',
  53252. '�' => '�',
  53253. '�' => '�',
  53254. '�' => '�',
  53255. '�' => '�',
  53256. '�' => '�',
  53257. '�' => '�',
  53258. '�' => '�',
  53259. '�' => '�',
  53260. '�' => '�',
  53261. '�' => '�',
  53262. '�' => '�',
  53263. '�' => '�',
  53264. '�' => '�',
  53265. '�' => '�',
  53266. '�' => '�',
  53267. '�' => '�',
  53268. '�' => '�',
  53269. '�' => '�',
  53270. '�' => '�',
  53271. '�' => '�',
  53272. '�' => '�',
  53273. '�' => '�',
  53274. '�' => '�',
  53275. '�' => '�',
  53276. '�' => '�',
  53277. '�' => '�',
  53278. '�' => '�',
  53279. '�' => '�',
  53280. '�' => '�',
  53281. '�' => '�',
  53282. '�' => '�',
  53283. '�' => '�',
  53284. '�' => '�',
  53285. '�' => '�',
  53286. '�' => '�',
  53287. '�' => '�',
  53288. '�' => '�',
  53289. '�' => '�',
  53290. '�' => '�',
  53291. '�' => '�',
  53292. '�' => '�',
  53293. '�' => '�',
  53294. '�' => '�',
  53295. '�' => '�',
  53296. '�' => '�',
  53297. '�' => '�',
  53298. '�' => '�',
  53299. '�' => '�',
  53300. '�' => '�',
  53301. '�' => '�',
  53302. '�' => '�',
  53303. '�' => '�',
  53304. '�' => '�',
  53305. '�' => '�',
  53306. '�' => '�',
  53307. '�' => '�',
  53308. '�' => '�',
  53309. '�' => '�',
  53310. '�' => '�',
  53311. '�' => '�',
  53312. '�' => '�',
  53313. '�' => '�',
  53314. '�' => '�',
  53315. '�' => '�',
  53316. '�' => '�',
  53317. '�' => '�',
  53318. '�' => '�',
  53319. '�' => '�',
  53320. '�' => '�',
  53321. '�' => '�',
  53322. '�' => '�',
  53323. '�' => '�',
  53324. '�' => '�',
  53325. 'ð‘¢ ' => 'ð‘£€',
  53326. '𑢡' => '�',
  53327. '𑢢' => '𑣂',
  53328. '𑢣' => '𑣃',
  53329. '𑢤' => '𑣄',
  53330. 'ð‘¢¥' => 'ð‘£…',
  53331. '𑢦' => '𑣆',
  53332. '𑢧' => '𑣇',
  53333. '𑢨' => '𑣈',
  53334. '𑢩' => '𑣉',
  53335. '𑢪' => '𑣊',
  53336. '𑢫' => '𑣋',
  53337. '𑢬' => '𑣌',
  53338. '𑢭' => '�',
  53339. '𑢮' => '𑣎',
  53340. '𑢯' => '�',
  53341. '𑢰' => '�',
  53342. '𑢱' => '𑣑',
  53343. 'ð‘¢²' => 'ð‘£’',
  53344. '𑢳' => '𑣓',
  53345. 'ð‘¢´' => 'ð‘£”',
  53346. '𑢵' => '𑣕',
  53347. 'ð‘¢¶' => 'ð‘£–',
  53348. 'ð‘¢·' => 'ð‘£—',
  53349. '𑢸' => '𑣘',
  53350. 'ð‘¢¹' => 'ð‘£™',
  53351. '𑢺' => '𑣚',
  53352. 'ð‘¢»' => 'ð‘£›',
  53353. '𑢼' => '𑣜',
  53354. '𑢽' => '�',
  53355. '𑢾' => '𑣞',
  53356. '𑢿' => '𑣟',
  53357. 'ð–¹€' => 'ð–¹ ',
  53358. '�' => '𖹡',
  53359. '𖹂' => '𖹢',
  53360. '𖹃' => '𖹣',
  53361. '𖹄' => '𖹤',
  53362. 'ð–¹…' => 'ð–¹¥',
  53363. '𖹆' => '𖹦',
  53364. '𖹇' => '𖹧',
  53365. '𖹈' => '𖹨',
  53366. '𖹉' => '𖹩',
  53367. '𖹊' => '𖹪',
  53368. '𖹋' => '𖹫',
  53369. '𖹌' => '𖹬',
  53370. '�' => '𖹭',
  53371. '𖹎' => '𖹮',
  53372. '�' => '𖹯',
  53373. '�' => '𖹰',
  53374. '𖹑' => '𖹱',
  53375. 'ð–¹’' => 'ð–¹²',
  53376. '𖹓' => '𖹳',
  53377. 'ð–¹”' => 'ð–¹´',
  53378. '𖹕' => '𖹵',
  53379. 'ð–¹–' => 'ð–¹¶',
  53380. 'ð–¹—' => 'ð–¹·',
  53381. '𖹘' => '𖹸',
  53382. 'ð–¹™' => 'ð–¹¹',
  53383. '𖹚' => '𖹺',
  53384. 'ð–¹›' => 'ð–¹»',
  53385. '𖹜' => '𖹼',
  53386. '�' => '𖹽',
  53387. '𖹞' => '𖹾',
  53388. '𖹟' => '𖹿',
  53389. '𞤀' => '𞤢',
  53390. '�' => '𞤣',
  53391. '𞤂' => '𞤤',
  53392. '𞤃' => '𞤥',
  53393. '𞤄' => '𞤦',
  53394. '𞤅' => '𞤧',
  53395. '𞤆' => '𞤨',
  53396. '𞤇' => '𞤩',
  53397. '𞤈' => '𞤪',
  53398. '𞤉' => '𞤫',
  53399. '𞤊' => '𞤬',
  53400. '𞤋' => '𞤭',
  53401. '𞤌' => '𞤮',
  53402. '�' => '𞤯',
  53403. '𞤎' => '𞤰',
  53404. '�' => '𞤱',
  53405. '�' => '𞤲',
  53406. '𞤑' => '𞤳',
  53407. '𞤒' => '𞤴',
  53408. '𞤓' => '𞤵',
  53409. '𞤔' => '𞤶',
  53410. '𞤕' => '𞤷',
  53411. '𞤖' => '𞤸',
  53412. '𞤗' => '𞤹',
  53413. '𞤘' => '𞤺',
  53414. '𞤙' => '𞤻',
  53415. '𞤚' => '𞤼',
  53416. '𞤛' => '𞤽',
  53417. '𞤜' => '𞤾',
  53418. '�' => '𞤿',
  53419. '𞤞' => '𞥀',
  53420. '𞤟' => '�',
  53421. '𞤠' => '𞥂',
  53422. '𞤡' => '𞥃',
  53423. );
  53424. <?php
  53425. namespace Symfony\Component\OptionsResolver;
  53426. use Symfony\Component\OptionsResolver\Exception\AccessException;
  53427. use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException;
  53428. use Symfony\Component\OptionsResolver\Exception\MissingOptionsException;
  53429. use Symfony\Component\OptionsResolver\Exception\NoSuchOptionException;
  53430. use Symfony\Component\OptionsResolver\Exception\OptionDefinitionException;
  53431. use Symfony\Component\OptionsResolver\Exception\UndefinedOptionsException;
  53432. class OptionsResolver implements Options
  53433. {
  53434. private $defined = [];
  53435. private $defaults = [];
  53436. private $required = [];
  53437. private $resolved = [];
  53438. private $normalizers = [];
  53439. private $allowedValues = [];
  53440. private $allowedTypes = [];
  53441. private $lazy = [];
  53442. private $calling = [];
  53443. private $locked = false;
  53444. private static $typeAliases = [
  53445. 'boolean' => 'bool',
  53446. 'integer' => 'int',
  53447. 'double' => 'float',
  53448. ];
  53449. public function setDefault($option, $value)
  53450. {
  53451. if ($this->locked) {
  53452. throw new AccessException('Default values cannot be set from a lazy option or normalizer.');
  53453. }
  53454. if ($value instanceof \Closure) {
  53455. $reflClosure = new \ReflectionFunction($value);
  53456. $params = $reflClosure->getParameters();
  53457. if (isset($params[0]) && Options::class === $this->getParameterClassName($params[0])) {
  53458. if (!isset($this->defaults[$option])) {
  53459. $this->defaults[$option] = null;
  53460. }
  53461. if (!isset($this->lazy[$option]) || !isset($params[1])) {
  53462. $this->lazy[$option] = [];
  53463. }
  53464. $this->lazy[$option][] = $value;
  53465. $this->defined[$option] = true;
  53466. unset($this->resolved[$option]);
  53467. return $this;
  53468. }
  53469. }
  53470. unset($this->lazy[$option]);
  53471. if (!isset($this->defined[$option]) || \array_key_exists($option, $this->resolved)) {
  53472. $this->resolved[$option] = $value;
  53473. }
  53474. $this->defaults[$option] = $value;
  53475. $this->defined[$option] = true;
  53476. return $this;
  53477. }
  53478. public function setDefaults(array $defaults)
  53479. {
  53480. foreach ($defaults as $option => $value) {
  53481. $this->setDefault($option, $value);
  53482. }
  53483. return $this;
  53484. }
  53485. public function hasDefault($option)
  53486. {
  53487. return \array_key_exists($option, $this->defaults);
  53488. }
  53489. public function setRequired($optionNames)
  53490. {
  53491. if ($this->locked) {
  53492. throw new AccessException('Options cannot be made required from a lazy option or normalizer.');
  53493. }
  53494. foreach ((array) $optionNames as $option) {
  53495. $this->defined[$option] = true;
  53496. $this->required[$option] = true;
  53497. }
  53498. return $this;
  53499. }
  53500. public function isRequired($option)
  53501. {
  53502. return isset($this->required[$option]);
  53503. }
  53504. public function getRequiredOptions()
  53505. {
  53506. return array_keys($this->required);
  53507. }
  53508. public function isMissing($option)
  53509. {
  53510. return isset($this->required[$option]) && !\array_key_exists($option, $this->defaults);
  53511. }
  53512. public function getMissingOptions()
  53513. {
  53514. return array_keys(array_diff_key($this->required, $this->defaults));
  53515. }
  53516. public function setDefined($optionNames)
  53517. {
  53518. if ($this->locked) {
  53519. throw new AccessException('Options cannot be defined from a lazy option or normalizer.');
  53520. }
  53521. foreach ((array) $optionNames as $option) {
  53522. $this->defined[$option] = true;
  53523. }
  53524. return $this;
  53525. }
  53526. public function isDefined($option)
  53527. {
  53528. return isset($this->defined[$option]);
  53529. }
  53530. public function getDefinedOptions()
  53531. {
  53532. return array_keys($this->defined);
  53533. }
  53534. public function setNormalizer($option, \Closure $normalizer)
  53535. {
  53536. if ($this->locked) {
  53537. throw new AccessException('Normalizers cannot be set from a lazy option or normalizer.');
  53538. }
  53539. if (!isset($this->defined[$option])) {
  53540. throw new UndefinedOptionsException(sprintf('The option "%s" does not exist. Defined options are: "%s".', $option, implode('", "', array_keys($this->defined))));
  53541. }
  53542. $this->normalizers[$option] = $normalizer;
  53543. unset($this->resolved[$option]);
  53544. return $this;
  53545. }
  53546. public function setAllowedValues($option, $allowedValues)
  53547. {
  53548. if ($this->locked) {
  53549. throw new AccessException('Allowed values cannot be set from a lazy option or normalizer.');
  53550. }
  53551. if (!isset($this->defined[$option])) {
  53552. throw new UndefinedOptionsException(sprintf('The option "%s" does not exist. Defined options are: "%s".', $option, implode('", "', array_keys($this->defined))));
  53553. }
  53554. $this->allowedValues[$option] = \is_array($allowedValues) ? $allowedValues : [$allowedValues];
  53555. unset($this->resolved[$option]);
  53556. return $this;
  53557. }
  53558. public function addAllowedValues($option, $allowedValues)
  53559. {
  53560. if ($this->locked) {
  53561. throw new AccessException('Allowed values cannot be added from a lazy option or normalizer.');
  53562. }
  53563. if (!isset($this->defined[$option])) {
  53564. throw new UndefinedOptionsException(sprintf('The option "%s" does not exist. Defined options are: "%s".', $option, implode('", "', array_keys($this->defined))));
  53565. }
  53566. if (!\is_array($allowedValues)) {
  53567. $allowedValues = [$allowedValues];
  53568. }
  53569. if (!isset($this->allowedValues[$option])) {
  53570. $this->allowedValues[$option] = $allowedValues;
  53571. } else {
  53572. $this->allowedValues[$option] = array_merge($this->allowedValues[$option], $allowedValues);
  53573. }
  53574. unset($this->resolved[$option]);
  53575. return $this;
  53576. }
  53577. public function setAllowedTypes($option, $allowedTypes)
  53578. {
  53579. if ($this->locked) {
  53580. throw new AccessException('Allowed types cannot be set from a lazy option or normalizer.');
  53581. }
  53582. if (!isset($this->defined[$option])) {
  53583. throw new UndefinedOptionsException(sprintf('The option "%s" does not exist. Defined options are: "%s".', $option, implode('", "', array_keys($this->defined))));
  53584. }
  53585. $this->allowedTypes[$option] = (array) $allowedTypes;
  53586. unset($this->resolved[$option]);
  53587. return $this;
  53588. }
  53589. public function addAllowedTypes($option, $allowedTypes)
  53590. {
  53591. if ($this->locked) {
  53592. throw new AccessException('Allowed types cannot be added from a lazy option or normalizer.');
  53593. }
  53594. if (!isset($this->defined[$option])) {
  53595. throw new UndefinedOptionsException(sprintf('The option "%s" does not exist. Defined options are: "%s".', $option, implode('", "', array_keys($this->defined))));
  53596. }
  53597. if (!isset($this->allowedTypes[$option])) {
  53598. $this->allowedTypes[$option] = (array) $allowedTypes;
  53599. } else {
  53600. $this->allowedTypes[$option] = array_merge($this->allowedTypes[$option], (array) $allowedTypes);
  53601. }
  53602. unset($this->resolved[$option]);
  53603. return $this;
  53604. }
  53605. public function remove($optionNames)
  53606. {
  53607. if ($this->locked) {
  53608. throw new AccessException('Options cannot be removed from a lazy option or normalizer.');
  53609. }
  53610. foreach ((array) $optionNames as $option) {
  53611. unset($this->defined[$option], $this->defaults[$option], $this->required[$option], $this->resolved[$option]);
  53612. unset($this->lazy[$option], $this->normalizers[$option], $this->allowedTypes[$option], $this->allowedValues[$option]);
  53613. }
  53614. return $this;
  53615. }
  53616. public function clear()
  53617. {
  53618. if ($this->locked) {
  53619. throw new AccessException('Options cannot be cleared from a lazy option or normalizer.');
  53620. }
  53621. $this->defined = [];
  53622. $this->defaults = [];
  53623. $this->required = [];
  53624. $this->resolved = [];
  53625. $this->lazy = [];
  53626. $this->normalizers = [];
  53627. $this->allowedTypes = [];
  53628. $this->allowedValues = [];
  53629. return $this;
  53630. }
  53631. public function resolve(array $options = [])
  53632. {
  53633. if ($this->locked) {
  53634. throw new AccessException('Options cannot be resolved from a lazy option or normalizer.');
  53635. }
  53636. $clone = clone $this;
  53637. $diff = array_diff_key($options, $clone->defined);
  53638. if (\count($diff) > 0) {
  53639. ksort($clone->defined);
  53640. ksort($diff);
  53641. throw new UndefinedOptionsException(sprintf((\count($diff) > 1 ? 'The options "%s" do not exist.' : 'The option "%s" does not exist.').' Defined options are: "%s".', implode('", "', array_keys($diff)), implode('", "', array_keys($clone->defined))));
  53642. }
  53643. foreach ($options as $option => $value) {
  53644. $clone->defaults[$option] = $value;
  53645. unset($clone->resolved[$option], $clone->lazy[$option]);
  53646. }
  53647. $diff = array_diff_key($clone->required, $clone->defaults);
  53648. if (\count($diff) > 0) {
  53649. ksort($diff);
  53650. throw new MissingOptionsException(sprintf(\count($diff) > 1 ? 'The required options "%s" are missing.' : 'The required option "%s" is missing.', implode('", "', array_keys($diff))));
  53651. }
  53652. $clone->locked = true;
  53653. foreach ($clone->defaults as $option => $_) {
  53654. $clone->offsetGet($option);
  53655. }
  53656. return $clone->resolved;
  53657. }
  53658. public function offsetGet($option)
  53659. {
  53660. if (!$this->locked) {
  53661. throw new AccessException('Array access is only supported within closures of lazy options and normalizers.');
  53662. }
  53663. if (\array_key_exists($option, $this->resolved)) {
  53664. return $this->resolved[$option];
  53665. }
  53666. if (!\array_key_exists($option, $this->defaults)) {
  53667. if (!isset($this->defined[$option])) {
  53668. throw new NoSuchOptionException(sprintf('The option "%s" does not exist. Defined options are: "%s".', $option, implode('", "', array_keys($this->defined))));
  53669. }
  53670. throw new NoSuchOptionException(sprintf('The optional option "%s" has no value set. You should make sure it is set with "isset" before reading it.', $option));
  53671. }
  53672. $value = $this->defaults[$option];
  53673. if (isset($this->lazy[$option])) {
  53674. if (isset($this->calling[$option])) {
  53675. throw new OptionDefinitionException(sprintf('The options "%s" have a cyclic dependency.', implode('", "', array_keys($this->calling))));
  53676. }
  53677. $this->calling[$option] = true;
  53678. try {
  53679. foreach ($this->lazy[$option] as $closure) {
  53680. $value = $closure($this, $value);
  53681. }
  53682. } finally {
  53683. unset($this->calling[$option]);
  53684. }
  53685. }
  53686. if (isset($this->allowedTypes[$option])) {
  53687. $valid = true;
  53688. $invalidTypes = [];
  53689. foreach ($this->allowedTypes[$option] as $type) {
  53690. $type = isset(self::$typeAliases[$type]) ? self::$typeAliases[$type] : $type;
  53691. if ($valid = $this->verifyTypes($type, $value, $invalidTypes)) {
  53692. break;
  53693. }
  53694. }
  53695. if (!$valid) {
  53696. $fmtActualValue = $this->formatValue($value);
  53697. $fmtAllowedTypes = implode('" or "', $this->allowedTypes[$option]);
  53698. $fmtProvidedTypes = implode('|', array_keys($invalidTypes));
  53699. $allowedContainsArrayType = \count(array_filter(
  53700. $this->allowedTypes[$option],
  53701. function ($item) {
  53702. return '[]' === substr(isset(self::$typeAliases[$item]) ? self::$typeAliases[$item] : $item, -2);
  53703. }
  53704. )) > 0;
  53705. if (\is_array($value) && $allowedContainsArrayType) {
  53706. 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".', $option, $fmtActualValue, $fmtAllowedTypes, $fmtProvidedTypes));
  53707. }
  53708. throw new InvalidOptionsException(sprintf('The option "%s" with value %s is expected to be of type "%s", but is of type "%s".', $option, $fmtActualValue, $fmtAllowedTypes, $fmtProvidedTypes));
  53709. }
  53710. }
  53711. if (isset($this->allowedValues[$option])) {
  53712. $success = false;
  53713. $printableAllowedValues = [];
  53714. foreach ($this->allowedValues[$option] as $allowedValue) {
  53715. if ($allowedValue instanceof \Closure) {
  53716. if ($allowedValue($value)) {
  53717. $success = true;
  53718. break;
  53719. }
  53720. continue;
  53721. }
  53722. if ($value === $allowedValue) {
  53723. $success = true;
  53724. break;
  53725. }
  53726. $printableAllowedValues[] = $allowedValue;
  53727. }
  53728. if (!$success) {
  53729. $message = sprintf(
  53730. 'The option "%s" with value %s is invalid.',
  53731. $option,
  53732. $this->formatValue($value)
  53733. );
  53734. if (\count($printableAllowedValues) > 0) {
  53735. $message .= sprintf(
  53736. ' Accepted values are: %s.',
  53737. $this->formatValues($printableAllowedValues)
  53738. );
  53739. }
  53740. throw new InvalidOptionsException($message);
  53741. }
  53742. }
  53743. if (isset($this->normalizers[$option])) {
  53744. if (isset($this->calling[$option])) {
  53745. throw new OptionDefinitionException(sprintf('The options "%s" have a cyclic dependency.', implode('", "', array_keys($this->calling))));
  53746. }
  53747. $normalizer = $this->normalizers[$option];
  53748. $this->calling[$option] = true;
  53749. try {
  53750. $value = $normalizer($this, $value);
  53751. } finally {
  53752. unset($this->calling[$option]);
  53753. }
  53754. }
  53755. $this->resolved[$option] = $value;
  53756. return $value;
  53757. }
  53758. private function verifyTypes($type, $value, array &$invalidTypes)
  53759. {
  53760. if (\is_array($value) && '[]' === substr($type, -2)) {
  53761. return $this->verifyArrayType($type, $value, $invalidTypes);
  53762. }
  53763. if (self::isValueValidType($type, $value)) {
  53764. return true;
  53765. }
  53766. if (!$invalidTypes) {
  53767. $invalidTypes[$this->formatTypeOf($value, null)] = true;
  53768. }
  53769. return false;
  53770. }
  53771. private function verifyArrayType($type, array $value, array &$invalidTypes, $level = 0)
  53772. {
  53773. $type = substr($type, 0, -2);
  53774. if ('[]' === substr($type, -2)) {
  53775. $success = true;
  53776. foreach ($value as $item) {
  53777. if (!\is_array($item)) {
  53778. $invalidTypes[$this->formatTypeOf($item, null)] = true;
  53779. $success = false;
  53780. } elseif (!$this->verifyArrayType($type, $item, $invalidTypes, $level + 1)) {
  53781. $success = false;
  53782. }
  53783. }
  53784. return $success;
  53785. }
  53786. $valid = true;
  53787. foreach ($value as $item) {
  53788. if (!self::isValueValidType($type, $item)) {
  53789. $invalidTypes[$this->formatTypeOf($item, $type)] = $value;
  53790. $valid = false;
  53791. }
  53792. }
  53793. return $valid;
  53794. }
  53795. public function offsetExists($option)
  53796. {
  53797. if (!$this->locked) {
  53798. throw new AccessException('Array access is only supported within closures of lazy options and normalizers.');
  53799. }
  53800. return \array_key_exists($option, $this->defaults);
  53801. }
  53802. public function offsetSet($option, $value)
  53803. {
  53804. throw new AccessException('Setting options via array access is not supported. Use setDefault() instead.');
  53805. }
  53806. public function offsetUnset($option)
  53807. {
  53808. throw new AccessException('Removing options via array access is not supported. Use remove() instead.');
  53809. }
  53810. public function count()
  53811. {
  53812. if (!$this->locked) {
  53813. throw new AccessException('Counting is only supported within closures of lazy options and normalizers.');
  53814. }
  53815. return \count($this->defaults);
  53816. }
  53817. private function formatTypeOf($value, $type)
  53818. {
  53819. $suffix = '';
  53820. if ('[]' === substr($type, -2)) {
  53821. $suffix = '[]';
  53822. $type = substr($type, 0, -2);
  53823. while ('[]' === substr($type, -2)) {
  53824. $type = substr($type, 0, -2);
  53825. $value = array_shift($value);
  53826. if (!\is_array($value)) {
  53827. break;
  53828. }
  53829. $suffix .= '[]';
  53830. }
  53831. if (\is_array($value)) {
  53832. $subTypes = [];
  53833. foreach ($value as $val) {
  53834. $subTypes[$this->formatTypeOf($val, null)] = true;
  53835. }
  53836. return implode('|', array_keys($subTypes)).$suffix;
  53837. }
  53838. }
  53839. return (\is_object($value) ? \get_class($value) : \gettype($value)).$suffix;
  53840. }
  53841. private function formatValue($value)
  53842. {
  53843. if (\is_object($value)) {
  53844. return \get_class($value);
  53845. }
  53846. if (\is_array($value)) {
  53847. return 'array';
  53848. }
  53849. if (\is_string($value)) {
  53850. return '"'.$value.'"';
  53851. }
  53852. if (\is_resource($value)) {
  53853. return 'resource';
  53854. }
  53855. if (null === $value) {
  53856. return 'null';
  53857. }
  53858. if (false === $value) {
  53859. return 'false';
  53860. }
  53861. if (true === $value) {
  53862. return 'true';
  53863. }
  53864. return (string) $value;
  53865. }
  53866. private function formatValues(array $values)
  53867. {
  53868. foreach ($values as $key => $value) {
  53869. $values[$key] = $this->formatValue($value);
  53870. }
  53871. return implode(', ', $values);
  53872. }
  53873. private static function isValueValidType($type, $value)
  53874. {
  53875. return (\function_exists($isFunction = 'is_'.$type) && $isFunction($value)) || $value instanceof $type;
  53876. }
  53877. private function getParameterClassName(\ReflectionParameter $parameter)
  53878. {
  53879. if (!method_exists($parameter, 'getType')) {
  53880. return ($class = $parameter->getClass()) ? $class->name : null;
  53881. }
  53882. if (!($type = $parameter->getType()) || $type->isBuiltin()) {
  53883. return null;
  53884. }
  53885. return method_exists($type, 'getName') ? $type->getName() : (string) $type;
  53886. }
  53887. }
  53888. <?php
  53889. namespace Symfony\Component\OptionsResolver\Debug;
  53890. use Symfony\Component\OptionsResolver\Exception\NoConfigurationException;
  53891. use Symfony\Component\OptionsResolver\Exception\UndefinedOptionsException;
  53892. use Symfony\Component\OptionsResolver\OptionsResolver;
  53893. class OptionsResolverIntrospector
  53894. {
  53895. private $get;
  53896. public function __construct(OptionsResolver $optionsResolver)
  53897. {
  53898. $this->get = \Closure::bind(function ($property, $option, $message) {
  53899. if (!$this->isDefined($option)) {
  53900. throw new UndefinedOptionsException(sprintf('The option "%s" does not exist.', $option));
  53901. }
  53902. if (!\array_key_exists($option, $this->{$property})) {
  53903. throw new NoConfigurationException($message);
  53904. }
  53905. return $this->{$property}[$option];
  53906. }, $optionsResolver, $optionsResolver);
  53907. }
  53908. public function getDefault($option)
  53909. {
  53910. return \call_user_func($this->get, 'defaults', $option, sprintf('No default value was set for the "%s" option.', $option));
  53911. }
  53912. public function getLazyClosures($option)
  53913. {
  53914. return \call_user_func($this->get, 'lazy', $option, sprintf('No lazy closures were set for the "%s" option.', $option));
  53915. }
  53916. public function getAllowedTypes($option)
  53917. {
  53918. return \call_user_func($this->get, 'allowedTypes', $option, sprintf('No allowed types were set for the "%s" option.', $option));
  53919. }
  53920. public function getAllowedValues($option)
  53921. {
  53922. return \call_user_func($this->get, 'allowedValues', $option, sprintf('No allowed values were set for the "%s" option.', $option));
  53923. }
  53924. public function getNormalizer($option)
  53925. {
  53926. return \call_user_func($this->get, 'normalizers', $option, sprintf('No normalizer was set for the "%s" option.', $option));
  53927. }
  53928. }
  53929. <?php
  53930. namespace Symfony\Component\OptionsResolver;
  53931. interface Options extends \ArrayAccess, \Countable
  53932. {
  53933. }
  53934. <?php
  53935. namespace Symfony\Component\OptionsResolver\Exception;
  53936. class MissingOptionsException extends InvalidArgumentException
  53937. {
  53938. }
  53939. <?php
  53940. namespace Symfony\Component\OptionsResolver\Exception;
  53941. class AccessException extends \LogicException implements ExceptionInterface
  53942. {
  53943. }
  53944. <?php
  53945. namespace Symfony\Component\OptionsResolver\Exception;
  53946. interface ExceptionInterface
  53947. {
  53948. }
  53949. <?php
  53950. namespace Symfony\Component\OptionsResolver\Exception;
  53951. class OptionDefinitionException extends \LogicException implements ExceptionInterface
  53952. {
  53953. }
  53954. <?php
  53955. namespace Symfony\Component\OptionsResolver\Exception;
  53956. use Symfony\Component\OptionsResolver\Debug\OptionsResolverIntrospector;
  53957. class NoConfigurationException extends \RuntimeException implements ExceptionInterface
  53958. {
  53959. }
  53960. <?php
  53961. namespace Symfony\Component\OptionsResolver\Exception;
  53962. class UndefinedOptionsException extends InvalidArgumentException
  53963. {
  53964. }
  53965. <?php
  53966. namespace Symfony\Component\OptionsResolver\Exception;
  53967. class InvalidOptionsException extends InvalidArgumentException
  53968. {
  53969. }
  53970. <?php
  53971. namespace Symfony\Component\OptionsResolver\Exception;
  53972. class NoSuchOptionException extends \OutOfBoundsException implements ExceptionInterface
  53973. {
  53974. }
  53975. <?php
  53976. namespace Symfony\Component\OptionsResolver\Exception;
  53977. class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface
  53978. {
  53979. }
  53980. <?php
  53981. namespace Symfony\Component\EventDispatcher\Debug;
  53982. use Symfony\Component\EventDispatcher\Event;
  53983. use Symfony\Component\EventDispatcher\EventDispatcherInterface;
  53984. use Symfony\Component\Stopwatch\Stopwatch;
  53985. use Symfony\Component\VarDumper\Caster\ClassStub;
  53986. class WrappedListener
  53987. {
  53988. private $listener;
  53989. private $name;
  53990. private $called;
  53991. private $stoppedPropagation;
  53992. private $stopwatch;
  53993. private $dispatcher;
  53994. private $pretty;
  53995. private $stub;
  53996. private $priority;
  53997. private static $hasClassStub;
  53998. public function __construct($listener, $name, Stopwatch $stopwatch, EventDispatcherInterface $dispatcher = null)
  53999. {
  54000. $this->listener = $listener;
  54001. $this->stopwatch = $stopwatch;
  54002. $this->dispatcher = $dispatcher;
  54003. $this->called = false;
  54004. $this->stoppedPropagation = false;
  54005. if (\is_array($listener)) {
  54006. $this->name = \is_object($listener[0]) ? \get_class($listener[0]) : $listener[0];
  54007. $this->pretty = $this->name.'::'.$listener[1];
  54008. } elseif ($listener instanceof \Closure) {
  54009. $r = new \ReflectionFunction($listener);
  54010. if (false !== strpos($r->name, '{closure}')) {
  54011. $this->pretty = $this->name = 'closure';
  54012. } elseif ($class = $r->getClosureScopeClass()) {
  54013. $this->name = $class->name;
  54014. $this->pretty = $this->name.'::'.$r->name;
  54015. } else {
  54016. $this->pretty = $this->name = $r->name;
  54017. }
  54018. } elseif (\is_string($listener)) {
  54019. $this->pretty = $this->name = $listener;
  54020. } else {
  54021. $this->name = \get_class($listener);
  54022. $this->pretty = $this->name.'::__invoke';
  54023. }
  54024. if (null !== $name) {
  54025. $this->name = $name;
  54026. }
  54027. if (null === self::$hasClassStub) {
  54028. self::$hasClassStub = class_exists(ClassStub::class);
  54029. }
  54030. }
  54031. public function getWrappedListener()
  54032. {
  54033. return $this->listener;
  54034. }
  54035. public function wasCalled()
  54036. {
  54037. return $this->called;
  54038. }
  54039. public function stoppedPropagation()
  54040. {
  54041. return $this->stoppedPropagation;
  54042. }
  54043. public function getPretty()
  54044. {
  54045. return $this->pretty;
  54046. }
  54047. public function getInfo($eventName)
  54048. {
  54049. if (null === $this->stub) {
  54050. $this->stub = self::$hasClassStub ? new ClassStub($this->pretty.'()', $this->listener) : $this->pretty.'()';
  54051. }
  54052. return [
  54053. 'event' => $eventName,
  54054. 'priority' => null !== $this->priority ? $this->priority : (null !== $this->dispatcher ? $this->dispatcher->getListenerPriority($eventName, $this->listener) : null),
  54055. 'pretty' => $this->pretty,
  54056. 'stub' => $this->stub,
  54057. ];
  54058. }
  54059. public function __invoke(Event $event, $eventName, EventDispatcherInterface $dispatcher)
  54060. {
  54061. $dispatcher = $this->dispatcher ?: $dispatcher;
  54062. $this->called = true;
  54063. $this->priority = $dispatcher->getListenerPriority($eventName, $this->listener);
  54064. $e = $this->stopwatch->start($this->name, 'event_listener');
  54065. \call_user_func($this->listener, $event, $eventName, $dispatcher);
  54066. if ($e->isStarted()) {
  54067. $e->stop();
  54068. }
  54069. if ($event->isPropagationStopped()) {
  54070. $this->stoppedPropagation = true;
  54071. }
  54072. }
  54073. }
  54074. <?php
  54075. namespace Symfony\Component\EventDispatcher\Debug;
  54076. use Symfony\Component\EventDispatcher\EventDispatcherInterface;
  54077. interface TraceableEventDispatcherInterface extends EventDispatcherInterface
  54078. {
  54079. public function getCalledListeners();
  54080. public function getNotCalledListeners();
  54081. }
  54082. <?php
  54083. namespace Symfony\Component\EventDispatcher\Debug;
  54084. use Psr\Log\LoggerInterface;
  54085. use Symfony\Component\EventDispatcher\Event;
  54086. use Symfony\Component\EventDispatcher\EventDispatcherInterface;
  54087. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  54088. use Symfony\Component\Stopwatch\Stopwatch;
  54089. class TraceableEventDispatcher implements TraceableEventDispatcherInterface
  54090. {
  54091. protected $logger;
  54092. protected $stopwatch;
  54093. private $callStack;
  54094. private $dispatcher;
  54095. private $wrappedListeners;
  54096. public function __construct(EventDispatcherInterface $dispatcher, Stopwatch $stopwatch, LoggerInterface $logger = null)
  54097. {
  54098. $this->dispatcher = $dispatcher;
  54099. $this->stopwatch = $stopwatch;
  54100. $this->logger = $logger;
  54101. $this->wrappedListeners = [];
  54102. }
  54103. public function addListener($eventName, $listener, $priority = 0)
  54104. {
  54105. $this->dispatcher->addListener($eventName, $listener, $priority);
  54106. }
  54107. public function addSubscriber(EventSubscriberInterface $subscriber)
  54108. {
  54109. $this->dispatcher->addSubscriber($subscriber);
  54110. }
  54111. public function removeListener($eventName, $listener)
  54112. {
  54113. if (isset($this->wrappedListeners[$eventName])) {
  54114. foreach ($this->wrappedListeners[$eventName] as $index => $wrappedListener) {
  54115. if ($wrappedListener->getWrappedListener() === $listener) {
  54116. $listener = $wrappedListener;
  54117. unset($this->wrappedListeners[$eventName][$index]);
  54118. break;
  54119. }
  54120. }
  54121. }
  54122. return $this->dispatcher->removeListener($eventName, $listener);
  54123. }
  54124. public function removeSubscriber(EventSubscriberInterface $subscriber)
  54125. {
  54126. return $this->dispatcher->removeSubscriber($subscriber);
  54127. }
  54128. public function getListeners($eventName = null)
  54129. {
  54130. return $this->dispatcher->getListeners($eventName);
  54131. }
  54132. public function getListenerPriority($eventName, $listener)
  54133. {
  54134. if (isset($this->wrappedListeners[$eventName])) {
  54135. foreach ($this->wrappedListeners[$eventName] as $index => $wrappedListener) {
  54136. if ($wrappedListener->getWrappedListener() === $listener) {
  54137. return $this->dispatcher->getListenerPriority($eventName, $wrappedListener);
  54138. }
  54139. }
  54140. }
  54141. return $this->dispatcher->getListenerPriority($eventName, $listener);
  54142. }
  54143. public function hasListeners($eventName = null)
  54144. {
  54145. return $this->dispatcher->hasListeners($eventName);
  54146. }
  54147. public function dispatch($eventName, Event $event = null)
  54148. {
  54149. if (null === $this->callStack) {
  54150. $this->callStack = new \SplObjectStorage();
  54151. }
  54152. if (null === $event) {
  54153. $event = new Event();
  54154. }
  54155. if (null !== $this->logger && $event->isPropagationStopped()) {
  54156. $this->logger->debug(sprintf('The "%s" event is already stopped. No listeners have been called.', $eventName));
  54157. }
  54158. $this->preProcess($eventName);
  54159. try {
  54160. $this->preDispatch($eventName, $event);
  54161. try {
  54162. $e = $this->stopwatch->start($eventName, 'section');
  54163. try {
  54164. $this->dispatcher->dispatch($eventName, $event);
  54165. } finally {
  54166. if ($e->isStarted()) {
  54167. $e->stop();
  54168. }
  54169. }
  54170. } finally {
  54171. $this->postDispatch($eventName, $event);
  54172. }
  54173. } finally {
  54174. $this->postProcess($eventName);
  54175. }
  54176. return $event;
  54177. }
  54178. public function getCalledListeners()
  54179. {
  54180. if (null === $this->callStack) {
  54181. return [];
  54182. }
  54183. $called = [];
  54184. foreach ($this->callStack as $listener) {
  54185. list($eventName) = $this->callStack->getInfo();
  54186. $called[] = $listener->getInfo($eventName);
  54187. }
  54188. return $called;
  54189. }
  54190. public function getNotCalledListeners()
  54191. {
  54192. try {
  54193. $allListeners = $this->getListeners();
  54194. } catch (\Exception $e) {
  54195. if (null !== $this->logger) {
  54196. $this->logger->info('An exception was thrown while getting the uncalled listeners.', ['exception' => $e]);
  54197. }
  54198. return [];
  54199. }
  54200. $calledListeners = [];
  54201. if (null !== $this->callStack) {
  54202. foreach ($this->callStack as $calledListener) {
  54203. $calledListeners[] = $calledListener->getWrappedListener();
  54204. }
  54205. }
  54206. $notCalled = [];
  54207. foreach ($allListeners as $eventName => $listeners) {
  54208. foreach ($listeners as $listener) {
  54209. if (!\in_array($listener, $calledListeners, true)) {
  54210. if (!$listener instanceof WrappedListener) {
  54211. $listener = new WrappedListener($listener, null, $this->stopwatch, $this);
  54212. }
  54213. $notCalled[] = $listener->getInfo($eventName);
  54214. }
  54215. }
  54216. }
  54217. uasort($notCalled, [$this, 'sortNotCalledListeners']);
  54218. return $notCalled;
  54219. }
  54220. public function reset()
  54221. {
  54222. $this->callStack = null;
  54223. }
  54224. public function __call($method, $arguments)
  54225. {
  54226. return \call_user_func_array([$this->dispatcher, $method], $arguments);
  54227. }
  54228. protected function preDispatch($eventName, Event $event)
  54229. {
  54230. }
  54231. protected function postDispatch($eventName, Event $event)
  54232. {
  54233. }
  54234. private function preProcess($eventName)
  54235. {
  54236. foreach ($this->dispatcher->getListeners($eventName) as $listener) {
  54237. $priority = $this->getListenerPriority($eventName, $listener);
  54238. $wrappedListener = new WrappedListener($listener instanceof WrappedListener ? $listener->getWrappedListener() : $listener, null, $this->stopwatch, $this);
  54239. $this->wrappedListeners[$eventName][] = $wrappedListener;
  54240. $this->dispatcher->removeListener($eventName, $listener);
  54241. $this->dispatcher->addListener($eventName, $wrappedListener, $priority);
  54242. $this->callStack->attach($wrappedListener, [$eventName]);
  54243. }
  54244. }
  54245. private function postProcess($eventName)
  54246. {
  54247. unset($this->wrappedListeners[$eventName]);
  54248. $skipped = false;
  54249. foreach ($this->dispatcher->getListeners($eventName) as $listener) {
  54250. if (!$listener instanceof WrappedListener) {
  54251. continue;
  54252. }
  54253. $priority = $this->getListenerPriority($eventName, $listener);
  54254. $this->dispatcher->removeListener($eventName, $listener);
  54255. $this->dispatcher->addListener($eventName, $listener->getWrappedListener(), $priority);
  54256. if (null !== $this->logger) {
  54257. $context = ['event' => $eventName, 'listener' => $listener->getPretty()];
  54258. }
  54259. if ($listener->wasCalled()) {
  54260. if (null !== $this->logger) {
  54261. $this->logger->debug('Notified event "{event}" to listener "{listener}".', $context);
  54262. }
  54263. } else {
  54264. $this->callStack->detach($listener);
  54265. }
  54266. if (null !== $this->logger && $skipped) {
  54267. $this->logger->debug('Listener "{listener}" was not called for event "{event}".', $context);
  54268. }
  54269. if ($listener->stoppedPropagation()) {
  54270. if (null !== $this->logger) {
  54271. $this->logger->debug('Listener "{listener}" stopped propagation of the event "{event}".', $context);
  54272. }
  54273. $skipped = true;
  54274. }
  54275. }
  54276. }
  54277. private function sortNotCalledListeners(array $a, array $b)
  54278. {
  54279. if (0 !== $cmp = strcmp($a['event'], $b['event'])) {
  54280. return $cmp;
  54281. }
  54282. if (\is_int($a['priority']) && !\is_int($b['priority'])) {
  54283. return 1;
  54284. }
  54285. if (!\is_int($a['priority']) && \is_int($b['priority'])) {
  54286. return -1;
  54287. }
  54288. if ($a['priority'] === $b['priority']) {
  54289. return 0;
  54290. }
  54291. if ($a['priority'] > $b['priority']) {
  54292. return -1;
  54293. }
  54294. return 1;
  54295. }
  54296. }
  54297. <?php
  54298. namespace Symfony\Component\EventDispatcher\DependencyInjection;
  54299. use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
  54300. use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
  54301. use Symfony\Component\DependencyInjection\ContainerBuilder;
  54302. use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
  54303. use Symfony\Component\DependencyInjection\Reference;
  54304. use Symfony\Component\EventDispatcher\EventDispatcher;
  54305. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  54306. class RegisterListenersPass implements CompilerPassInterface
  54307. {
  54308. protected $dispatcherService;
  54309. protected $listenerTag;
  54310. protected $subscriberTag;
  54311. private $hotPathEvents = [];
  54312. private $hotPathTagName;
  54313. public function __construct($dispatcherService = 'event_dispatcher', $listenerTag = 'kernel.event_listener', $subscriberTag = 'kernel.event_subscriber')
  54314. {
  54315. $this->dispatcherService = $dispatcherService;
  54316. $this->listenerTag = $listenerTag;
  54317. $this->subscriberTag = $subscriberTag;
  54318. }
  54319. public function setHotPathEvents(array $hotPathEvents, $tagName = 'container.hot_path')
  54320. {
  54321. $this->hotPathEvents = array_flip($hotPathEvents);
  54322. $this->hotPathTagName = $tagName;
  54323. return $this;
  54324. }
  54325. public function process(ContainerBuilder $container)
  54326. {
  54327. if (!$container->hasDefinition($this->dispatcherService) && !$container->hasAlias($this->dispatcherService)) {
  54328. return;
  54329. }
  54330. $definition = $container->findDefinition($this->dispatcherService);
  54331. foreach ($container->findTaggedServiceIds($this->listenerTag, true) as $id => $events) {
  54332. foreach ($events as $event) {
  54333. $priority = isset($event['priority']) ? $event['priority'] : 0;
  54334. if (!isset($event['event'])) {
  54335. throw new InvalidArgumentException(sprintf('Service "%s" must define the "event" attribute on "%s" tags.', $id, $this->listenerTag));
  54336. }
  54337. if (!isset($event['method'])) {
  54338. $event['method'] = 'on'.preg_replace_callback([
  54339. '/(?<=\b)[a-z]/i',
  54340. '/[^a-z0-9]/i',
  54341. ], function ($matches) { return strtoupper($matches[0]); }, $event['event']);
  54342. $event['method'] = preg_replace('/[^a-z0-9]/i', '', $event['method']);
  54343. }
  54344. $definition->addMethodCall('addListener', [$event['event'], [new ServiceClosureArgument(new Reference($id)), $event['method']], $priority]);
  54345. if (isset($this->hotPathEvents[$event['event']])) {
  54346. $container->getDefinition($id)->addTag($this->hotPathTagName);
  54347. }
  54348. }
  54349. }
  54350. $extractingDispatcher = new ExtractingEventDispatcher();
  54351. foreach ($container->findTaggedServiceIds($this->subscriberTag, true) as $id => $attributes) {
  54352. $def = $container->getDefinition($id);
  54353. $class = $def->getClass();
  54354. if (!$r = $container->getReflectionClass($class)) {
  54355. throw new InvalidArgumentException(sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id));
  54356. }
  54357. if (!$r->isSubclassOf(EventSubscriberInterface::class)) {
  54358. throw new InvalidArgumentException(sprintf('Service "%s" must implement interface "%s".', $id, EventSubscriberInterface::class));
  54359. }
  54360. $class = $r->name;
  54361. ExtractingEventDispatcher::$subscriber = $class;
  54362. $extractingDispatcher->addSubscriber($extractingDispatcher);
  54363. foreach ($extractingDispatcher->listeners as $args) {
  54364. $args[1] = [new ServiceClosureArgument(new Reference($id)), $args[1]];
  54365. $definition->addMethodCall('addListener', $args);
  54366. if (isset($this->hotPathEvents[$args[0]])) {
  54367. $container->getDefinition($id)->addTag($this->hotPathTagName);
  54368. }
  54369. }
  54370. $extractingDispatcher->listeners = [];
  54371. }
  54372. }
  54373. }
  54374. class ExtractingEventDispatcher extends EventDispatcher implements EventSubscriberInterface
  54375. {
  54376. public $listeners = [];
  54377. public static $subscriber;
  54378. public function addListener($eventName, $listener, $priority = 0)
  54379. {
  54380. $this->listeners[] = [$eventName, $listener[1], $priority];
  54381. }
  54382. public static function getSubscribedEvents()
  54383. {
  54384. $callback = [self::$subscriber, 'getSubscribedEvents'];
  54385. return $callback();
  54386. }
  54387. }
  54388. <?php
  54389. namespace Symfony\Component\EventDispatcher;
  54390. interface EventDispatcherInterface
  54391. {
  54392. public function dispatch($eventName, Event $event = null);
  54393. public function addListener($eventName, $listener, $priority = 0);
  54394. public function addSubscriber(EventSubscriberInterface $subscriber);
  54395. public function removeListener($eventName, $listener);
  54396. public function removeSubscriber(EventSubscriberInterface $subscriber);
  54397. public function getListeners($eventName = null);
  54398. public function getListenerPriority($eventName, $listener);
  54399. public function hasListeners($eventName = null);
  54400. }
  54401. <?php
  54402. namespace Symfony\Component\EventDispatcher;
  54403. class GenericEvent extends Event implements \ArrayAccess, \IteratorAggregate
  54404. {
  54405. protected $subject;
  54406. protected $arguments;
  54407. public function __construct($subject = null, array $arguments = [])
  54408. {
  54409. $this->subject = $subject;
  54410. $this->arguments = $arguments;
  54411. }
  54412. public function getSubject()
  54413. {
  54414. return $this->subject;
  54415. }
  54416. public function getArgument($key)
  54417. {
  54418. if ($this->hasArgument($key)) {
  54419. return $this->arguments[$key];
  54420. }
  54421. throw new \InvalidArgumentException(sprintf('Argument "%s" not found.', $key));
  54422. }
  54423. public function setArgument($key, $value)
  54424. {
  54425. $this->arguments[$key] = $value;
  54426. return $this;
  54427. }
  54428. public function getArguments()
  54429. {
  54430. return $this->arguments;
  54431. }
  54432. public function setArguments(array $args = [])
  54433. {
  54434. $this->arguments = $args;
  54435. return $this;
  54436. }
  54437. public function hasArgument($key)
  54438. {
  54439. return \array_key_exists($key, $this->arguments);
  54440. }
  54441. public function offsetGet($key)
  54442. {
  54443. return $this->getArgument($key);
  54444. }
  54445. public function offsetSet($key, $value)
  54446. {
  54447. $this->setArgument($key, $value);
  54448. }
  54449. public function offsetUnset($key)
  54450. {
  54451. if ($this->hasArgument($key)) {
  54452. unset($this->arguments[$key]);
  54453. }
  54454. }
  54455. public function offsetExists($key)
  54456. {
  54457. return $this->hasArgument($key);
  54458. }
  54459. public function getIterator()
  54460. {
  54461. return new \ArrayIterator($this->arguments);
  54462. }
  54463. }
  54464. <?php
  54465. namespace Symfony\Component\EventDispatcher;
  54466. /**
  54467. @gmail
  54468. @gmail
  54469. @symfony
  54470. @seld
  54471. @gmail
  54472. @tchwork
  54473. */
  54474. class EventDispatcher implements EventDispatcherInterface
  54475. {
  54476. private $listeners = [];
  54477. private $sorted = [];
  54478. public function dispatch($eventName, Event $event = null)
  54479. {
  54480. if (null === $event) {
  54481. $event = new Event();
  54482. }
  54483. if ($listeners = $this->getListeners($eventName)) {
  54484. $this->doDispatch($listeners, $eventName, $event);
  54485. }
  54486. return $event;
  54487. }
  54488. public function getListeners($eventName = null)
  54489. {
  54490. if (null !== $eventName) {
  54491. if (empty($this->listeners[$eventName])) {
  54492. return [];
  54493. }
  54494. if (!isset($this->sorted[$eventName])) {
  54495. $this->sortListeners($eventName);
  54496. }
  54497. return $this->sorted[$eventName];
  54498. }
  54499. foreach ($this->listeners as $eventName => $eventListeners) {
  54500. if (!isset($this->sorted[$eventName])) {
  54501. $this->sortListeners($eventName);
  54502. }
  54503. }
  54504. return array_filter($this->sorted);
  54505. }
  54506. public function getListenerPriority($eventName, $listener)
  54507. {
  54508. if (empty($this->listeners[$eventName])) {
  54509. return null;
  54510. }
  54511. if (\is_array($listener) && isset($listener[0]) && $listener[0] instanceof \Closure) {
  54512. $listener[0] = $listener[0]();
  54513. }
  54514. foreach ($this->listeners[$eventName] as $priority => $listeners) {
  54515. foreach ($listeners as $k => $v) {
  54516. if ($v !== $listener && \is_array($v) && isset($v[0]) && $v[0] instanceof \Closure) {
  54517. $v[0] = $v[0]();
  54518. $this->listeners[$eventName][$priority][$k] = $v;
  54519. }
  54520. if ($v === $listener) {
  54521. return $priority;
  54522. }
  54523. }
  54524. }
  54525. return null;
  54526. }
  54527. public function hasListeners($eventName = null)
  54528. {
  54529. if (null !== $eventName) {
  54530. return !empty($this->listeners[$eventName]);
  54531. }
  54532. foreach ($this->listeners as $eventListeners) {
  54533. if ($eventListeners) {
  54534. return true;
  54535. }
  54536. }
  54537. return false;
  54538. }
  54539. public function addListener($eventName, $listener, $priority = 0)
  54540. {
  54541. $this->listeners[$eventName][$priority][] = $listener;
  54542. unset($this->sorted[$eventName]);
  54543. }
  54544. public function removeListener($eventName, $listener)
  54545. {
  54546. if (empty($this->listeners[$eventName])) {
  54547. return;
  54548. }
  54549. if (\is_array($listener) && isset($listener[0]) && $listener[0] instanceof \Closure) {
  54550. $listener[0] = $listener[0]();
  54551. }
  54552. foreach ($this->listeners[$eventName] as $priority => $listeners) {
  54553. foreach ($listeners as $k => $v) {
  54554. if ($v !== $listener && \is_array($v) && isset($v[0]) && $v[0] instanceof \Closure) {
  54555. $v[0] = $v[0]();
  54556. }
  54557. if ($v === $listener) {
  54558. unset($listeners[$k], $this->sorted[$eventName]);
  54559. } else {
  54560. $listeners[$k] = $v;
  54561. }
  54562. }
  54563. if ($listeners) {
  54564. $this->listeners[$eventName][$priority] = $listeners;
  54565. } else {
  54566. unset($this->listeners[$eventName][$priority]);
  54567. }
  54568. }
  54569. }
  54570. public function addSubscriber(EventSubscriberInterface $subscriber)
  54571. {
  54572. foreach ($subscriber->getSubscribedEvents() as $eventName => $params) {
  54573. if (\is_string($params)) {
  54574. $this->addListener($eventName, [$subscriber, $params]);
  54575. } elseif (\is_string($params[0])) {
  54576. $this->addListener($eventName, [$subscriber, $params[0]], isset($params[1]) ? $params[1] : 0);
  54577. } else {
  54578. foreach ($params as $listener) {
  54579. $this->addListener($eventName, [$subscriber, $listener[0]], isset($listener[1]) ? $listener[1] : 0);
  54580. }
  54581. }
  54582. }
  54583. }
  54584. public function removeSubscriber(EventSubscriberInterface $subscriber)
  54585. {
  54586. foreach ($subscriber->getSubscribedEvents() as $eventName => $params) {
  54587. if (\is_array($params) && \is_array($params[0])) {
  54588. foreach ($params as $listener) {
  54589. $this->removeListener($eventName, [$subscriber, $listener[0]]);
  54590. }
  54591. } else {
  54592. $this->removeListener($eventName, [$subscriber, \is_string($params) ? $params : $params[0]]);
  54593. }
  54594. }
  54595. }
  54596. protected function doDispatch($listeners, $eventName, Event $event)
  54597. {
  54598. foreach ($listeners as $listener) {
  54599. if ($event->isPropagationStopped()) {
  54600. break;
  54601. }
  54602. \call_user_func($listener, $event, $eventName, $this);
  54603. }
  54604. }
  54605. private function sortListeners($eventName)
  54606. {
  54607. krsort($this->listeners[$eventName]);
  54608. $this->sorted[$eventName] = [];
  54609. foreach ($this->listeners[$eventName] as $priority => $listeners) {
  54610. foreach ($listeners as $k => $listener) {
  54611. if (\is_array($listener) && isset($listener[0]) && $listener[0] instanceof \Closure) {
  54612. $listener[0] = $listener[0]();
  54613. $this->listeners[$eventName][$priority][$k] = $listener;
  54614. }
  54615. $this->sorted[$eventName][] = $listener;
  54616. }
  54617. }
  54618. }
  54619. }
  54620. <?php
  54621. namespace Symfony\Component\EventDispatcher;
  54622. use PHPUnit\Framework\MockObject\MockObject;
  54623. use Symfony\Component\DependencyInjection\ContainerInterface;
  54624. /**
  54625. @gmail
  54626. @gmail
  54627. */
  54628. class ContainerAwareEventDispatcher extends EventDispatcher
  54629. {
  54630. private $container;
  54631. private $listenerIds = [];
  54632. private $listeners = [];
  54633. public function __construct(ContainerInterface $container)
  54634. {
  54635. $this->container = $container;
  54636. $class = static::class;
  54637. if ($this instanceof \PHPUnit_Framework_MockObject_MockObject || $this instanceof MockObject || $this instanceof \Prophecy\Doubler\DoubleInterface) {
  54638. $class = get_parent_class($class);
  54639. }
  54640. if (__CLASS__ !== $class) {
  54641. @trigger_error(sprintf('The %s class is deprecated since Symfony 3.3 and will be removed in 4.0. Use EventDispatcher with closure factories instead.', __CLASS__), E_USER_DEPRECATED);
  54642. }
  54643. }
  54644. public function addListenerService($eventName, $callback, $priority = 0)
  54645. {
  54646. @trigger_error(sprintf('The %s class is deprecated since Symfony 3.3 and will be removed in 4.0. Use EventDispatcher with closure factories instead.', __CLASS__), E_USER_DEPRECATED);
  54647. if (!\is_array($callback) || 2 !== \count($callback)) {
  54648. throw new \InvalidArgumentException('Expected an ["service", "method"] argument.');
  54649. }
  54650. $this->listenerIds[$eventName][] = [$callback[0], $callback[1], $priority];
  54651. }
  54652. public function removeListener($eventName, $listener)
  54653. {
  54654. $this->lazyLoad($eventName);
  54655. if (isset($this->listenerIds[$eventName])) {
  54656. foreach ($this->listenerIds[$eventName] as $i => list($serviceId, $method)) {
  54657. $key = $serviceId.'.'.$method;
  54658. if (isset($this->listeners[$eventName][$key]) && $listener === [$this->listeners[$eventName][$key], $method]) {
  54659. unset($this->listeners[$eventName][$key]);
  54660. if (empty($this->listeners[$eventName])) {
  54661. unset($this->listeners[$eventName]);
  54662. }
  54663. unset($this->listenerIds[$eventName][$i]);
  54664. if (empty($this->listenerIds[$eventName])) {
  54665. unset($this->listenerIds[$eventName]);
  54666. }
  54667. }
  54668. }
  54669. }
  54670. parent::removeListener($eventName, $listener);
  54671. }
  54672. public function hasListeners($eventName = null)
  54673. {
  54674. if (null === $eventName) {
  54675. return $this->listenerIds || $this->listeners || parent::hasListeners();
  54676. }
  54677. if (isset($this->listenerIds[$eventName])) {
  54678. return true;
  54679. }
  54680. return parent::hasListeners($eventName);
  54681. }
  54682. public function getListeners($eventName = null)
  54683. {
  54684. if (null === $eventName) {
  54685. foreach ($this->listenerIds as $serviceEventName => $args) {
  54686. $this->lazyLoad($serviceEventName);
  54687. }
  54688. } else {
  54689. $this->lazyLoad($eventName);
  54690. }
  54691. return parent::getListeners($eventName);
  54692. }
  54693. public function getListenerPriority($eventName, $listener)
  54694. {
  54695. $this->lazyLoad($eventName);
  54696. return parent::getListenerPriority($eventName, $listener);
  54697. }
  54698. public function addSubscriberService($serviceId, $class)
  54699. {
  54700. @trigger_error(sprintf('The %s class is deprecated since Symfony 3.3 and will be removed in 4.0. Use EventDispatcher with closure factories instead.', __CLASS__), E_USER_DEPRECATED);
  54701. foreach ($class::getSubscribedEvents() as $eventName => $params) {
  54702. if (\is_string($params)) {
  54703. $this->listenerIds[$eventName][] = [$serviceId, $params, 0];
  54704. } elseif (\is_string($params[0])) {
  54705. $this->listenerIds[$eventName][] = [$serviceId, $params[0], isset($params[1]) ? $params[1] : 0];
  54706. } else {
  54707. foreach ($params as $listener) {
  54708. $this->listenerIds[$eventName][] = [$serviceId, $listener[0], isset($listener[1]) ? $listener[1] : 0];
  54709. }
  54710. }
  54711. }
  54712. }
  54713. public function getContainer()
  54714. {
  54715. @trigger_error('The '.__METHOD__.'() method is deprecated since Symfony 3.3 as its class will be removed in 4.0. Inject the container or the services you need in your listeners/subscribers instead.', E_USER_DEPRECATED);
  54716. return $this->container;
  54717. }
  54718. protected function lazyLoad($eventName)
  54719. {
  54720. if (isset($this->listenerIds[$eventName])) {
  54721. foreach ($this->listenerIds[$eventName] as list($serviceId, $method, $priority)) {
  54722. $listener = $this->container->get($serviceId);
  54723. $key = $serviceId.'.'.$method;
  54724. if (!isset($this->listeners[$eventName][$key])) {
  54725. $this->addListener($eventName, [$listener, $method], $priority);
  54726. } elseif ($this->listeners[$eventName][$key] !== $listener) {
  54727. parent::removeListener($eventName, [$this->listeners[$eventName][$key], $method]);
  54728. $this->addListener($eventName, [$listener, $method], $priority);
  54729. }
  54730. $this->listeners[$eventName][$key] = $listener;
  54731. }
  54732. }
  54733. }
  54734. }
  54735. <?php
  54736. namespace Symfony\Component\EventDispatcher;
  54737. /**
  54738. @gmail
  54739. @gmail
  54740. */
  54741. class Event
  54742. {
  54743. private $propagationStopped = false;
  54744. public function isPropagationStopped()
  54745. {
  54746. return $this->propagationStopped;
  54747. }
  54748. public function stopPropagation()
  54749. {
  54750. $this->propagationStopped = true;
  54751. }
  54752. }
  54753. <?php
  54754. namespace Symfony\Component\EventDispatcher;
  54755. class ImmutableEventDispatcher implements EventDispatcherInterface
  54756. {
  54757. private $dispatcher;
  54758. public function __construct(EventDispatcherInterface $dispatcher)
  54759. {
  54760. $this->dispatcher = $dispatcher;
  54761. }
  54762. public function dispatch($eventName, Event $event = null)
  54763. {
  54764. return $this->dispatcher->dispatch($eventName, $event);
  54765. }
  54766. public function addListener($eventName, $listener, $priority = 0)
  54767. {
  54768. throw new \BadMethodCallException('Unmodifiable event dispatchers must not be modified.');
  54769. }
  54770. public function addSubscriber(EventSubscriberInterface $subscriber)
  54771. {
  54772. throw new \BadMethodCallException('Unmodifiable event dispatchers must not be modified.');
  54773. }
  54774. public function removeListener($eventName, $listener)
  54775. {
  54776. throw new \BadMethodCallException('Unmodifiable event dispatchers must not be modified.');
  54777. }
  54778. public function removeSubscriber(EventSubscriberInterface $subscriber)
  54779. {
  54780. throw new \BadMethodCallException('Unmodifiable event dispatchers must not be modified.');
  54781. }
  54782. public function getListeners($eventName = null)
  54783. {
  54784. return $this->dispatcher->getListeners($eventName);
  54785. }
  54786. public function getListenerPriority($eventName, $listener)
  54787. {
  54788. return $this->dispatcher->getListenerPriority($eventName, $listener);
  54789. }
  54790. public function hasListeners($eventName = null)
  54791. {
  54792. return $this->dispatcher->hasListeners($eventName);
  54793. }
  54794. }
  54795. <?php
  54796. namespace Symfony\Component\EventDispatcher;
  54797. /**
  54798. @gmail
  54799. @gmail
  54800. */
  54801. interface EventSubscriberInterface
  54802. {
  54803. public static function getSubscribedEvents();
  54804. }
  54805. <?php
  54806. namespace Symfony\Component\Stopwatch;
  54807. class StopwatchPeriod
  54808. {
  54809. private $start;
  54810. private $end;
  54811. private $memory;
  54812. public function __construct($start, $end, $morePrecision = false)
  54813. {
  54814. $this->start = $morePrecision ? (float) $start : (int) $start;
  54815. $this->end = $morePrecision ? (float) $end : (int) $end;
  54816. $this->memory = memory_get_usage(true);
  54817. }
  54818. public function getStartTime()
  54819. {
  54820. return $this->start;
  54821. }
  54822. public function getEndTime()
  54823. {
  54824. return $this->end;
  54825. }
  54826. public function getDuration()
  54827. {
  54828. return $this->end - $this->start;
  54829. }
  54830. public function getMemory()
  54831. {
  54832. return $this->memory;
  54833. }
  54834. }
  54835. <?php
  54836. namespace Symfony\Component\Stopwatch;
  54837. class Stopwatch
  54838. {
  54839. private $morePrecision;
  54840. private $sections;
  54841. private $activeSections;
  54842. public function __construct($morePrecision = false)
  54843. {
  54844. $this->morePrecision = $morePrecision;
  54845. $this->reset();
  54846. }
  54847. public function getSections()
  54848. {
  54849. return $this->sections;
  54850. }
  54851. public function openSection($id = null)
  54852. {
  54853. $current = end($this->activeSections);
  54854. if (null !== $id && null === $current->get($id)) {
  54855. throw new \LogicException(sprintf('The section "%s" has been started at an other level and can not be opened.', $id));
  54856. }
  54857. $this->start('__section__.child', 'section');
  54858. $this->activeSections[] = $current->open($id);
  54859. $this->start('__section__');
  54860. }
  54861. public function stopSection($id)
  54862. {
  54863. $this->stop('__section__');
  54864. if (1 == \count($this->activeSections)) {
  54865. throw new \LogicException('There is no started section to stop.');
  54866. }
  54867. $this->sections[$id] = array_pop($this->activeSections)->setId($id);
  54868. $this->stop('__section__.child');
  54869. }
  54870. public function start($name, $category = null)
  54871. {
  54872. return end($this->activeSections)->startEvent($name, $category);
  54873. }
  54874. public function isStarted($name)
  54875. {
  54876. return end($this->activeSections)->isEventStarted($name);
  54877. }
  54878. public function stop($name)
  54879. {
  54880. return end($this->activeSections)->stopEvent($name);
  54881. }
  54882. public function lap($name)
  54883. {
  54884. return end($this->activeSections)->stopEvent($name)->start();
  54885. }
  54886. public function getEvent($name)
  54887. {
  54888. return end($this->activeSections)->getEvent($name);
  54889. }
  54890. public function getSectionEvents($id)
  54891. {
  54892. return isset($this->sections[$id]) ? $this->sections[$id]->getEvents() : [];
  54893. }
  54894. public function reset()
  54895. {
  54896. $this->sections = $this->activeSections = ['__root__' => new Section(null, $this->morePrecision)];
  54897. }
  54898. }
  54899. <?php
  54900. namespace Symfony\Component\Stopwatch;
  54901. class StopwatchEvent
  54902. {
  54903. private $periods = [];
  54904. private $origin;
  54905. private $category;
  54906. private $morePrecision;
  54907. private $started = [];
  54908. public function __construct($origin, $category = null, $morePrecision = false)
  54909. {
  54910. $this->origin = $this->formatTime($origin);
  54911. $this->category = \is_string($category) ? $category : 'default';
  54912. $this->morePrecision = $morePrecision;
  54913. }
  54914. public function getCategory()
  54915. {
  54916. return $this->category;
  54917. }
  54918. public function getOrigin()
  54919. {
  54920. return $this->origin;
  54921. }
  54922. public function start()
  54923. {
  54924. $this->started[] = $this->getNow();
  54925. return $this;
  54926. }
  54927. public function stop()
  54928. {
  54929. if (!\count($this->started)) {
  54930. throw new \LogicException('stop() called but start() has not been called before.');
  54931. }
  54932. $this->periods[] = new StopwatchPeriod(array_pop($this->started), $this->getNow(), $this->morePrecision);
  54933. return $this;
  54934. }
  54935. public function isStarted()
  54936. {
  54937. return !empty($this->started);
  54938. }
  54939. public function lap()
  54940. {
  54941. return $this->stop()->start();
  54942. }
  54943. public function ensureStopped()
  54944. {
  54945. while (\count($this->started)) {
  54946. $this->stop();
  54947. }
  54948. }
  54949. public function getPeriods()
  54950. {
  54951. return $this->periods;
  54952. }
  54953. public function getStartTime()
  54954. {
  54955. if (isset($this->periods[0])) {
  54956. return $this->periods[0]->getStartTime();
  54957. }
  54958. if ($this->started) {
  54959. return $this->started[0];
  54960. }
  54961. return 0;
  54962. }
  54963. public function getEndTime()
  54964. {
  54965. $count = \count($this->periods);
  54966. return $count ? $this->periods[$count - 1]->getEndTime() : 0;
  54967. }
  54968. public function getDuration()
  54969. {
  54970. $periods = $this->periods;
  54971. $left = \count($this->started);
  54972. for ($i = $left - 1; $i >= 0; --$i) {
  54973. $periods[] = new StopwatchPeriod($this->started[$i], $this->getNow(), $this->morePrecision);
  54974. }
  54975. $total = 0;
  54976. foreach ($periods as $period) {
  54977. $total += $period->getDuration();
  54978. }
  54979. return $total;
  54980. }
  54981. public function getMemory()
  54982. {
  54983. $memory = 0;
  54984. foreach ($this->periods as $period) {
  54985. if ($period->getMemory() > $memory) {
  54986. $memory = $period->getMemory();
  54987. }
  54988. }
  54989. return $memory;
  54990. }
  54991. protected function getNow()
  54992. {
  54993. return $this->formatTime(microtime(true) * 1000 - $this->origin);
  54994. }
  54995. private function formatTime($time)
  54996. {
  54997. if (!is_numeric($time)) {
  54998. throw new \InvalidArgumentException('The time must be a numerical value.');
  54999. }
  55000. return round($time, 1);
  55001. }
  55002. public function __toString()
  55003. {
  55004. return sprintf('%s: %.2F MiB - %d ms', $this->getCategory(), $this->getMemory() / 1024 / 1024, $this->getDuration());
  55005. }
  55006. }
  55007. <?php
  55008. namespace Symfony\Component\Stopwatch;
  55009. class Section
  55010. {
  55011. private $events = [];
  55012. private $origin;
  55013. private $morePrecision;
  55014. private $id;
  55015. private $children = [];
  55016. public function __construct($origin = null, $morePrecision = false)
  55017. {
  55018. $this->origin = is_numeric($origin) ? $origin : null;
  55019. $this->morePrecision = $morePrecision;
  55020. }
  55021. public function get($id)
  55022. {
  55023. foreach ($this->children as $child) {
  55024. if ($id === $child->getId()) {
  55025. return $child;
  55026. }
  55027. }
  55028. return null;
  55029. }
  55030. public function open($id)
  55031. {
  55032. if (null === $session = $this->get($id)) {
  55033. $session = $this->children[] = new self(microtime(true) * 1000, $this->morePrecision);
  55034. }
  55035. return $session;
  55036. }
  55037. public function getId()
  55038. {
  55039. return $this->id;
  55040. }
  55041. public function setId($id)
  55042. {
  55043. $this->id = $id;
  55044. return $this;
  55045. }
  55046. public function startEvent($name, $category)
  55047. {
  55048. if (!isset($this->events[$name])) {
  55049. $this->events[$name] = new StopwatchEvent($this->origin ?: microtime(true) * 1000, $category, $this->morePrecision);
  55050. }
  55051. return $this->events[$name]->start();
  55052. }
  55053. public function isEventStarted($name)
  55054. {
  55055. return isset($this->events[$name]) && $this->events[$name]->isStarted();
  55056. }
  55057. public function stopEvent($name)
  55058. {
  55059. if (!isset($this->events[$name])) {
  55060. throw new \LogicException(sprintf('Event "%s" is not started.', $name));
  55061. }
  55062. return $this->events[$name]->stop();
  55063. }
  55064. public function lap($name)
  55065. {
  55066. return $this->stopEvent($name)->start();
  55067. }
  55068. public function getEvent($name)
  55069. {
  55070. if (!isset($this->events[$name])) {
  55071. throw new \LogicException(sprintf('Event "%s" is not known.', $name));
  55072. }
  55073. return $this->events[$name];
  55074. }
  55075. public function getEvents()
  55076. {
  55077. return $this->events;
  55078. }
  55079. }
  55080. <?php
  55081. require_once __DIR__ . '/composer/autoload_real.php';
  55082. return ComposerAutoloaderInit9f0dd14c94ce02dc34a0e91e293e3b6e::getLoader();
  55083. <?php
  55084. namespace Composer\Autoload;
  55085. class ComposerStaticInit9f0dd14c94ce02dc34a0e91e293e3b6e
  55086. {
  55087. public static $files = array (
  55088. '5255c38a0faeba867671b61dfda6d864' => __DIR__ . '/..' . '/paragonie/random_compat/lib/random.php',
  55089. '320cde22f66dd4f5d3fd621d3e88b98f' => __DIR__ . '/..' . '/symfony/polyfill-ctype/bootstrap.php',
  55090. '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php',
  55091. '023d27dca8066ef29e6739335ea73bad' => __DIR__ . '/..' . '/symfony/polyfill-php70/bootstrap.php',
  55092. '25072dd6e2470089de65ae7bf11d3109' => __DIR__ . '/..' . '/symfony/polyfill-php72/bootstrap.php',
  55093. );
  55094. public static $prefixLengthsPsr4 = array (
  55095. 'S' =>
  55096. array (
  55097. 'Symfony\\Polyfill\\Php72\\' => 23,
  55098. 'Symfony\\Polyfill\\Php70\\' => 23,
  55099. 'Symfony\\Polyfill\\Mbstring\\' => 26,
  55100. 'Symfony\\Polyfill\\Ctype\\' => 23,
  55101. 'Symfony\\Component\\Stopwatch\\' => 28,
  55102. 'Symfony\\Component\\Process\\' => 26,
  55103. 'Symfony\\Component\\OptionsResolver\\' => 34,
  55104. 'Symfony\\Component\\Finder\\' => 25,
  55105. 'Symfony\\Component\\Filesystem\\' => 29,
  55106. 'Symfony\\Component\\EventDispatcher\\' => 34,
  55107. 'Symfony\\Component\\Debug\\' => 24,
  55108. 'Symfony\\Component\\Console\\' => 26,
  55109. ),
  55110. 'P' =>
  55111. array (
  55112. 'Psr\\Log\\' => 8,
  55113. 'PhpCsFixer\\' => 11,
  55114. ),
  55115. 'D' =>
  55116. array (
  55117. 'Doctrine\\Common\\Lexer\\' => 22,
  55118. 'Doctrine\\Common\\Annotations\\' => 28,
  55119. ),
  55120. 'C' =>
  55121. array (
  55122. 'Composer\\XdebugHandler\\' => 23,
  55123. 'Composer\\Semver\\' => 16,
  55124. ),
  55125. );
  55126. public static $prefixDirsPsr4 = array (
  55127. 'Symfony\\Polyfill\\Php72\\' =>
  55128. array (
  55129. 0 => __DIR__ . '/..' . '/symfony/polyfill-php72',
  55130. ),
  55131. 'Symfony\\Polyfill\\Php70\\' =>
  55132. array (
  55133. 0 => __DIR__ . '/..' . '/symfony/polyfill-php70',
  55134. ),
  55135. 'Symfony\\Polyfill\\Mbstring\\' =>
  55136. array (
  55137. 0 => __DIR__ . '/..' . '/symfony/polyfill-mbstring',
  55138. ),
  55139. 'Symfony\\Polyfill\\Ctype\\' =>
  55140. array (
  55141. 0 => __DIR__ . '/..' . '/symfony/polyfill-ctype',
  55142. ),
  55143. 'Symfony\\Component\\Stopwatch\\' =>
  55144. array (
  55145. 0 => __DIR__ . '/..' . '/symfony/stopwatch',
  55146. ),
  55147. 'Symfony\\Component\\Process\\' =>
  55148. array (
  55149. 0 => __DIR__ . '/..' . '/symfony/process',
  55150. ),
  55151. 'Symfony\\Component\\OptionsResolver\\' =>
  55152. array (
  55153. 0 => __DIR__ . '/..' . '/symfony/options-resolver',
  55154. ),
  55155. 'Symfony\\Component\\Finder\\' =>
  55156. array (
  55157. 0 => __DIR__ . '/..' . '/symfony/finder',
  55158. ),
  55159. 'Symfony\\Component\\Filesystem\\' =>
  55160. array (
  55161. 0 => __DIR__ . '/..' . '/symfony/filesystem',
  55162. ),
  55163. 'Symfony\\Component\\EventDispatcher\\' =>
  55164. array (
  55165. 0 => __DIR__ . '/..' . '/symfony/event-dispatcher',
  55166. ),
  55167. 'Symfony\\Component\\Debug\\' =>
  55168. array (
  55169. 0 => __DIR__ . '/..' . '/symfony/debug',
  55170. ),
  55171. 'Symfony\\Component\\Console\\' =>
  55172. array (
  55173. 0 => __DIR__ . '/..' . '/symfony/console',
  55174. ),
  55175. 'Psr\\Log\\' =>
  55176. array (
  55177. 0 => __DIR__ . '/..' . '/psr/log/Psr/Log',
  55178. ),
  55179. 'PhpCsFixer\\' =>
  55180. array (
  55181. 0 => __DIR__ . '/../..' . '/src',
  55182. ),
  55183. 'Doctrine\\Common\\Lexer\\' =>
  55184. array (
  55185. 0 => __DIR__ . '/..' . '/doctrine/lexer/lib/Doctrine/Common/Lexer',
  55186. ),
  55187. 'Doctrine\\Common\\Annotations\\' =>
  55188. array (
  55189. 0 => __DIR__ . '/..' . '/doctrine/annotations/lib/Doctrine/Common/Annotations',
  55190. ),
  55191. 'Composer\\XdebugHandler\\' =>
  55192. array (
  55193. 0 => __DIR__ . '/..' . '/composer/xdebug-handler/src',
  55194. ),
  55195. 'Composer\\Semver\\' =>
  55196. array (
  55197. 0 => __DIR__ . '/..' . '/composer/semver/src',
  55198. ),
  55199. );
  55200. public static $classMap = array (
  55201. 'ArithmeticError' => __DIR__ . '/..' . '/symfony/polyfill-php70/Resources/stubs/ArithmeticError.php',
  55202. 'AssertionError' => __DIR__ . '/..' . '/symfony/polyfill-php70/Resources/stubs/AssertionError.php',
  55203. 'DivisionByZeroError' => __DIR__ . '/..' . '/symfony/polyfill-php70/Resources/stubs/DivisionByZeroError.php',
  55204. 'Error' => __DIR__ . '/..' . '/symfony/polyfill-php70/Resources/stubs/Error.php',
  55205. 'ParseError' => __DIR__ . '/..' . '/symfony/polyfill-php70/Resources/stubs/ParseError.php',
  55206. 'PhpCsFixer\\Diff\\GeckoPackages\\DiffOutputBuilder\\ConfigurationException' => __DIR__ . '/..' . '/php-cs-fixer/diff/src/GeckoPackages/DiffOutputBuilder/ConfigurationException.php',
  55207. 'PhpCsFixer\\Diff\\GeckoPackages\\DiffOutputBuilder\\UnifiedDiffOutputBuilder' => __DIR__ . '/..' . '/php-cs-fixer/diff/src/GeckoPackages/DiffOutputBuilder/UnifiedDiffOutputBuilder.php',
  55208. 'PhpCsFixer\\Diff\\v1_4\\Chunk' => __DIR__ . '/..' . '/php-cs-fixer/diff/src/v1_4/Chunk.php',
  55209. 'PhpCsFixer\\Diff\\v1_4\\Diff' => __DIR__ . '/..' . '/php-cs-fixer/diff/src/v1_4/Diff.php',
  55210. 'PhpCsFixer\\Diff\\v1_4\\Differ' => __DIR__ . '/..' . '/php-cs-fixer/diff/src/v1_4/Differ.php',
  55211. 'PhpCsFixer\\Diff\\v1_4\\LCS\\LongestCommonSubsequence' => __DIR__ . '/..' . '/php-cs-fixer/diff/src/v1_4/LCS/LongestCommonSubsequence.php',
  55212. 'PhpCsFixer\\Diff\\v1_4\\LCS\\MemoryEfficientImplementation' => __DIR__ . '/..' . '/php-cs-fixer/diff/src/v1_4/LCS/MemoryEfficientLongestCommonSubsequenceImplementation.php',
  55213. 'PhpCsFixer\\Diff\\v1_4\\LCS\\TimeEfficientImplementation' => __DIR__ . '/..' . '/php-cs-fixer/diff/src/v1_4/LCS/TimeEfficientLongestCommonSubsequenceImplementation.php',
  55214. 'PhpCsFixer\\Diff\\v1_4\\Line' => __DIR__ . '/..' . '/php-cs-fixer/diff/src/v1_4/Line.php',
  55215. 'PhpCsFixer\\Diff\\v1_4\\Parser' => __DIR__ . '/..' . '/php-cs-fixer/diff/src/v1_4/Parser.php',
  55216. 'PhpCsFixer\\Diff\\v2_0\\Chunk' => __DIR__ . '/..' . '/php-cs-fixer/diff/src/v2_0/Chunk.php',
  55217. 'PhpCsFixer\\Diff\\v2_0\\Diff' => __DIR__ . '/..' . '/php-cs-fixer/diff/src/v2_0/Diff.php',
  55218. 'PhpCsFixer\\Diff\\v2_0\\Differ' => __DIR__ . '/..' . '/php-cs-fixer/diff/src/v2_0/Differ.php',
  55219. 'PhpCsFixer\\Diff\\v2_0\\Exception' => __DIR__ . '/..' . '/php-cs-fixer/diff/src/v2_0/Exception/Exception.php',
  55220. 'PhpCsFixer\\Diff\\v2_0\\InvalidArgumentException' => __DIR__ . '/..' . '/php-cs-fixer/diff/src/v2_0/Exception/InvalidArgumentException.php',
  55221. 'PhpCsFixer\\Diff\\v2_0\\Line' => __DIR__ . '/..' . '/php-cs-fixer/diff/src/v2_0/Line.php',
  55222. 'PhpCsFixer\\Diff\\v2_0\\LongestCommonSubsequenceCalculator' => __DIR__ . '/..' . '/php-cs-fixer/diff/src/v2_0/LongestCommonSubsequenceCalculator.php',
  55223. 'PhpCsFixer\\Diff\\v2_0\\MemoryEfficientLongestCommonSubsequenceCalculator' => __DIR__ . '/..' . '/php-cs-fixer/diff/src/v2_0/MemoryEfficientLongestCommonSubsequenceCalculator.php',
  55224. 'PhpCsFixer\\Diff\\v2_0\\Output\\AbstractChunkOutputBuilder' => __DIR__ . '/..' . '/php-cs-fixer/diff/src/v2_0/Output/AbstractChunkOutputBuilder.php',
  55225. 'PhpCsFixer\\Diff\\v2_0\\Output\\DiffOnlyOutputBuilder' => __DIR__ . '/..' . '/php-cs-fixer/diff/src/v2_0/Output/DiffOnlyOutputBuilder.php',
  55226. 'PhpCsFixer\\Diff\\v2_0\\Output\\DiffOutputBuilderInterface' => __DIR__ . '/..' . '/php-cs-fixer/diff/src/v2_0/Output/DiffOutputBuilderInterface.php',
  55227. 'PhpCsFixer\\Diff\\v2_0\\Output\\UnifiedDiffOutputBuilder' => __DIR__ . '/..' . '/php-cs-fixer/diff/src/v2_0/Output/UnifiedDiffOutputBuilder.php',
  55228. 'PhpCsFixer\\Diff\\v2_0\\Parser' => __DIR__ . '/..' . '/php-cs-fixer/diff/src/v2_0/Parser.php',
  55229. 'PhpCsFixer\\Diff\\v2_0\\TimeEfficientLongestCommonSubsequenceCalculator' => __DIR__ . '/..' . '/php-cs-fixer/diff/src/v2_0/TimeEfficientLongestCommonSubsequenceCalculator.php',
  55230. 'PhpCsFixer\\Diff\\v3_0\\Chunk' => __DIR__ . '/..' . '/php-cs-fixer/diff/src/v3_0/Chunk.php',
  55231. 'PhpCsFixer\\Diff\\v3_0\\ConfigurationException' => __DIR__ . '/..' . '/php-cs-fixer/diff/src/v3_0/Exception/ConfigurationException.php',
  55232. 'PhpCsFixer\\Diff\\v3_0\\Diff' => __DIR__ . '/..' . '/php-cs-fixer/diff/src/v3_0/Diff.php',
  55233. 'PhpCsFixer\\Diff\\v3_0\\Differ' => __DIR__ . '/..' . '/php-cs-fixer/diff/src/v3_0/Differ.php',
  55234. 'PhpCsFixer\\Diff\\v3_0\\Exception' => __DIR__ . '/..' . '/php-cs-fixer/diff/src/v3_0/Exception/Exception.php',
  55235. 'PhpCsFixer\\Diff\\v3_0\\InvalidArgumentException' => __DIR__ . '/..' . '/php-cs-fixer/diff/src/v3_0/Exception/InvalidArgumentException.php',
  55236. 'PhpCsFixer\\Diff\\v3_0\\Line' => __DIR__ . '/..' . '/php-cs-fixer/diff/src/v3_0/Line.php',
  55237. 'PhpCsFixer\\Diff\\v3_0\\LongestCommonSubsequenceCalculator' => __DIR__ . '/..' . '/php-cs-fixer/diff/src/v3_0/LongestCommonSubsequenceCalculator.php',
  55238. 'PhpCsFixer\\Diff\\v3_0\\MemoryEfficientLongestCommonSubsequenceCalculator' => __DIR__ . '/..' . '/php-cs-fixer/diff/src/v3_0/MemoryEfficientLongestCommonSubsequenceCalculator.php',
  55239. 'PhpCsFixer\\Diff\\v3_0\\Output\\AbstractChunkOutputBuilder' => __DIR__ . '/..' . '/php-cs-fixer/diff/src/v3_0/Output/AbstractChunkOutputBuilder.php',
  55240. 'PhpCsFixer\\Diff\\v3_0\\Output\\DiffOnlyOutputBuilder' => __DIR__ . '/..' . '/php-cs-fixer/diff/src/v3_0/Output/DiffOnlyOutputBuilder.php',
  55241. 'PhpCsFixer\\Diff\\v3_0\\Output\\DiffOutputBuilderInterface' => __DIR__ . '/..' . '/php-cs-fixer/diff/src/v3_0/Output/DiffOutputBuilderInterface.php',
  55242. 'PhpCsFixer\\Diff\\v3_0\\Output\\StrictUnifiedDiffOutputBuilder' => __DIR__ . '/..' . '/php-cs-fixer/diff/src/v3_0/Output/StrictUnifiedDiffOutputBuilder.php',
  55243. 'PhpCsFixer\\Diff\\v3_0\\Output\\UnifiedDiffOutputBuilder' => __DIR__ . '/..' . '/php-cs-fixer/diff/src/v3_0/Output/UnifiedDiffOutputBuilder.php',
  55244. 'PhpCsFixer\\Diff\\v3_0\\Parser' => __DIR__ . '/..' . '/php-cs-fixer/diff/src/v3_0/Parser.php',
  55245. 'PhpCsFixer\\Diff\\v3_0\\TimeEfficientLongestCommonSubsequenceCalculator' => __DIR__ . '/..' . '/php-cs-fixer/diff/src/v3_0/TimeEfficientLongestCommonSubsequenceCalculator.php',
  55246. 'PhpCsFixer\\Tests\\TestCase' => __DIR__ . '/../..' . '/tests/TestCase.php',
  55247. 'PhpCsFixer\\Tests\\Test\\AbstractFixerTestCase' => __DIR__ . '/../..' . '/tests/Test/AbstractFixerTestCase.php',
  55248. 'PhpCsFixer\\Tests\\Test\\AbstractIntegrationCaseFactory' => __DIR__ . '/../..' . '/tests/Test/AbstractIntegrationCaseFactory.php',
  55249. 'PhpCsFixer\\Tests\\Test\\AbstractIntegrationTestCase' => __DIR__ . '/../..' . '/tests/Test/AbstractIntegrationTestCase.php',
  55250. 'PhpCsFixer\\Tests\\Test\\Assert\\AssertTokensTrait' => __DIR__ . '/../..' . '/tests/Test/Assert/AssertTokensTrait.php',
  55251. 'PhpCsFixer\\Tests\\Test\\IntegrationCase' => __DIR__ . '/../..' . '/tests/Test/IntegrationCase.php',
  55252. 'PhpCsFixer\\Tests\\Test\\IntegrationCaseFactory' => __DIR__ . '/../..' . '/tests/Test/IntegrationCaseFactory.php',
  55253. 'PhpCsFixer\\Tests\\Test\\IntegrationCaseFactoryInterface' => __DIR__ . '/../..' . '/tests/Test/IntegrationCaseFactoryInterface.php',
  55254. 'PhpCsFixer\\Tests\\Test\\InternalIntegrationCaseFactory' => __DIR__ . '/../..' . '/tests/Test/InternalIntegrationCaseFactory.php',
  55255. 'PhpCsFixer\\Tests\\Test\\IsIdenticalConstraint' => __DIR__ . '/../..' . '/tests/Test/IsIdenticalConstraint.php',
  55256. 'SessionUpdateTimestampHandlerInterface' => __DIR__ . '/..' . '/symfony/polyfill-php70/Resources/stubs/SessionUpdateTimestampHandlerInterface.php',
  55257. 'TypeError' => __DIR__ . '/..' . '/symfony/polyfill-php70/Resources/stubs/TypeError.php',
  55258. );
  55259. public static function getInitializer(ClassLoader $loader)
  55260. {
  55261. return \Closure::bind(function () use ($loader) {
  55262. $loader->prefixLengthsPsr4 = ComposerStaticInit9f0dd14c94ce02dc34a0e91e293e3b6e::$prefixLengthsPsr4;
  55263. $loader->prefixDirsPsr4 = ComposerStaticInit9f0dd14c94ce02dc34a0e91e293e3b6e::$prefixDirsPsr4;
  55264. $loader->classMap = ComposerStaticInit9f0dd14c94ce02dc34a0e91e293e3b6e::$classMap;
  55265. }, null, ClassLoader::class);
  55266. }
  55267. }
  55268. <?php
  55269. namespace Composer\XdebugHandler;
  55270. use Psr\Log\LoggerInterface;
  55271. class XdebugHandler
  55272. {
  55273. const SUFFIX_ALLOW = '_ALLOW_XDEBUG';
  55274. const SUFFIX_INIS = '_ORIGINAL_INIS';
  55275. const RESTART_ID = 'internal';
  55276. const RESTART_SETTINGS = 'XDEBUG_HANDLER_SETTINGS';
  55277. const DEBUG = 'XDEBUG_HANDLER_DEBUG';
  55278. protected $tmpIni;
  55279. private static $inRestart;
  55280. private static $name;
  55281. private static $skipped;
  55282. private $cli;
  55283. private $colorOption;
  55284. private $debug;
  55285. private $envAllowXdebug;
  55286. private $envOriginalInis;
  55287. private $loaded;
  55288. private $persistent;
  55289. private $script;
  55290. private $statusWriter;
  55291. public function __construct($envPrefix, $colorOption = '')
  55292. {
  55293. if (!is_string($envPrefix) || empty($envPrefix) || !is_string($colorOption)) {
  55294. throw new \RuntimeException('Invalid constructor parameter');
  55295. }
  55296. self::$name = strtoupper($envPrefix);
  55297. $this->envAllowXdebug = self::$name.self::SUFFIX_ALLOW;
  55298. $this->envOriginalInis = self::$name.self::SUFFIX_INIS;
  55299. $this->colorOption = $colorOption;
  55300. if (extension_loaded('xdebug')) {
  55301. $ext = new \ReflectionExtension('xdebug');
  55302. $this->loaded = $ext->getVersion() ?: 'unknown';
  55303. }
  55304. if ($this->cli = PHP_SAPI === 'cli') {
  55305. $this->debug = getenv(self::DEBUG);
  55306. }
  55307. $this->statusWriter = new Status($this->envAllowXdebug, (bool) $this->debug);
  55308. }
  55309. public function setLogger(LoggerInterface $logger)
  55310. {
  55311. $this->statusWriter->setLogger($logger);
  55312. return $this;
  55313. }
  55314. public function setMainScript($script)
  55315. {
  55316. $this->script = $script;
  55317. return $this;
  55318. }
  55319. public function setPersistent()
  55320. {
  55321. $this->persistent = true;
  55322. return $this;
  55323. }
  55324. public function check()
  55325. {
  55326. $this->notify(Status::CHECK, $this->loaded);
  55327. $envArgs = explode('|', (string) getenv($this->envAllowXdebug));
  55328. if (empty($envArgs[0]) && $this->requiresRestart((bool) $this->loaded)) {
  55329. $this->notify(Status::RESTART);
  55330. if ($this->prepareRestart()) {
  55331. $command = $this->getCommand();
  55332. $this->notify(Status::RESTARTING, $command);
  55333. $this->restart($command);
  55334. }
  55335. return;
  55336. }
  55337. if (self::RESTART_ID === $envArgs[0] && count($envArgs) === 5) {
  55338. $this->notify(Status::RESTARTED);
  55339. Process::setEnv($this->envAllowXdebug);
  55340. self::$inRestart = true;
  55341. if (!$this->loaded) {
  55342. self::$skipped = $envArgs[1];
  55343. }
  55344. $this->setEnvRestartSettings($envArgs);
  55345. return;
  55346. }
  55347. $this->notify(Status::NORESTART);
  55348. if ($settings = self::getRestartSettings()) {
  55349. $this->syncSettings($settings);
  55350. }
  55351. }
  55352. public static function getAllIniFiles()
  55353. {
  55354. if (!empty(self::$name)) {
  55355. $env = getenv(self::$name.self::SUFFIX_INIS);
  55356. if (false !== $env) {
  55357. return explode(PATH_SEPARATOR, $env);
  55358. }
  55359. }
  55360. $paths = array((string) php_ini_loaded_file());
  55361. if ($scanned = php_ini_scanned_files()) {
  55362. $paths = array_merge($paths, array_map('trim', explode(',', $scanned)));
  55363. }
  55364. return $paths;
  55365. }
  55366. public static function getRestartSettings()
  55367. {
  55368. $envArgs = explode('|', (string) getenv(self::RESTART_SETTINGS));
  55369. if (count($envArgs) !== 6
  55370. || (!self::$inRestart && php_ini_loaded_file() !== $envArgs[0])) {
  55371. return;
  55372. }
  55373. return array(
  55374. 'tmpIni' => $envArgs[0],
  55375. 'scannedInis' => (bool) $envArgs[1],
  55376. 'scanDir' => '*' === $envArgs[2] ? false : $envArgs[2],
  55377. 'phprc' => '*' === $envArgs[3] ? false : $envArgs[3],
  55378. 'inis' => explode(PATH_SEPARATOR, $envArgs[4]),
  55379. 'skipped' => $envArgs[5],
  55380. );
  55381. }
  55382. public static function getSkippedVersion()
  55383. {
  55384. return (string) self::$skipped;
  55385. }
  55386. protected function requiresRestart($isLoaded)
  55387. {
  55388. return $isLoaded;
  55389. }
  55390. protected function restart($command)
  55391. {
  55392. $this->doRestart($command);
  55393. }
  55394. private function doRestart($command)
  55395. {
  55396. if (function_exists('pcntl_async_signals') && function_exists('pcntl_signal')) {
  55397. pcntl_async_signals(true);
  55398. pcntl_signal(SIGINT, SIG_IGN);
  55399. }
  55400. passthru($command, $exitCode);
  55401. $this->notify(Status::INFO, 'Restarted process exited '.$exitCode);
  55402. if ($this->debug === '2') {
  55403. $this->notify(Status::INFO, 'Temp ini saved: '.$this->tmpIni);
  55404. } else {
  55405. @unlink($this->tmpIni);
  55406. }
  55407. exit($exitCode);
  55408. }
  55409. private function prepareRestart()
  55410. {
  55411. $error = '';
  55412. $iniFiles = self::getAllIniFiles();
  55413. $scannedInis = count($iniFiles) > 1;
  55414. $tmpDir = sys_get_temp_dir();
  55415. if (!$this->cli) {
  55416. $error = 'Unsupported SAPI: '.PHP_SAPI;
  55417. } elseif (!defined('PHP_BINARY')) {
  55418. $error = 'PHP version is too old: '.PHP_VERSION;
  55419. } elseif (!$this->checkConfiguration($info)) {
  55420. $error = $info;
  55421. } elseif (!$this->checkScanDirConfig()) {
  55422. $error = 'PHP version does not report scanned inis: '.PHP_VERSION;
  55423. } elseif (!$this->checkMainScript()) {
  55424. $error = 'Unable to access main script: '.$this->script;
  55425. } elseif (!$this->writeTmpIni($iniFiles, $tmpDir, $error)) {
  55426. $error = $error ?: 'Unable to create temp ini file at: '.$tmpDir;
  55427. } elseif (!$this->setEnvironment($scannedInis, $iniFiles)) {
  55428. $error = 'Unable to set environment variables';
  55429. }
  55430. if ($error) {
  55431. $this->notify(Status::ERROR, $error);
  55432. }
  55433. return empty($error);
  55434. }
  55435. private function writeTmpIni(array $iniFiles, $tmpDir, &$error)
  55436. {
  55437. if (!$this->tmpIni = @tempnam($tmpDir, '')) {
  55438. return false;
  55439. }
  55440. if (empty($iniFiles[0])) {
  55441. array_shift($iniFiles);
  55442. }
  55443. $content = '';
  55444. $regex = '/^\s*(zend_extension\s*=.*xdebug.*)$/mi';
  55445. foreach ($iniFiles as $file) {
  55446. if (($data = @file_get_contents($file)) === false) {
  55447. $error = 'Unable to read ini: '.$file;
  55448. return false;
  55449. }
  55450. $content .= preg_replace($regex, ';$1', $data).PHP_EOL;
  55451. }
  55452. if ($config = parse_ini_string($content)) {
  55453. $loaded = ini_get_all(null, false);
  55454. $content .= $this->mergeLoadedConfig($loaded, $config);
  55455. }
  55456. $content .= 'opcache.enable_cli=0'.PHP_EOL;
  55457. return @file_put_contents($this->tmpIni, $content);
  55458. }
  55459. private function getCommand()
  55460. {
  55461. $php = array(PHP_BINARY);
  55462. $args = array_slice($_SERVER['argv'], 1);
  55463. if (!$this->persistent) {
  55464. array_push($php, '-n', '-c', $this->tmpIni);
  55465. }
  55466. if (defined('STDOUT') && Process::supportsColor(STDOUT)) {
  55467. $args = Process::addColorOption($args, $this->colorOption);
  55468. }
  55469. $args = array_merge($php, array($this->script), $args);
  55470. $cmd = Process::escape(array_shift($args), true, true);
  55471. foreach ($args as $arg) {
  55472. $cmd .= ' '.Process::escape($arg);
  55473. }
  55474. return $cmd;
  55475. }
  55476. private function setEnvironment($scannedInis, array $iniFiles)
  55477. {
  55478. $scanDir = getenv('PHP_INI_SCAN_DIR');
  55479. $phprc = getenv('PHPRC');
  55480. if (!putenv($this->envOriginalInis.'='.implode(PATH_SEPARATOR, $iniFiles))) {
  55481. return false;
  55482. }
  55483. if ($this->persistent) {
  55484. if (!putenv('PHP_INI_SCAN_DIR=') || !putenv('PHPRC='.$this->tmpIni)) {
  55485. return false;
  55486. }
  55487. }
  55488. $envArgs = array(
  55489. self::RESTART_ID,
  55490. $this->loaded,
  55491. (int) $scannedInis,
  55492. false === $scanDir ? '*' : $scanDir,
  55493. false === $phprc ? '*' : $phprc,
  55494. );
  55495. return putenv($this->envAllowXdebug.'='.implode('|', $envArgs));
  55496. }
  55497. private function notify($op, $data = null)
  55498. {
  55499. $this->statusWriter->report($op, $data);
  55500. }
  55501. private function mergeLoadedConfig(array $loadedConfig, array $iniConfig)
  55502. {
  55503. $content = '';
  55504. foreach ($loadedConfig as $name => $value) {
  55505. if (!is_string($value)
  55506. || strpos($name, 'xdebug') === 0
  55507. || $name === 'apc.mmap_file_mask') {
  55508. continue;
  55509. }
  55510. if (!isset($iniConfig[$name]) || $iniConfig[$name] !== $value) {
  55511. $content .= $name.'="'.addcslashes($value, '\\"').'"'.PHP_EOL;
  55512. }
  55513. }
  55514. return $content;
  55515. }
  55516. private function checkMainScript()
  55517. {
  55518. if (null !== $this->script) {
  55519. return file_exists($this->script) || '--' === $this->script;
  55520. }
  55521. if (file_exists($this->script = $_SERVER['argv'][0])) {
  55522. return true;
  55523. }
  55524. $options = PHP_VERSION_ID >= 50306 ? DEBUG_BACKTRACE_IGNORE_ARGS : false;
  55525. $trace = debug_backtrace($options);
  55526. if (($main = end($trace)) && isset($main['file'])) {
  55527. return file_exists($this->script = $main['file']);
  55528. }
  55529. return false;
  55530. }
  55531. private function setEnvRestartSettings($envArgs)
  55532. {
  55533. $settings = array(
  55534. php_ini_loaded_file(),
  55535. $envArgs[2],
  55536. $envArgs[3],
  55537. $envArgs[4],
  55538. getenv($this->envOriginalInis),
  55539. self::$skipped,
  55540. );
  55541. Process::setEnv(self::RESTART_SETTINGS, implode('|', $settings));
  55542. }
  55543. private function syncSettings(array $settings)
  55544. {
  55545. if (false === getenv($this->envOriginalInis)) {
  55546. Process::setEnv($this->envOriginalInis, implode(PATH_SEPARATOR, $settings['inis']));
  55547. }
  55548. self::$skipped = $settings['skipped'];
  55549. $this->notify(Status::INFO, 'Process called with existing restart settings');
  55550. }
  55551. private function checkScanDirConfig()
  55552. {
  55553. return !(getenv('PHP_INI_SCAN_DIR')
  55554. && !PHP_CONFIG_FILE_SCAN_DIR
  55555. && (PHP_VERSION_ID < 70113
  55556. || PHP_VERSION_ID === 70200));
  55557. }
  55558. private function checkConfiguration(&$info)
  55559. {
  55560. if (false !== strpos(ini_get('disable_functions'), 'passthru')) {
  55561. $info = 'passthru function is disabled';
  55562. return false;
  55563. }
  55564. if (extension_loaded('uopz') && !ini_get('uopz.disable')) {
  55565. if (function_exists('uopz_allow_exit')) {
  55566. @uopz_allow_exit(true);
  55567. } else {
  55568. $info = 'uopz extension is not compatible';
  55569. return false;
  55570. }
  55571. }
  55572. return true;
  55573. }
  55574. }
  55575. <?php
  55576. namespace Composer\XdebugHandler;
  55577. class PhpConfig
  55578. {
  55579. public function useOriginal()
  55580. {
  55581. $this->getDataAndReset();
  55582. return array();
  55583. }
  55584. public function useStandard()
  55585. {
  55586. if ($data = $this->getDataAndReset()) {
  55587. return array('-n', '-c', $data['tmpIni']);
  55588. }
  55589. return array();
  55590. }
  55591. public function usePersistent()
  55592. {
  55593. if ($data = $this->getDataAndReset()) {
  55594. Process::setEnv('PHPRC', $data['tmpIni']);
  55595. Process::setEnv('PHP_INI_SCAN_DIR', '');
  55596. }
  55597. return array();
  55598. }
  55599. private function getDataAndReset()
  55600. {
  55601. if ($data = XdebugHandler::getRestartSettings()) {
  55602. Process::setEnv('PHPRC', $data['phprc']);
  55603. Process::setEnv('PHP_INI_SCAN_DIR', $data['scanDir']);
  55604. }
  55605. return $data;
  55606. }
  55607. }
  55608. <?php
  55609. namespace Composer\XdebugHandler;
  55610. use Psr\Log\LoggerInterface;
  55611. use Psr\Log\LogLevel;
  55612. class Status
  55613. {
  55614. const ENV_RESTART = 'XDEBUG_HANDLER_RESTART';
  55615. const CHECK = 'Check';
  55616. const ERROR = 'Error';
  55617. const INFO = 'Info';
  55618. const NORESTART = 'NoRestart';
  55619. const RESTART = 'Restart';
  55620. const RESTARTING = 'Restarting';
  55621. const RESTARTED = 'Restarted';
  55622. private $debug;
  55623. private $envAllowXdebug;
  55624. private $loaded;
  55625. private $logger;
  55626. private $time;
  55627. public function __construct($envAllowXdebug, $debug)
  55628. {
  55629. $start = getenv(self::ENV_RESTART);
  55630. Process::setEnv(self::ENV_RESTART);
  55631. $this->time = $start ? round((microtime(true) - $start) * 1000) : 0;
  55632. $this->envAllowXdebug = $envAllowXdebug;
  55633. $this->debug = $debug && defined('STDERR');
  55634. }
  55635. public function setLogger(LoggerInterface $logger)
  55636. {
  55637. $this->logger = $logger;
  55638. }
  55639. public function report($op, $data)
  55640. {
  55641. if ($this->logger || $this->debug) {
  55642. call_user_func(array($this, 'report'.$op), $data);
  55643. }
  55644. }
  55645. private function output($text, $level = null)
  55646. {
  55647. if ($this->logger) {
  55648. $this->logger->log($level ?: LogLevel::DEBUG, $text);
  55649. }
  55650. if ($this->debug) {
  55651. fwrite(STDERR, sprintf('xdebug-handler[%d] %s', getmypid(), $text.PHP_EOL));
  55652. }
  55653. }
  55654. private function reportCheck($loaded)
  55655. {
  55656. $this->loaded = $loaded;
  55657. $this->output('Checking '.$this->envAllowXdebug);
  55658. }
  55659. private function reportError($error)
  55660. {
  55661. $this->output(sprintf('No restart (%s)', $error), LogLevel::WARNING);
  55662. }
  55663. private function reportInfo($info)
  55664. {
  55665. $this->output($info);
  55666. }
  55667. private function reportNoRestart()
  55668. {
  55669. $this->output($this->getLoadedMessage());
  55670. if ($this->loaded) {
  55671. $text = sprintf('No restart (%s)', $this->getEnvAllow());
  55672. if (!getenv($this->envAllowXdebug)) {
  55673. $text .= ' Allowed by application';
  55674. }
  55675. $this->output($text);
  55676. }
  55677. }
  55678. private function reportRestart()
  55679. {
  55680. $this->output($this->getLoadedMessage());
  55681. Process::setEnv(self::ENV_RESTART, (string) microtime(true));
  55682. }
  55683. private function reportRestarted()
  55684. {
  55685. $loaded = $this->getLoadedMessage();
  55686. $text = sprintf('Restarted (%d ms). %s', $this->time, $loaded);
  55687. $level = $this->loaded ? LogLevel::WARNING : null;
  55688. $this->output($text, $level);
  55689. }
  55690. private function reportRestarting($command)
  55691. {
  55692. $text = sprintf('Process restarting (%s)', $this->getEnvAllow());
  55693. $this->output($text);
  55694. $text = 'Running '.$command;
  55695. $this->output($text);
  55696. }
  55697. private function getEnvAllow()
  55698. {
  55699. return $this->envAllowXdebug.'='.getenv($this->envAllowXdebug);
  55700. }
  55701. private function getLoadedMessage()
  55702. {
  55703. $loaded = $this->loaded ? sprintf('loaded (%s)', $this->loaded) : 'not loaded';
  55704. return 'The Xdebug extension is '.$loaded;
  55705. }
  55706. }
  55707. <?php
  55708. namespace Composer\XdebugHandler;
  55709. class Process
  55710. {
  55711. public static function addColorOption(array $args, $colorOption)
  55712. {
  55713. if (!$colorOption
  55714. || in_array($colorOption, $args)
  55715. || !preg_match('/^--([a-z]+$)|(^--[a-z]+=)/', $colorOption, $matches)) {
  55716. return $args;
  55717. }
  55718. if (isset($matches[2])) {
  55719. if (false !== ($index = array_search($matches[2].'auto', $args))) {
  55720. $args[$index] = $colorOption;
  55721. return $args;
  55722. } elseif (preg_grep('/^'.$matches[2].'/', $args)) {
  55723. return $args;
  55724. }
  55725. } elseif (in_array('--no-'.$matches[1], $args)) {
  55726. return $args;
  55727. }
  55728. if (false !== getenv('NO_COLOR')) {
  55729. return $args;
  55730. }
  55731. if (false !== ($index = array_search('--', $args))) {
  55732. array_splice($args, $index, 0, $colorOption);
  55733. } else {
  55734. $args[] = $colorOption;
  55735. }
  55736. return $args;
  55737. }
  55738. /**
  55739. @blueyonder
  55740. */
  55741. public static function escape($arg, $meta = true, $module = false)
  55742. {
  55743. if (!defined('PHP_WINDOWS_VERSION_BUILD')) {
  55744. return "'".str_replace("'", "'\\''", $arg)."'";
  55745. }
  55746. $quote = strpbrk($arg, " \t") !== false || $arg === '';
  55747. $arg = preg_replace('/(\\\\*)"/', '$1$1\\"', $arg, -1, $dquotes);
  55748. if ($meta) {
  55749. $meta = $dquotes || preg_match('/%[^%]+%/', $arg);
  55750. if (!$meta) {
  55751. $quote = $quote || strpbrk($arg, '^&|<>()') !== false;
  55752. } elseif ($module && !$dquotes && $quote) {
  55753. $meta = false;
  55754. }
  55755. }
  55756. if ($quote) {
  55757. $arg = '"'.preg_replace('/(\\\\*)$/', '$1$1', $arg).'"';
  55758. }
  55759. if ($meta) {
  55760. $arg = preg_replace('/(["^&|<>()%])/', '^$1', $arg);
  55761. }
  55762. return $arg;
  55763. }
  55764. public static function supportsColor($output)
  55765. {
  55766. if ('Hyper' === getenv('TERM_PROGRAM')) {
  55767. return true;
  55768. }
  55769. if (defined('PHP_WINDOWS_VERSION_BUILD')) {
  55770. return (function_exists('sapi_windows_vt100_support')
  55771. && sapi_windows_vt100_support($output))
  55772. || false !== getenv('ANSICON')
  55773. || 'ON' === getenv('ConEmuANSI')
  55774. || 'xterm' === getenv('TERM');
  55775. }
  55776. if (function_exists('stream_isatty')) {
  55777. return stream_isatty($output);
  55778. }
  55779. if (function_exists('posix_isatty')) {
  55780. return posix_isatty($output);
  55781. }
  55782. $stat = fstat($output);
  55783. return $stat ? 0020000 === ($stat['mode'] & 0170000) : false;
  55784. }
  55785. public static function setEnv($name, $value = false)
  55786. {
  55787. $unset = false === $value;
  55788. if (!putenv($unset ? $name : $name.'='.$value)) {
  55789. return false;
  55790. }
  55791. if ($unset) {
  55792. unset($_SERVER[$name]);
  55793. } else {
  55794. $_SERVER[$name] = $value;
  55795. }
  55796. if (false !== stripos((string) ini_get('variables_order'), 'E')) {
  55797. if ($unset) {
  55798. unset($_ENV[$name]);
  55799. } else {
  55800. $_ENV[$name] = $value;
  55801. }
  55802. }
  55803. return true;
  55804. }
  55805. }
  55806. <?php
  55807. class ComposerAutoloaderInit9f0dd14c94ce02dc34a0e91e293e3b6e
  55808. {
  55809. private static $loader;
  55810. public static function loadClassLoader($class)
  55811. {
  55812. if ('Composer\Autoload\ClassLoader' === $class) {
  55813. require __DIR__ . '/ClassLoader.php';
  55814. }
  55815. }
  55816. public static function getLoader()
  55817. {
  55818. if (null !== self::$loader) {
  55819. return self::$loader;
  55820. }
  55821. spl_autoload_register(array('ComposerAutoloaderInit9f0dd14c94ce02dc34a0e91e293e3b6e', 'loadClassLoader'), true, true);
  55822. self::$loader = $loader = new \Composer\Autoload\ClassLoader();
  55823. spl_autoload_unregister(array('ComposerAutoloaderInit9f0dd14c94ce02dc34a0e91e293e3b6e', 'loadClassLoader'));
  55824. $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
  55825. if ($useStaticLoader) {
  55826. require_once __DIR__ . '/autoload_static.php';
  55827. call_user_func(\Composer\Autoload\ComposerStaticInit9f0dd14c94ce02dc34a0e91e293e3b6e::getInitializer($loader));
  55828. } else {
  55829. $map = require __DIR__ . '/autoload_namespaces.php';
  55830. foreach ($map as $namespace => $path) {
  55831. $loader->set($namespace, $path);
  55832. }
  55833. $map = require __DIR__ . '/autoload_psr4.php';
  55834. foreach ($map as $namespace => $path) {
  55835. $loader->setPsr4($namespace, $path);
  55836. }
  55837. $classMap = require __DIR__ . '/autoload_classmap.php';
  55838. if ($classMap) {
  55839. $loader->addClassMap($classMap);
  55840. }
  55841. }
  55842. $loader->register(true);
  55843. if ($useStaticLoader) {
  55844. $includeFiles = Composer\Autoload\ComposerStaticInit9f0dd14c94ce02dc34a0e91e293e3b6e::$files;
  55845. } else {
  55846. $includeFiles = require __DIR__ . '/autoload_files.php';
  55847. }
  55848. foreach ($includeFiles as $fileIdentifier => $file) {
  55849. composerRequire9f0dd14c94ce02dc34a0e91e293e3b6e($fileIdentifier, $file);
  55850. }
  55851. return $loader;
  55852. }
  55853. }
  55854. function composerRequire9f0dd14c94ce02dc34a0e91e293e3b6e($fileIdentifier, $file)
  55855. {
  55856. if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
  55857. require $file;
  55858. $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
  55859. }
  55860. }
  55861. <?php
  55862. $vendorDir = dirname(dirname(__FILE__));
  55863. $baseDir = dirname($vendorDir);
  55864. return array(
  55865. '5255c38a0faeba867671b61dfda6d864' => $vendorDir . '/paragonie/random_compat/lib/random.php',
  55866. '320cde22f66dd4f5d3fd621d3e88b98f' => $vendorDir . '/symfony/polyfill-ctype/bootstrap.php',
  55867. '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php',
  55868. '023d27dca8066ef29e6739335ea73bad' => $vendorDir . '/symfony/polyfill-php70/bootstrap.php',
  55869. '25072dd6e2470089de65ae7bf11d3109' => $vendorDir . '/symfony/polyfill-php72/bootstrap.php',
  55870. );
  55871. <?php
  55872. $vendorDir = dirname(dirname(__FILE__));
  55873. $baseDir = dirname($vendorDir);
  55874. return array(
  55875. 'Symfony\\Polyfill\\Php72\\' => array($vendorDir . '/symfony/polyfill-php72'),
  55876. 'Symfony\\Polyfill\\Php70\\' => array($vendorDir . '/symfony/polyfill-php70'),
  55877. 'Symfony\\Polyfill\\Mbstring\\' => array($vendorDir . '/symfony/polyfill-mbstring'),
  55878. 'Symfony\\Polyfill\\Ctype\\' => array($vendorDir . '/symfony/polyfill-ctype'),
  55879. 'Symfony\\Component\\Stopwatch\\' => array($vendorDir . '/symfony/stopwatch'),
  55880. 'Symfony\\Component\\Process\\' => array($vendorDir . '/symfony/process'),
  55881. 'Symfony\\Component\\OptionsResolver\\' => array($vendorDir . '/symfony/options-resolver'),
  55882. 'Symfony\\Component\\Finder\\' => array($vendorDir . '/symfony/finder'),
  55883. 'Symfony\\Component\\Filesystem\\' => array($vendorDir . '/symfony/filesystem'),
  55884. 'Symfony\\Component\\EventDispatcher\\' => array($vendorDir . '/symfony/event-dispatcher'),
  55885. 'Symfony\\Component\\Debug\\' => array($vendorDir . '/symfony/debug'),
  55886. 'Symfony\\Component\\Console\\' => array($vendorDir . '/symfony/console'),
  55887. 'Psr\\Log\\' => array($vendorDir . '/psr/log/Psr/Log'),
  55888. 'PhpCsFixer\\' => array($baseDir . '/src'),
  55889. 'Doctrine\\Common\\Lexer\\' => array($vendorDir . '/doctrine/lexer/lib/Doctrine/Common/Lexer'),
  55890. 'Doctrine\\Common\\Annotations\\' => array($vendorDir . '/doctrine/annotations/lib/Doctrine/Common/Annotations'),
  55891. 'Composer\\XdebugHandler\\' => array($vendorDir . '/composer/xdebug-handler/src'),
  55892. 'Composer\\Semver\\' => array($vendorDir . '/composer/semver/src'),
  55893. );
  55894. <?php
  55895. $vendorDir = dirname(dirname(__FILE__));
  55896. $baseDir = dirname($vendorDir);
  55897. return array(
  55898. 'ArithmeticError' => $vendorDir . '/symfony/polyfill-php70/Resources/stubs/ArithmeticError.php',
  55899. 'AssertionError' => $vendorDir . '/symfony/polyfill-php70/Resources/stubs/AssertionError.php',
  55900. 'DivisionByZeroError' => $vendorDir . '/symfony/polyfill-php70/Resources/stubs/DivisionByZeroError.php',
  55901. 'Error' => $vendorDir . '/symfony/polyfill-php70/Resources/stubs/Error.php',
  55902. 'ParseError' => $vendorDir . '/symfony/polyfill-php70/Resources/stubs/ParseError.php',
  55903. 'PhpCsFixer\\Diff\\GeckoPackages\\DiffOutputBuilder\\ConfigurationException' => $vendorDir . '/php-cs-fixer/diff/src/GeckoPackages/DiffOutputBuilder/ConfigurationException.php',
  55904. 'PhpCsFixer\\Diff\\GeckoPackages\\DiffOutputBuilder\\UnifiedDiffOutputBuilder' => $vendorDir . '/php-cs-fixer/diff/src/GeckoPackages/DiffOutputBuilder/UnifiedDiffOutputBuilder.php',
  55905. 'PhpCsFixer\\Diff\\v1_4\\Chunk' => $vendorDir . '/php-cs-fixer/diff/src/v1_4/Chunk.php',
  55906. 'PhpCsFixer\\Diff\\v1_4\\Diff' => $vendorDir . '/php-cs-fixer/diff/src/v1_4/Diff.php',
  55907. 'PhpCsFixer\\Diff\\v1_4\\Differ' => $vendorDir . '/php-cs-fixer/diff/src/v1_4/Differ.php',
  55908. 'PhpCsFixer\\Diff\\v1_4\\LCS\\LongestCommonSubsequence' => $vendorDir . '/php-cs-fixer/diff/src/v1_4/LCS/LongestCommonSubsequence.php',
  55909. 'PhpCsFixer\\Diff\\v1_4\\LCS\\MemoryEfficientImplementation' => $vendorDir . '/php-cs-fixer/diff/src/v1_4/LCS/MemoryEfficientLongestCommonSubsequenceImplementation.php',
  55910. 'PhpCsFixer\\Diff\\v1_4\\LCS\\TimeEfficientImplementation' => $vendorDir . '/php-cs-fixer/diff/src/v1_4/LCS/TimeEfficientLongestCommonSubsequenceImplementation.php',
  55911. 'PhpCsFixer\\Diff\\v1_4\\Line' => $vendorDir . '/php-cs-fixer/diff/src/v1_4/Line.php',
  55912. 'PhpCsFixer\\Diff\\v1_4\\Parser' => $vendorDir . '/php-cs-fixer/diff/src/v1_4/Parser.php',
  55913. 'PhpCsFixer\\Diff\\v2_0\\Chunk' => $vendorDir . '/php-cs-fixer/diff/src/v2_0/Chunk.php',
  55914. 'PhpCsFixer\\Diff\\v2_0\\Diff' => $vendorDir . '/php-cs-fixer/diff/src/v2_0/Diff.php',
  55915. 'PhpCsFixer\\Diff\\v2_0\\Differ' => $vendorDir . '/php-cs-fixer/diff/src/v2_0/Differ.php',
  55916. 'PhpCsFixer\\Diff\\v2_0\\Exception' => $vendorDir . '/php-cs-fixer/diff/src/v2_0/Exception/Exception.php',
  55917. 'PhpCsFixer\\Diff\\v2_0\\InvalidArgumentException' => $vendorDir . '/php-cs-fixer/diff/src/v2_0/Exception/InvalidArgumentException.php',
  55918. 'PhpCsFixer\\Diff\\v2_0\\Line' => $vendorDir . '/php-cs-fixer/diff/src/v2_0/Line.php',
  55919. 'PhpCsFixer\\Diff\\v2_0\\LongestCommonSubsequenceCalculator' => $vendorDir . '/php-cs-fixer/diff/src/v2_0/LongestCommonSubsequenceCalculator.php',
  55920. 'PhpCsFixer\\Diff\\v2_0\\MemoryEfficientLongestCommonSubsequenceCalculator' => $vendorDir . '/php-cs-fixer/diff/src/v2_0/MemoryEfficientLongestCommonSubsequenceCalculator.php',
  55921. 'PhpCsFixer\\Diff\\v2_0\\Output\\AbstractChunkOutputBuilder' => $vendorDir . '/php-cs-fixer/diff/src/v2_0/Output/AbstractChunkOutputBuilder.php',
  55922. 'PhpCsFixer\\Diff\\v2_0\\Output\\DiffOnlyOutputBuilder' => $vendorDir . '/php-cs-fixer/diff/src/v2_0/Output/DiffOnlyOutputBuilder.php',
  55923. 'PhpCsFixer\\Diff\\v2_0\\Output\\DiffOutputBuilderInterface' => $vendorDir . '/php-cs-fixer/diff/src/v2_0/Output/DiffOutputBuilderInterface.php',
  55924. 'PhpCsFixer\\Diff\\v2_0\\Output\\UnifiedDiffOutputBuilder' => $vendorDir . '/php-cs-fixer/diff/src/v2_0/Output/UnifiedDiffOutputBuilder.php',
  55925. 'PhpCsFixer\\Diff\\v2_0\\Parser' => $vendorDir . '/php-cs-fixer/diff/src/v2_0/Parser.php',
  55926. 'PhpCsFixer\\Diff\\v2_0\\TimeEfficientLongestCommonSubsequenceCalculator' => $vendorDir . '/php-cs-fixer/diff/src/v2_0/TimeEfficientLongestCommonSubsequenceCalculator.php',
  55927. 'PhpCsFixer\\Diff\\v3_0\\Chunk' => $vendorDir . '/php-cs-fixer/diff/src/v3_0/Chunk.php',
  55928. 'PhpCsFixer\\Diff\\v3_0\\ConfigurationException' => $vendorDir . '/php-cs-fixer/diff/src/v3_0/Exception/ConfigurationException.php',
  55929. 'PhpCsFixer\\Diff\\v3_0\\Diff' => $vendorDir . '/php-cs-fixer/diff/src/v3_0/Diff.php',
  55930. 'PhpCsFixer\\Diff\\v3_0\\Differ' => $vendorDir . '/php-cs-fixer/diff/src/v3_0/Differ.php',
  55931. 'PhpCsFixer\\Diff\\v3_0\\Exception' => $vendorDir . '/php-cs-fixer/diff/src/v3_0/Exception/Exception.php',
  55932. 'PhpCsFixer\\Diff\\v3_0\\InvalidArgumentException' => $vendorDir . '/php-cs-fixer/diff/src/v3_0/Exception/InvalidArgumentException.php',
  55933. 'PhpCsFixer\\Diff\\v3_0\\Line' => $vendorDir . '/php-cs-fixer/diff/src/v3_0/Line.php',
  55934. 'PhpCsFixer\\Diff\\v3_0\\LongestCommonSubsequenceCalculator' => $vendorDir . '/php-cs-fixer/diff/src/v3_0/LongestCommonSubsequenceCalculator.php',
  55935. 'PhpCsFixer\\Diff\\v3_0\\MemoryEfficientLongestCommonSubsequenceCalculator' => $vendorDir . '/php-cs-fixer/diff/src/v3_0/MemoryEfficientLongestCommonSubsequenceCalculator.php',
  55936. 'PhpCsFixer\\Diff\\v3_0\\Output\\AbstractChunkOutputBuilder' => $vendorDir . '/php-cs-fixer/diff/src/v3_0/Output/AbstractChunkOutputBuilder.php',
  55937. 'PhpCsFixer\\Diff\\v3_0\\Output\\DiffOnlyOutputBuilder' => $vendorDir . '/php-cs-fixer/diff/src/v3_0/Output/DiffOnlyOutputBuilder.php',
  55938. 'PhpCsFixer\\Diff\\v3_0\\Output\\DiffOutputBuilderInterface' => $vendorDir . '/php-cs-fixer/diff/src/v3_0/Output/DiffOutputBuilderInterface.php',
  55939. 'PhpCsFixer\\Diff\\v3_0\\Output\\StrictUnifiedDiffOutputBuilder' => $vendorDir . '/php-cs-fixer/diff/src/v3_0/Output/StrictUnifiedDiffOutputBuilder.php',
  55940. 'PhpCsFixer\\Diff\\v3_0\\Output\\UnifiedDiffOutputBuilder' => $vendorDir . '/php-cs-fixer/diff/src/v3_0/Output/UnifiedDiffOutputBuilder.php',
  55941. 'PhpCsFixer\\Diff\\v3_0\\Parser' => $vendorDir . '/php-cs-fixer/diff/src/v3_0/Parser.php',
  55942. 'PhpCsFixer\\Diff\\v3_0\\TimeEfficientLongestCommonSubsequenceCalculator' => $vendorDir . '/php-cs-fixer/diff/src/v3_0/TimeEfficientLongestCommonSubsequenceCalculator.php',
  55943. 'PhpCsFixer\\Tests\\TestCase' => $baseDir . '/tests/TestCase.php',
  55944. 'PhpCsFixer\\Tests\\Test\\AbstractFixerTestCase' => $baseDir . '/tests/Test/AbstractFixerTestCase.php',
  55945. 'PhpCsFixer\\Tests\\Test\\AbstractIntegrationCaseFactory' => $baseDir . '/tests/Test/AbstractIntegrationCaseFactory.php',
  55946. 'PhpCsFixer\\Tests\\Test\\AbstractIntegrationTestCase' => $baseDir . '/tests/Test/AbstractIntegrationTestCase.php',
  55947. 'PhpCsFixer\\Tests\\Test\\Assert\\AssertTokensTrait' => $baseDir . '/tests/Test/Assert/AssertTokensTrait.php',
  55948. 'PhpCsFixer\\Tests\\Test\\IntegrationCase' => $baseDir . '/tests/Test/IntegrationCase.php',
  55949. 'PhpCsFixer\\Tests\\Test\\IntegrationCaseFactory' => $baseDir . '/tests/Test/IntegrationCaseFactory.php',
  55950. 'PhpCsFixer\\Tests\\Test\\IntegrationCaseFactoryInterface' => $baseDir . '/tests/Test/IntegrationCaseFactoryInterface.php',
  55951. 'PhpCsFixer\\Tests\\Test\\InternalIntegrationCaseFactory' => $baseDir . '/tests/Test/InternalIntegrationCaseFactory.php',
  55952. 'PhpCsFixer\\Tests\\Test\\IsIdenticalConstraint' => $baseDir . '/tests/Test/IsIdenticalConstraint.php',
  55953. 'SessionUpdateTimestampHandlerInterface' => $vendorDir . '/symfony/polyfill-php70/Resources/stubs/SessionUpdateTimestampHandlerInterface.php',
  55954. 'TypeError' => $vendorDir . '/symfony/polyfill-php70/Resources/stubs/TypeError.php',
  55955. );
  55956. <?php
  55957. namespace Composer\Semver;
  55958. use Composer\Semver\Constraint\ConstraintInterface;
  55959. use Composer\Semver\Constraint\EmptyConstraint;
  55960. use Composer\Semver\Constraint\MultiConstraint;
  55961. use Composer\Semver\Constraint\Constraint;
  55962. class VersionParser
  55963. {
  55964. private static $modifierRegex = '[._-]?(?:(stable|beta|b|RC|alpha|a|patch|pl|p)((?:[.-]?\d+)*+)?)?([.-]?dev)?';
  55965. private static $stabilities = array('stable', 'RC', 'beta', 'alpha', 'dev');
  55966. public static function parseStability($version)
  55967. {
  55968. $version = preg_replace('{#.+$}i', '', $version);
  55969. if (strpos($version, 'dev-') === 0 || '-dev' === substr($version, -4)) {
  55970. return 'dev';
  55971. }
  55972. preg_match('{' . self::$modifierRegex . '(?:\+.*)?$}i', strtolower($version), $match);
  55973. if (!empty($match[3])) {
  55974. return 'dev';
  55975. }
  55976. if (!empty($match[1])) {
  55977. if ('beta' === $match[1] || 'b' === $match[1]) {
  55978. return 'beta';
  55979. }
  55980. if ('alpha' === $match[1] || 'a' === $match[1]) {
  55981. return 'alpha';
  55982. }
  55983. if ('rc' === $match[1]) {
  55984. return 'RC';
  55985. }
  55986. }
  55987. return 'stable';
  55988. }
  55989. public static function normalizeStability($stability)
  55990. {
  55991. $stability = strtolower($stability);
  55992. return $stability === 'rc' ? 'RC' : $stability;
  55993. }
  55994. public function normalize($version, $fullVersion = null)
  55995. {
  55996. $version = trim($version);
  55997. if (null === $fullVersion) {
  55998. $fullVersion = $version;
  55999. }
  56000. if (preg_match('{^([^,\s]++) ++as ++([^,\s]++)$}', $version, $match)) {
  56001. $this->normalize($match[2]);
  56002. $version = $match[1];
  56003. }
  56004. if (preg_match('{^(?:dev-)?(?:master|trunk|default)$}i', $version)) {
  56005. return '9999999-dev';
  56006. }
  56007. if (stripos($version, 'dev-') === 0) {
  56008. return 'dev-' . substr($version, 4);
  56009. }
  56010. if (preg_match('{^([^,\s+]++)\+[^\s]++$}', $version, $match)) {
  56011. $version = $match[1];
  56012. }
  56013. if (preg_match('{^v?(\d{1,5})(\.\d++)?(\.\d++)?(\.\d++)?' . self::$modifierRegex . '$}i', $version, $matches)) {
  56014. $version = $matches[1]
  56015. . (!empty($matches[2]) ? $matches[2] : '.0')
  56016. . (!empty($matches[3]) ? $matches[3] : '.0')
  56017. . (!empty($matches[4]) ? $matches[4] : '.0');
  56018. $index = 5;
  56019. } elseif (preg_match('{^v?(\d{4}(?:[.:-]?\d{2}){1,6}(?:[.:-]?\d{1,3})?)' . self::$modifierRegex . '$}i', $version, $matches)) {
  56020. $version = preg_replace('{\D}', '.', $matches[1]);
  56021. $index = 2;
  56022. }
  56023. if (isset($index)) {
  56024. if (!empty($matches[$index])) {
  56025. if ('stable' === $matches[$index]) {
  56026. return $version;
  56027. }
  56028. $version .= '-' . $this->expandStability($matches[$index]) . (!empty($matches[$index + 1]) ? ltrim($matches[$index + 1], '.-') : '');
  56029. }
  56030. if (!empty($matches[$index + 2])) {
  56031. $version .= '-dev';
  56032. }
  56033. return $version;
  56034. }
  56035. if (preg_match('{(.*?)[.-]?dev$}i', $version, $match)) {
  56036. try {
  56037. return $this->normalizeBranch($match[1]);
  56038. } catch (\Exception $e) {
  56039. }
  56040. }
  56041. $extraMessage = '';
  56042. if (preg_match('{ +as +' . preg_quote($version) . '$}', $fullVersion)) {
  56043. $extraMessage = ' in "' . $fullVersion . '", the alias must be an exact version';
  56044. } elseif (preg_match('{^' . preg_quote($version) . ' +as +}', $fullVersion)) {
  56045. $extraMessage = ' in "' . $fullVersion . '", the alias source must be an exact version, if it is a branch name you should prefix it with dev-';
  56046. }
  56047. throw new \UnexpectedValueException('Invalid version string "' . $version . '"' . $extraMessage);
  56048. }
  56049. public function parseNumericAliasPrefix($branch)
  56050. {
  56051. if (preg_match('{^(?P<version>(\d++\\.)*\d++)(?:\.x)?-dev$}i', $branch, $matches)) {
  56052. return $matches['version'] . '.';
  56053. }
  56054. return false;
  56055. }
  56056. public function normalizeBranch($name)
  56057. {
  56058. $name = trim($name);
  56059. if (in_array($name, array('master', 'trunk', 'default'))) {
  56060. return $this->normalize($name);
  56061. }
  56062. if (preg_match('{^v?(\d++)(\.(?:\d++|[xX*]))?(\.(?:\d++|[xX*]))?(\.(?:\d++|[xX*]))?$}i', $name, $matches)) {
  56063. $version = '';
  56064. for ($i = 1; $i < 5; ++$i) {
  56065. $version .= isset($matches[$i]) ? str_replace(array('*', 'X'), 'x', $matches[$i]) : '.x';
  56066. }
  56067. return str_replace('x', '9999999', $version) . '-dev';
  56068. }
  56069. return 'dev-' . $name;
  56070. }
  56071. public function parseConstraints($constraints)
  56072. {
  56073. $prettyConstraint = $constraints;
  56074. if (preg_match('{^([^,\s]*?)@(' . implode('|', self::$stabilities) . ')$}i', $constraints, $match)) {
  56075. $constraints = empty($match[1]) ? '*' : $match[1];
  56076. }
  56077. if (preg_match('{^(dev-[^,\s@]+?|[^,\s@]+?\.x-dev)#.+$}i', $constraints, $match)) {
  56078. $constraints = $match[1];
  56079. }
  56080. $orConstraints = preg_split('{\s*\|\|?\s*}', trim($constraints));
  56081. $orGroups = array();
  56082. foreach ($orConstraints as $constraints) {
  56083. $andConstraints = preg_split('{(?<!^|as|[=>< ,]) *(?<!-)[, ](?!-) *(?!,|as|$)}', $constraints);
  56084. if (count($andConstraints) > 1) {
  56085. $constraintObjects = array();
  56086. foreach ($andConstraints as $constraint) {
  56087. foreach ($this->parseConstraint($constraint) as $parsedConstraint) {
  56088. $constraintObjects[] = $parsedConstraint;
  56089. }
  56090. }
  56091. } else {
  56092. $constraintObjects = $this->parseConstraint($andConstraints[0]);
  56093. }
  56094. if (1 === count($constraintObjects)) {
  56095. $constraint = $constraintObjects[0];
  56096. } else {
  56097. $constraint = new MultiConstraint($constraintObjects);
  56098. }
  56099. $orGroups[] = $constraint;
  56100. }
  56101. if (1 === count($orGroups)) {
  56102. $constraint = $orGroups[0];
  56103. } elseif (2 === count($orGroups)
  56104. && $orGroups[0] instanceof MultiConstraint
  56105. && $orGroups[1] instanceof MultiConstraint
  56106. && 2 === count($orGroups[0]->getConstraints())
  56107. && 2 === count($orGroups[1]->getConstraints())
  56108. && ($a = (string) $orGroups[0])
  56109. && strpos($a, '[>=') === 0 && (false !== ($posA = strpos($a, '<', 4)))
  56110. && ($b = (string) $orGroups[1])
  56111. && strpos($b, '[>=') === 0 && (false !== ($posB = strpos($b, '<', 4)))
  56112. && substr($a, $posA + 2, -1) === substr($b, 4, $posB - 5)
  56113. ) {
  56114. $constraint = new MultiConstraint(array(
  56115. new Constraint('>=', substr($a, 4, $posA - 5)),
  56116. new Constraint('<', substr($b, $posB + 2, -1)),
  56117. ));
  56118. } else {
  56119. $constraint = new MultiConstraint($orGroups, false);
  56120. }
  56121. $constraint->setPrettyString($prettyConstraint);
  56122. return $constraint;
  56123. }
  56124. private function parseConstraint($constraint)
  56125. {
  56126. if (preg_match('{^([^,\s]+?)@(' . implode('|', self::$stabilities) . ')$}i', $constraint, $match)) {
  56127. $constraint = $match[1];
  56128. if ($match[2] !== 'stable') {
  56129. $stabilityModifier = $match[2];
  56130. }
  56131. }
  56132. if (preg_match('{^v?[xX*](\.[xX*])*$}i', $constraint)) {
  56133. return array(new EmptyConstraint());
  56134. }
  56135. $versionRegex = 'v?(\d++)(?:\.(\d++))?(?:\.(\d++))?(?:\.(\d++))?' . self::$modifierRegex . '(?:\+[^\s]+)?';
  56136. if (preg_match('{^~>?' . $versionRegex . '$}i', $constraint, $matches)) {
  56137. if (strpos($constraint, '~>') === 0) {
  56138. throw new \UnexpectedValueException(
  56139. 'Could not parse version constraint ' . $constraint . ': ' .
  56140. 'Invalid operator "~>", you probably meant to use the "~" operator'
  56141. );
  56142. }
  56143. if (isset($matches[4]) && '' !== $matches[4] && null !== $matches[4]) {
  56144. $position = 4;
  56145. } elseif (isset($matches[3]) && '' !== $matches[3] && null !== $matches[3]) {
  56146. $position = 3;
  56147. } elseif (isset($matches[2]) && '' !== $matches[2] && null !== $matches[2]) {
  56148. $position = 2;
  56149. } else {
  56150. $position = 1;
  56151. }
  56152. $stabilitySuffix = '';
  56153. if (empty($matches[5]) && empty($matches[7])) {
  56154. $stabilitySuffix .= '-dev';
  56155. }
  56156. $lowVersion = $this->normalize(substr($constraint . $stabilitySuffix, 1));
  56157. $lowerBound = new Constraint('>=', $lowVersion);
  56158. $highPosition = max(1, $position - 1);
  56159. $highVersion = $this->manipulateVersionString($matches, $highPosition, 1) . '-dev';
  56160. $upperBound = new Constraint('<', $highVersion);
  56161. return array(
  56162. $lowerBound,
  56163. $upperBound,
  56164. );
  56165. }
  56166. if (preg_match('{^\^' . $versionRegex . '($)}i', $constraint, $matches)) {
  56167. if ('0' !== $matches[1] || '' === $matches[2] || null === $matches[2]) {
  56168. $position = 1;
  56169. } elseif ('0' !== $matches[2] || '' === $matches[3] || null === $matches[3]) {
  56170. $position = 2;
  56171. } else {
  56172. $position = 3;
  56173. }
  56174. $stabilitySuffix = '';
  56175. if (empty($matches[5]) && empty($matches[7])) {
  56176. $stabilitySuffix .= '-dev';
  56177. }
  56178. $lowVersion = $this->normalize(substr($constraint . $stabilitySuffix, 1));
  56179. $lowerBound = new Constraint('>=', $lowVersion);
  56180. $highVersion = $this->manipulateVersionString($matches, $position, 1) . '-dev';
  56181. $upperBound = new Constraint('<', $highVersion);
  56182. return array(
  56183. $lowerBound,
  56184. $upperBound,
  56185. );
  56186. }
  56187. if (preg_match('{^v?(\d++)(?:\.(\d++))?(?:\.(\d++))?(?:\.[xX*])++$}', $constraint, $matches)) {
  56188. if (isset($matches[3]) && '' !== $matches[3] && null !== $matches[3]) {
  56189. $position = 3;
  56190. } elseif (isset($matches[2]) && '' !== $matches[2] && null !== $matches[2]) {
  56191. $position = 2;
  56192. } else {
  56193. $position = 1;
  56194. }
  56195. $lowVersion = $this->manipulateVersionString($matches, $position) . '-dev';
  56196. $highVersion = $this->manipulateVersionString($matches, $position, 1) . '-dev';
  56197. if ($lowVersion === '0.0.0.0-dev') {
  56198. return array(new Constraint('<', $highVersion));
  56199. }
  56200. return array(
  56201. new Constraint('>=', $lowVersion),
  56202. new Constraint('<', $highVersion),
  56203. );
  56204. }
  56205. if (preg_match('{^(?P<from>' . $versionRegex . ') +- +(?P<to>' . $versionRegex . ')($)}i', $constraint, $matches)) {
  56206. $lowStabilitySuffix = '';
  56207. if (empty($matches[6]) && empty($matches[8])) {
  56208. $lowStabilitySuffix = '-dev';
  56209. }
  56210. $lowVersion = $this->normalize($matches['from']);
  56211. $lowerBound = new Constraint('>=', $lowVersion . $lowStabilitySuffix);
  56212. $empty = function ($x) {
  56213. return ($x === 0 || $x === '0') ? false : empty($x);
  56214. };
  56215. if ((!$empty($matches[11]) && !$empty($matches[12])) || !empty($matches[14]) || !empty($matches[16])) {
  56216. $highVersion = $this->normalize($matches['to']);
  56217. $upperBound = new Constraint('<=', $highVersion);
  56218. } else {
  56219. $highMatch = array('', $matches[10], $matches[11], $matches[12], $matches[13]);
  56220. $highVersion = $this->manipulateVersionString($highMatch, $empty($matches[11]) ? 1 : 2, 1) . '-dev';
  56221. $upperBound = new Constraint('<', $highVersion);
  56222. }
  56223. return array(
  56224. $lowerBound,
  56225. $upperBound,
  56226. );
  56227. }
  56228. if (preg_match('{^(<>|!=|>=?|<=?|==?)?\s*(.*)}', $constraint, $matches)) {
  56229. try {
  56230. $version = $this->normalize($matches[2]);
  56231. if (!empty($stabilityModifier) && self::parseStability($version) === 'stable') {
  56232. $version .= '-' . $stabilityModifier;
  56233. } elseif ('<' === $matches[1] || '>=' === $matches[1]) {
  56234. if (!preg_match('/-' . self::$modifierRegex . '$/', strtolower($matches[2]))) {
  56235. if (strpos($matches[2], 'dev-') !== 0) {
  56236. $version .= '-dev';
  56237. }
  56238. }
  56239. }
  56240. return array(new Constraint($matches[1] ?: '=', $version));
  56241. } catch (\Exception $e) {
  56242. }
  56243. }
  56244. $message = 'Could not parse version constraint ' . $constraint;
  56245. if (isset($e)) {
  56246. $message .= ': ' . $e->getMessage();
  56247. }
  56248. throw new \UnexpectedValueException($message);
  56249. }
  56250. private function manipulateVersionString($matches, $position, $increment = 0, $pad = '0')
  56251. {
  56252. for ($i = 4; $i > 0; --$i) {
  56253. if ($i > $position) {
  56254. $matches[$i] = $pad;
  56255. } elseif ($i === $position && $increment) {
  56256. $matches[$i] += $increment;
  56257. if ($matches[$i] < 0) {
  56258. $matches[$i] = $pad;
  56259. --$position;
  56260. if ($i === 1) {
  56261. return null;
  56262. }
  56263. }
  56264. }
  56265. }
  56266. return $matches[1] . '.' . $matches[2] . '.' . $matches[3] . '.' . $matches[4];
  56267. }
  56268. private function expandStability($stability)
  56269. {
  56270. $stability = strtolower($stability);
  56271. switch ($stability) {
  56272. case 'a':
  56273. return 'alpha';
  56274. case 'b':
  56275. return 'beta';
  56276. case 'p':
  56277. case 'pl':
  56278. return 'patch';
  56279. case 'rc':
  56280. return 'RC';
  56281. default:
  56282. return $stability;
  56283. }
  56284. }
  56285. }
  56286. <?php
  56287. namespace Composer\Semver\Constraint;
  56288. trigger_error('The ' . __NAMESPACE__ . '\AbstractConstraint abstract class is deprecated, there is no replacement for it, it will be removed in the next major version.', E_USER_DEPRECATED);
  56289. abstract class AbstractConstraint implements ConstraintInterface
  56290. {
  56291. protected $prettyString;
  56292. public function matches(ConstraintInterface $provider)
  56293. {
  56294. if ($provider instanceof $this) {
  56295. return $this->matchSpecific($provider);
  56296. }
  56297. return $provider->matches($this);
  56298. }
  56299. public function setPrettyString($prettyString)
  56300. {
  56301. $this->prettyString = $prettyString;
  56302. }
  56303. public function getPrettyString()
  56304. {
  56305. if ($this->prettyString) {
  56306. return $this->prettyString;
  56307. }
  56308. return $this->__toString();
  56309. }
  56310. }
  56311. <?php
  56312. namespace Composer\Semver\Constraint;
  56313. class Constraint implements ConstraintInterface
  56314. {
  56315. const OP_EQ = 0;
  56316. const OP_LT = 1;
  56317. const OP_LE = 2;
  56318. const OP_GT = 3;
  56319. const OP_GE = 4;
  56320. const OP_NE = 5;
  56321. private static $transOpStr = array(
  56322. '=' => self::OP_EQ,
  56323. '==' => self::OP_EQ,
  56324. '<' => self::OP_LT,
  56325. '<=' => self::OP_LE,
  56326. '>' => self::OP_GT,
  56327. '>=' => self::OP_GE,
  56328. '<>' => self::OP_NE,
  56329. '!=' => self::OP_NE,
  56330. );
  56331. private static $transOpInt = array(
  56332. self::OP_EQ => '==',
  56333. self::OP_LT => '<',
  56334. self::OP_LE => '<=',
  56335. self::OP_GT => '>',
  56336. self::OP_GE => '>=',
  56337. self::OP_NE => '!=',
  56338. );
  56339. protected $operator;
  56340. protected $version;
  56341. protected $prettyString;
  56342. public function matches(ConstraintInterface $provider)
  56343. {
  56344. if ($provider instanceof $this) {
  56345. return $this->matchSpecific($provider);
  56346. }
  56347. return $provider->matches($this);
  56348. }
  56349. public function setPrettyString($prettyString)
  56350. {
  56351. $this->prettyString = $prettyString;
  56352. }
  56353. public function getPrettyString()
  56354. {
  56355. if ($this->prettyString) {
  56356. return $this->prettyString;
  56357. }
  56358. return $this->__toString();
  56359. }
  56360. public static function getSupportedOperators()
  56361. {
  56362. return array_keys(self::$transOpStr);
  56363. }
  56364. public function __construct($operator, $version)
  56365. {
  56366. if (!isset(self::$transOpStr[$operator])) {
  56367. throw new \InvalidArgumentException(sprintf(
  56368. 'Invalid operator "%s" given, expected one of: %s',
  56369. $operator,
  56370. implode(', ', self::getSupportedOperators())
  56371. ));
  56372. }
  56373. $this->operator = self::$transOpStr[$operator];
  56374. $this->version = $version;
  56375. }
  56376. public function versionCompare($a, $b, $operator, $compareBranches = false)
  56377. {
  56378. if (!isset(self::$transOpStr[$operator])) {
  56379. throw new \InvalidArgumentException(sprintf(
  56380. 'Invalid operator "%s" given, expected one of: %s',
  56381. $operator,
  56382. implode(', ', self::getSupportedOperators())
  56383. ));
  56384. }
  56385. $aIsBranch = 'dev-' === substr($a, 0, 4);
  56386. $bIsBranch = 'dev-' === substr($b, 0, 4);
  56387. if ($aIsBranch && $bIsBranch) {
  56388. return $operator === '==' && $a === $b;
  56389. }
  56390. if (!$compareBranches && ($aIsBranch || $bIsBranch)) {
  56391. return false;
  56392. }
  56393. return version_compare($a, $b, $operator);
  56394. }
  56395. public function matchSpecific(Constraint $provider, $compareBranches = false)
  56396. {
  56397. $noEqualOp = str_replace('=', '', self::$transOpInt[$this->operator]);
  56398. $providerNoEqualOp = str_replace('=', '', self::$transOpInt[$provider->operator]);
  56399. $isEqualOp = self::OP_EQ === $this->operator;
  56400. $isNonEqualOp = self::OP_NE === $this->operator;
  56401. $isProviderEqualOp = self::OP_EQ === $provider->operator;
  56402. $isProviderNonEqualOp = self::OP_NE === $provider->operator;
  56403. if ($isNonEqualOp || $isProviderNonEqualOp) {
  56404. return (!$isEqualOp && !$isProviderEqualOp)
  56405. || $this->versionCompare($provider->version, $this->version, '!=', $compareBranches);
  56406. }
  56407. if ($this->operator !== self::OP_EQ && $noEqualOp === $providerNoEqualOp) {
  56408. return true;
  56409. }
  56410. if ($this->versionCompare($provider->version, $this->version, self::$transOpInt[$this->operator], $compareBranches)) {
  56411. return !($provider->version === $this->version
  56412. && self::$transOpInt[$provider->operator] === $providerNoEqualOp
  56413. && self::$transOpInt[$this->operator] !== $noEqualOp);
  56414. }
  56415. return false;
  56416. }
  56417. public function __toString()
  56418. {
  56419. return self::$transOpInt[$this->operator] . ' ' . $this->version;
  56420. }
  56421. }
  56422. <?php
  56423. namespace Composer\Semver\Constraint;
  56424. interface ConstraintInterface
  56425. {
  56426. public function matches(ConstraintInterface $provider);
  56427. public function getPrettyString();
  56428. public function __toString();
  56429. }
  56430. <?php
  56431. namespace Composer\Semver\Constraint;
  56432. class EmptyConstraint implements ConstraintInterface
  56433. {
  56434. protected $prettyString;
  56435. public function matches(ConstraintInterface $provider)
  56436. {
  56437. return true;
  56438. }
  56439. public function setPrettyString($prettyString)
  56440. {
  56441. $this->prettyString = $prettyString;
  56442. }
  56443. public function getPrettyString()
  56444. {
  56445. if ($this->prettyString) {
  56446. return $this->prettyString;
  56447. }
  56448. return (string) $this;
  56449. }
  56450. public function __toString()
  56451. {
  56452. return '[]';
  56453. }
  56454. }
  56455. <?php
  56456. namespace Composer\Semver\Constraint;
  56457. class MultiConstraint implements ConstraintInterface
  56458. {
  56459. protected $constraints;
  56460. protected $prettyString;
  56461. protected $conjunctive;
  56462. public function __construct(array $constraints, $conjunctive = true)
  56463. {
  56464. $this->constraints = $constraints;
  56465. $this->conjunctive = $conjunctive;
  56466. }
  56467. public function getConstraints()
  56468. {
  56469. return $this->constraints;
  56470. }
  56471. public function isConjunctive()
  56472. {
  56473. return $this->conjunctive;
  56474. }
  56475. public function isDisjunctive()
  56476. {
  56477. return !$this->conjunctive;
  56478. }
  56479. public function matches(ConstraintInterface $provider)
  56480. {
  56481. if (false === $this->conjunctive) {
  56482. foreach ($this->constraints as $constraint) {
  56483. if ($constraint->matches($provider)) {
  56484. return true;
  56485. }
  56486. }
  56487. return false;
  56488. }
  56489. foreach ($this->constraints as $constraint) {
  56490. if (!$constraint->matches($provider)) {
  56491. return false;
  56492. }
  56493. }
  56494. return true;
  56495. }
  56496. public function setPrettyString($prettyString)
  56497. {
  56498. $this->prettyString = $prettyString;
  56499. }
  56500. public function getPrettyString()
  56501. {
  56502. if ($this->prettyString) {
  56503. return $this->prettyString;
  56504. }
  56505. return (string) $this;
  56506. }
  56507. public function __toString()
  56508. {
  56509. $constraints = array();
  56510. foreach ($this->constraints as $constraint) {
  56511. $constraints[] = (string) $constraint;
  56512. }
  56513. return '[' . implode($this->conjunctive ? ' ' : ' || ', $constraints) . ']';
  56514. }
  56515. }
  56516. <?php
  56517. namespace Composer\Semver;
  56518. use Composer\Semver\Constraint\Constraint;
  56519. class Comparator
  56520. {
  56521. public static function greaterThan($version1, $version2)
  56522. {
  56523. return self::compare($version1, '>', $version2);
  56524. }
  56525. public static function greaterThanOrEqualTo($version1, $version2)
  56526. {
  56527. return self::compare($version1, '>=', $version2);
  56528. }
  56529. public static function lessThan($version1, $version2)
  56530. {
  56531. return self::compare($version1, '<', $version2);
  56532. }
  56533. public static function lessThanOrEqualTo($version1, $version2)
  56534. {
  56535. return self::compare($version1, '<=', $version2);
  56536. }
  56537. public static function equalTo($version1, $version2)
  56538. {
  56539. return self::compare($version1, '==', $version2);
  56540. }
  56541. public static function notEqualTo($version1, $version2)
  56542. {
  56543. return self::compare($version1, '!=', $version2);
  56544. }
  56545. public static function compare($version1, $operator, $version2)
  56546. {
  56547. $constraint = new Constraint($operator, $version2);
  56548. return $constraint->matches(new Constraint('==', $version1));
  56549. }
  56550. }
  56551. <?php
  56552. namespace Composer\Semver;
  56553. use Composer\Semver\Constraint\Constraint;
  56554. class Semver
  56555. {
  56556. const SORT_ASC = 1;
  56557. const SORT_DESC = -1;
  56558. private static $versionParser;
  56559. public static function satisfies($version, $constraints)
  56560. {
  56561. if (null === self::$versionParser) {
  56562. self::$versionParser = new VersionParser();
  56563. }
  56564. $versionParser = self::$versionParser;
  56565. $provider = new Constraint('==', $versionParser->normalize($version));
  56566. $parsedConstraints = $versionParser->parseConstraints($constraints);
  56567. return $parsedConstraints->matches($provider);
  56568. }
  56569. public static function satisfiedBy(array $versions, $constraints)
  56570. {
  56571. $versions = array_filter($versions, function ($version) use ($constraints) {
  56572. return Semver::satisfies($version, $constraints);
  56573. });
  56574. return array_values($versions);
  56575. }
  56576. public static function sort(array $versions)
  56577. {
  56578. return self::usort($versions, self::SORT_ASC);
  56579. }
  56580. public static function rsort(array $versions)
  56581. {
  56582. return self::usort($versions, self::SORT_DESC);
  56583. }
  56584. private static function usort(array $versions, $direction)
  56585. {
  56586. if (null === self::$versionParser) {
  56587. self::$versionParser = new VersionParser();
  56588. }
  56589. $versionParser = self::$versionParser;
  56590. $normalized = array();
  56591. foreach ($versions as $key => $version) {
  56592. $normalized[] = array($versionParser->normalize($version), $key);
  56593. }
  56594. usort($normalized, function (array $left, array $right) use ($direction) {
  56595. if ($left[0] === $right[0]) {
  56596. return 0;
  56597. }
  56598. if (Comparator::lessThan($left[0], $right[0])) {
  56599. return -$direction;
  56600. }
  56601. return $direction;
  56602. });
  56603. $sorted = array();
  56604. foreach ($normalized as $item) {
  56605. $sorted[] = $versions[$item[1]];
  56606. }
  56607. return $sorted;
  56608. }
  56609. }
  56610. <?php
  56611. $vendorDir = dirname(dirname(__FILE__));
  56612. $baseDir = dirname($vendorDir);
  56613. return array(
  56614. );
  56615. <?php
  56616. namespace Composer\Autoload;
  56617. /**
  56618. @seld
  56619. */
  56620. class ClassLoader
  56621. {
  56622. private $prefixLengthsPsr4 = array();
  56623. private $prefixDirsPsr4 = array();
  56624. private $fallbackDirsPsr4 = array();
  56625. private $prefixesPsr0 = array();
  56626. private $fallbackDirsPsr0 = array();
  56627. private $useIncludePath = false;
  56628. private $classMap = array();
  56629. private $classMapAuthoritative = false;
  56630. private $missingClasses = array();
  56631. private $apcuPrefix;
  56632. public function getPrefixes()
  56633. {
  56634. if (!empty($this->prefixesPsr0)) {
  56635. return call_user_func_array('array_merge', $this->prefixesPsr0);
  56636. }
  56637. return array();
  56638. }
  56639. public function getPrefixesPsr4()
  56640. {
  56641. return $this->prefixDirsPsr4;
  56642. }
  56643. public function getFallbackDirs()
  56644. {
  56645. return $this->fallbackDirsPsr0;
  56646. }
  56647. public function getFallbackDirsPsr4()
  56648. {
  56649. return $this->fallbackDirsPsr4;
  56650. }
  56651. public function getClassMap()
  56652. {
  56653. return $this->classMap;
  56654. }
  56655. public function addClassMap(array $classMap)
  56656. {
  56657. if ($this->classMap) {
  56658. $this->classMap = array_merge($this->classMap, $classMap);
  56659. } else {
  56660. $this->classMap = $classMap;
  56661. }
  56662. }
  56663. public function add($prefix, $paths, $prepend = false)
  56664. {
  56665. if (!$prefix) {
  56666. if ($prepend) {
  56667. $this->fallbackDirsPsr0 = array_merge(
  56668. (array) $paths,
  56669. $this->fallbackDirsPsr0
  56670. );
  56671. } else {
  56672. $this->fallbackDirsPsr0 = array_merge(
  56673. $this->fallbackDirsPsr0,
  56674. (array) $paths
  56675. );
  56676. }
  56677. return;
  56678. }
  56679. $first = $prefix[0];
  56680. if (!isset($this->prefixesPsr0[$first][$prefix])) {
  56681. $this->prefixesPsr0[$first][$prefix] = (array) $paths;
  56682. return;
  56683. }
  56684. if ($prepend) {
  56685. $this->prefixesPsr0[$first][$prefix] = array_merge(
  56686. (array) $paths,
  56687. $this->prefixesPsr0[$first][$prefix]
  56688. );
  56689. } else {
  56690. $this->prefixesPsr0[$first][$prefix] = array_merge(
  56691. $this->prefixesPsr0[$first][$prefix],
  56692. (array) $paths
  56693. );
  56694. }
  56695. }
  56696. public function addPsr4($prefix, $paths, $prepend = false)
  56697. {
  56698. if (!$prefix) {
  56699. if ($prepend) {
  56700. $this->fallbackDirsPsr4 = array_merge(
  56701. (array) $paths,
  56702. $this->fallbackDirsPsr4
  56703. );
  56704. } else {
  56705. $this->fallbackDirsPsr4 = array_merge(
  56706. $this->fallbackDirsPsr4,
  56707. (array) $paths
  56708. );
  56709. }
  56710. } elseif (!isset($this->prefixDirsPsr4[$prefix])) {
  56711. $length = strlen($prefix);
  56712. if ('\\' !== $prefix[$length - 1]) {
  56713. throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
  56714. }
  56715. $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
  56716. $this->prefixDirsPsr4[$prefix] = (array) $paths;
  56717. } elseif ($prepend) {
  56718. $this->prefixDirsPsr4[$prefix] = array_merge(
  56719. (array) $paths,
  56720. $this->prefixDirsPsr4[$prefix]
  56721. );
  56722. } else {
  56723. $this->prefixDirsPsr4[$prefix] = array_merge(
  56724. $this->prefixDirsPsr4[$prefix],
  56725. (array) $paths
  56726. );
  56727. }
  56728. }
  56729. public function set($prefix, $paths)
  56730. {
  56731. if (!$prefix) {
  56732. $this->fallbackDirsPsr0 = (array) $paths;
  56733. } else {
  56734. $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
  56735. }
  56736. }
  56737. public function setPsr4($prefix, $paths)
  56738. {
  56739. if (!$prefix) {
  56740. $this->fallbackDirsPsr4 = (array) $paths;
  56741. } else {
  56742. $length = strlen($prefix);
  56743. if ('\\' !== $prefix[$length - 1]) {
  56744. throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
  56745. }
  56746. $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
  56747. $this->prefixDirsPsr4[$prefix] = (array) $paths;
  56748. }
  56749. }
  56750. public function setUseIncludePath($useIncludePath)
  56751. {
  56752. $this->useIncludePath = $useIncludePath;
  56753. }
  56754. public function getUseIncludePath()
  56755. {
  56756. return $this->useIncludePath;
  56757. }
  56758. public function setClassMapAuthoritative($classMapAuthoritative)
  56759. {
  56760. $this->classMapAuthoritative = $classMapAuthoritative;
  56761. }
  56762. public function isClassMapAuthoritative()
  56763. {
  56764. return $this->classMapAuthoritative;
  56765. }
  56766. public function setApcuPrefix($apcuPrefix)
  56767. {
  56768. $this->apcuPrefix = function_exists('apcu_fetch') && ini_get('apc.enabled') ? $apcuPrefix : null;
  56769. }
  56770. public function getApcuPrefix()
  56771. {
  56772. return $this->apcuPrefix;
  56773. }
  56774. public function register($prepend = false)
  56775. {
  56776. spl_autoload_register(array($this, 'loadClass'), true, $prepend);
  56777. }
  56778. public function unregister()
  56779. {
  56780. spl_autoload_unregister(array($this, 'loadClass'));
  56781. }
  56782. public function loadClass($class)
  56783. {
  56784. if ($file = $this->findFile($class)) {
  56785. includeFile($file);
  56786. return true;
  56787. }
  56788. }
  56789. public function findFile($class)
  56790. {
  56791. if (isset($this->classMap[$class])) {
  56792. return $this->classMap[$class];
  56793. }
  56794. if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
  56795. return false;
  56796. }
  56797. if (null !== $this->apcuPrefix) {
  56798. $file = apcu_fetch($this->apcuPrefix.$class, $hit);
  56799. if ($hit) {
  56800. return $file;
  56801. }
  56802. }
  56803. $file = $this->findFileWithExtension($class, '.php');
  56804. if (false === $file && defined('HHVM_VERSION')) {
  56805. $file = $this->findFileWithExtension($class, '.hh');
  56806. }
  56807. if (null !== $this->apcuPrefix) {
  56808. apcu_add($this->apcuPrefix.$class, $file);
  56809. }
  56810. if (false === $file) {
  56811. $this->missingClasses[$class] = true;
  56812. }
  56813. return $file;
  56814. }
  56815. private function findFileWithExtension($class, $ext)
  56816. {
  56817. $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
  56818. $first = $class[0];
  56819. if (isset($this->prefixLengthsPsr4[$first])) {
  56820. $subPath = $class;
  56821. while (false !== $lastPos = strrpos($subPath, '\\')) {
  56822. $subPath = substr($subPath, 0, $lastPos);
  56823. $search = $subPath . '\\';
  56824. if (isset($this->prefixDirsPsr4[$search])) {
  56825. $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
  56826. foreach ($this->prefixDirsPsr4[$search] as $dir) {
  56827. if (file_exists($file = $dir . $pathEnd)) {
  56828. return $file;
  56829. }
  56830. }
  56831. }
  56832. }
  56833. }
  56834. foreach ($this->fallbackDirsPsr4 as $dir) {
  56835. if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
  56836. return $file;
  56837. }
  56838. }
  56839. if (false !== $pos = strrpos($class, '\\')) {
  56840. $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
  56841. . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
  56842. } else {
  56843. $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
  56844. }
  56845. if (isset($this->prefixesPsr0[$first])) {
  56846. foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
  56847. if (0 === strpos($class, $prefix)) {
  56848. foreach ($dirs as $dir) {
  56849. if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
  56850. return $file;
  56851. }
  56852. }
  56853. }
  56854. }
  56855. }
  56856. foreach ($this->fallbackDirsPsr0 as $dir) {
  56857. if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
  56858. return $file;
  56859. }
  56860. }
  56861. if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
  56862. return $file;
  56863. }
  56864. return false;
  56865. }
  56866. }
  56867. function includeFile($file)
  56868. {
  56869. include $file;
  56870. }
  56871. <?php
  56872. namespace Doctrine\Common\Annotations;
  56873. class IndexedReader implements Reader
  56874. {
  56875. private $delegate;
  56876. public function __construct(Reader $reader)
  56877. {
  56878. $this->delegate = $reader;
  56879. }
  56880. public function getClassAnnotations(\ReflectionClass $class)
  56881. {
  56882. $annotations = array();
  56883. foreach ($this->delegate->getClassAnnotations($class) as $annot) {
  56884. $annotations[get_class($annot)] = $annot;
  56885. }
  56886. return $annotations;
  56887. }
  56888. public function getClassAnnotation(\ReflectionClass $class, $annotation)
  56889. {
  56890. return $this->delegate->getClassAnnotation($class, $annotation);
  56891. }
  56892. public function getMethodAnnotations(\ReflectionMethod $method)
  56893. {
  56894. $annotations = array();
  56895. foreach ($this->delegate->getMethodAnnotations($method) as $annot) {
  56896. $annotations[get_class($annot)] = $annot;
  56897. }
  56898. return $annotations;
  56899. }
  56900. public function getMethodAnnotation(\ReflectionMethod $method, $annotation)
  56901. {
  56902. return $this->delegate->getMethodAnnotation($method, $annotation);
  56903. }
  56904. public function getPropertyAnnotations(\ReflectionProperty $property)
  56905. {
  56906. $annotations = array();
  56907. foreach ($this->delegate->getPropertyAnnotations($property) as $annot) {
  56908. $annotations[get_class($annot)] = $annot;
  56909. }
  56910. return $annotations;
  56911. }
  56912. public function getPropertyAnnotation(\ReflectionProperty $property, $annotation)
  56913. {
  56914. return $this->delegate->getPropertyAnnotation($property, $annotation);
  56915. }
  56916. public function __call($method, $args)
  56917. {
  56918. return call_user_func_array(array($this->delegate, $method), $args);
  56919. }
  56920. }
  56921. <?php
  56922. namespace Doctrine\Common\Annotations;
  56923. interface Reader
  56924. {
  56925. function getClassAnnotations(\ReflectionClass $class);
  56926. function getClassAnnotation(\ReflectionClass $class, $annotationName);
  56927. function getMethodAnnotations(\ReflectionMethod $method);
  56928. function getMethodAnnotation(\ReflectionMethod $method, $annotationName);
  56929. function getPropertyAnnotations(\ReflectionProperty $property);
  56930. function getPropertyAnnotation(\ReflectionProperty $property, $annotationName);
  56931. }
  56932. <?php
  56933. namespace Doctrine\Common\Annotations;
  56934. /**
  56935. @mohiva
  56936. */
  56937. class TokenParser
  56938. {
  56939. private $tokens;
  56940. private $numTokens;
  56941. private $pointer = 0;
  56942. public function __construct($contents)
  56943. {
  56944. $this->tokens = token_get_all($contents);
  56945. token_get_all("<?php\n/**\n *\n */");
  56946. $this->numTokens = count($this->tokens);
  56947. }
  56948. public function next($docCommentIsComment = TRUE)
  56949. {
  56950. for ($i = $this->pointer; $i < $this->numTokens; $i++) {
  56951. $this->pointer++;
  56952. if ($this->tokens[$i][0] === T_WHITESPACE ||
  56953. $this->tokens[$i][0] === T_COMMENT ||
  56954. ($docCommentIsComment && $this->tokens[$i][0] === T_DOC_COMMENT)) {
  56955. continue;
  56956. }
  56957. return $this->tokens[$i];
  56958. }
  56959. return null;
  56960. }
  56961. public function parseUseStatement()
  56962. {
  56963. $groupRoot = '';
  56964. $class = '';
  56965. $alias = '';
  56966. $statements = array();
  56967. $explicitAlias = false;
  56968. while (($token = $this->next())) {
  56969. $isNameToken = $token[0] === T_STRING || $token[0] === T_NS_SEPARATOR;
  56970. if (!$explicitAlias && $isNameToken) {
  56971. $class .= $token[1];
  56972. $alias = $token[1];
  56973. } else if ($explicitAlias && $isNameToken) {
  56974. $alias .= $token[1];
  56975. } else if ($token[0] === T_AS) {
  56976. $explicitAlias = true;
  56977. $alias = '';
  56978. } else if ($token === ',') {
  56979. $statements[strtolower($alias)] = $groupRoot . $class;
  56980. $class = '';
  56981. $alias = '';
  56982. $explicitAlias = false;
  56983. } else if ($token === ';') {
  56984. $statements[strtolower($alias)] = $groupRoot . $class;
  56985. break;
  56986. } else if ($token === '{' ) {
  56987. $groupRoot = $class;
  56988. $class = '';
  56989. } else if ($token === '}' ) {
  56990. continue;
  56991. } else {
  56992. break;
  56993. }
  56994. }
  56995. return $statements;
  56996. }
  56997. public function parseUseStatements($namespaceName)
  56998. {
  56999. $statements = array();
  57000. while (($token = $this->next())) {
  57001. if ($token[0] === T_USE) {
  57002. $statements = array_merge($statements, $this->parseUseStatement());
  57003. continue;
  57004. }
  57005. if ($token[0] !== T_NAMESPACE || $this->parseNamespace() != $namespaceName) {
  57006. continue;
  57007. }
  57008. $statements = array();
  57009. }
  57010. return $statements;
  57011. }
  57012. public function parseNamespace()
  57013. {
  57014. $name = '';
  57015. while (($token = $this->next()) && ($token[0] === T_STRING || $token[0] === T_NS_SEPARATOR)) {
  57016. $name .= $token[1];
  57017. }
  57018. return $name;
  57019. }
  57020. public function parseClass()
  57021. {
  57022. return $this->parseNamespace();
  57023. }
  57024. }
  57025. <?php
  57026. namespace Doctrine\Common\Annotations;
  57027. use Doctrine\Common\Annotations\Annotation\IgnoreAnnotation;
  57028. use Doctrine\Common\Annotations\Annotation\Target;
  57029. use ReflectionClass;
  57030. use ReflectionMethod;
  57031. use ReflectionProperty;
  57032. /**
  57033. @hotmail
  57034. @gmail
  57035. @gmail
  57036. */
  57037. class AnnotationReader implements Reader
  57038. {
  57039. private static $globalImports = array(
  57040. 'ignoreannotation' => 'Doctrine\Common\Annotations\Annotation\IgnoreAnnotation',
  57041. );
  57042. private static $globalIgnoredNames = array(
  57043. 'Annotation' => true, 'Attribute' => true, 'Attributes' => true,
  57044. 'Required' => true,
  57045. 'Target' => true,
  57046. 'fix' => true , 'fixme' => true,
  57047. 'override' => true,
  57048. 'abstract'=> true, 'access'=> true,
  57049. 'code' => true,
  57050. 'deprec'=> true,
  57051. 'endcode' => true, 'exception'=> true,
  57052. 'final'=> true,
  57053. 'ingroup' => true, 'inheritdoc'=> true, 'inheritDoc'=> true,
  57054. 'magic' => true,
  57055. 'name'=> true,
  57056. 'toc' => true, 'tutorial'=> true,
  57057. 'private' => true,
  57058. 'static'=> true, 'staticvar'=> true, 'staticVar'=> true,
  57059. 'throw' => true,
  57060. 'api' => true, 'author'=> true,
  57061. 'category'=> true, 'copyright'=> true,
  57062. 'deprecated'=> true,
  57063. 'example'=> true,
  57064. 'filesource'=> true,
  57065. 'global'=> true,
  57066. 'ignore'=> true, 'internal'=> true,
  57067. 'license'=> true, 'link'=> true,
  57068. 'method' => true,
  57069. 'package'=> true, 'param'=> true, 'property' => true, 'property-read' => true, 'property-write' => true,
  57070. 'return'=> true,
  57071. 'see'=> true, 'since'=> true, 'source' => true, 'subpackage'=> true,
  57072. 'throws'=> true, 'todo'=> true, 'TODO'=> true,
  57073. 'usedby'=> true, 'uses' => true,
  57074. 'var'=> true, 'version'=> true,
  57075. 'codeCoverageIgnore' => true, 'codeCoverageIgnoreStart' => true, 'codeCoverageIgnoreEnd' => true,
  57076. 'SuppressWarnings' => true,
  57077. 'noinspection' => true,
  57078. 'package_version' => true,
  57079. 'startuml' => true, 'enduml' => true,
  57080. );
  57081. private static $globalIgnoredNamespaces = array();
  57082. static public function addGlobalIgnoredName($name)
  57083. {
  57084. self::$globalIgnoredNames[$name] = true;
  57085. }
  57086. static public function addGlobalIgnoredNamespace($namespace)
  57087. {
  57088. self::$globalIgnoredNamespaces[$namespace] = true;
  57089. }
  57090. private $parser;
  57091. private $preParser;
  57092. private $phpParser;
  57093. private $imports = array();
  57094. private $ignoredAnnotationNames = array();
  57095. public function __construct(DocParser $parser = null)
  57096. {
  57097. if (extension_loaded('Zend Optimizer+') && (ini_get('zend_optimizerplus.save_comments') === "0" || ini_get('opcache.save_comments') === "0")) {
  57098. throw AnnotationException::optimizerPlusSaveComments();
  57099. }
  57100. if (extension_loaded('Zend OPcache') && ini_get('opcache.save_comments') == 0) {
  57101. throw AnnotationException::optimizerPlusSaveComments();
  57102. }
  57103. if (PHP_VERSION_ID < 70000) {
  57104. if (extension_loaded('Zend Optimizer+') && (ini_get('zend_optimizerplus.load_comments') === "0" || ini_get('opcache.load_comments') === "0")) {
  57105. throw AnnotationException::optimizerPlusLoadComments();
  57106. }
  57107. if (extension_loaded('Zend OPcache') && ini_get('opcache.load_comments') == 0) {
  57108. throw AnnotationException::optimizerPlusLoadComments();
  57109. }
  57110. }
  57111. AnnotationRegistry::registerFile(__DIR__ . '/Annotation/IgnoreAnnotation.php');
  57112. $this->parser = $parser ?: new DocParser();
  57113. $this->preParser = new DocParser;
  57114. $this->preParser->setImports(self::$globalImports);
  57115. $this->preParser->setIgnoreNotImportedAnnotations(true);
  57116. $this->phpParser = new PhpParser;
  57117. }
  57118. public function getClassAnnotations(ReflectionClass $class)
  57119. {
  57120. $this->parser->setTarget(Target::TARGET_CLASS);
  57121. $this->parser->setImports($this->getClassImports($class));
  57122. $this->parser->setIgnoredAnnotationNames($this->getIgnoredAnnotationNames($class));
  57123. $this->parser->setIgnoredAnnotationNamespaces(self::$globalIgnoredNamespaces);
  57124. return $this->parser->parse($class->getDocComment(), 'class ' . $class->getName());
  57125. }
  57126. public function getClassAnnotation(ReflectionClass $class, $annotationName)
  57127. {
  57128. $annotations = $this->getClassAnnotations($class);
  57129. foreach ($annotations as $annotation) {
  57130. if ($annotation instanceof $annotationName) {
  57131. return $annotation;
  57132. }
  57133. }
  57134. return null;
  57135. }
  57136. public function getPropertyAnnotations(ReflectionProperty $property)
  57137. {
  57138. $class = $property->getDeclaringClass();
  57139. $context = 'property ' . $class->getName() . "::\$" . $property->getName();
  57140. $this->parser->setTarget(Target::TARGET_PROPERTY);
  57141. $this->parser->setImports($this->getPropertyImports($property));
  57142. $this->parser->setIgnoredAnnotationNames($this->getIgnoredAnnotationNames($class));
  57143. $this->parser->setIgnoredAnnotationNamespaces(self::$globalIgnoredNamespaces);
  57144. return $this->parser->parse($property->getDocComment(), $context);
  57145. }
  57146. public function getPropertyAnnotation(ReflectionProperty $property, $annotationName)
  57147. {
  57148. $annotations = $this->getPropertyAnnotations($property);
  57149. foreach ($annotations as $annotation) {
  57150. if ($annotation instanceof $annotationName) {
  57151. return $annotation;
  57152. }
  57153. }
  57154. return null;
  57155. }
  57156. public function getMethodAnnotations(ReflectionMethod $method)
  57157. {
  57158. $class = $method->getDeclaringClass();
  57159. $context = 'method ' . $class->getName() . '::' . $method->getName() . '()';
  57160. $this->parser->setTarget(Target::TARGET_METHOD);
  57161. $this->parser->setImports($this->getMethodImports($method));
  57162. $this->parser->setIgnoredAnnotationNames($this->getIgnoredAnnotationNames($class));
  57163. $this->parser->setIgnoredAnnotationNamespaces(self::$globalIgnoredNamespaces);
  57164. return $this->parser->parse($method->getDocComment(), $context);
  57165. }
  57166. public function getMethodAnnotation(ReflectionMethod $method, $annotationName)
  57167. {
  57168. $annotations = $this->getMethodAnnotations($method);
  57169. foreach ($annotations as $annotation) {
  57170. if ($annotation instanceof $annotationName) {
  57171. return $annotation;
  57172. }
  57173. }
  57174. return null;
  57175. }
  57176. private function getIgnoredAnnotationNames(ReflectionClass $class)
  57177. {
  57178. $name = $class->getName();
  57179. if (isset($this->ignoredAnnotationNames[$name])) {
  57180. return $this->ignoredAnnotationNames[$name];
  57181. }
  57182. $this->collectParsingMetadata($class);
  57183. return $this->ignoredAnnotationNames[$name];
  57184. }
  57185. private function getClassImports(ReflectionClass $class)
  57186. {
  57187. $name = $class->getName();
  57188. if (isset($this->imports[$name])) {
  57189. return $this->imports[$name];
  57190. }
  57191. $this->collectParsingMetadata($class);
  57192. return $this->imports[$name];
  57193. }
  57194. private function getMethodImports(ReflectionMethod $method)
  57195. {
  57196. $class = $method->getDeclaringClass();
  57197. $classImports = $this->getClassImports($class);
  57198. if (!method_exists($class, 'getTraits')) {
  57199. return $classImports;
  57200. }
  57201. $traitImports = array();
  57202. foreach ($class->getTraits() as $trait) {
  57203. if ($trait->hasMethod($method->getName())
  57204. && $trait->getFileName() === $method->getFileName()
  57205. ) {
  57206. $traitImports = array_merge($traitImports, $this->phpParser->parseClass($trait));
  57207. }
  57208. }
  57209. return array_merge($classImports, $traitImports);
  57210. }
  57211. private function getPropertyImports(ReflectionProperty $property)
  57212. {
  57213. $class = $property->getDeclaringClass();
  57214. $classImports = $this->getClassImports($class);
  57215. if (!method_exists($class, 'getTraits')) {
  57216. return $classImports;
  57217. }
  57218. $traitImports = array();
  57219. foreach ($class->getTraits() as $trait) {
  57220. if ($trait->hasProperty($property->getName())) {
  57221. $traitImports = array_merge($traitImports, $this->phpParser->parseClass($trait));
  57222. }
  57223. }
  57224. return array_merge($classImports, $traitImports);
  57225. }
  57226. private function collectParsingMetadata(ReflectionClass $class)
  57227. {
  57228. $ignoredAnnotationNames = self::$globalIgnoredNames;
  57229. $annotations = $this->preParser->parse($class->getDocComment(), 'class ' . $class->name);
  57230. foreach ($annotations as $annotation) {
  57231. if ($annotation instanceof IgnoreAnnotation) {
  57232. foreach ($annotation->names AS $annot) {
  57233. $ignoredAnnotationNames[$annot] = true;
  57234. }
  57235. }
  57236. }
  57237. $name = $class->getName();
  57238. $this->imports[$name] = array_merge(
  57239. self::$globalImports,
  57240. $this->phpParser->parseClass($class),
  57241. array('__NAMESPACE__' => $class->getNamespaceName())
  57242. );
  57243. $this->ignoredAnnotationNames[$name] = $ignoredAnnotationNames;
  57244. }
  57245. }
  57246. <?php
  57247. namespace Doctrine\Common\Annotations\Annotation;
  57248. final class Required
  57249. {
  57250. }
  57251. <?php
  57252. namespace Doctrine\Common\Annotations\Annotation;
  57253. final class IgnoreAnnotation
  57254. {
  57255. public $names;
  57256. public function __construct(array $values)
  57257. {
  57258. if (is_string($values['value'])) {
  57259. $values['value'] = array($values['value']);
  57260. }
  57261. if (!is_array($values['value'])) {
  57262. throw new \RuntimeException(sprintf('@IgnoreAnnotation expects either a string name, or an array of strings, but got %s.', json_encode($values['value'])));
  57263. }
  57264. $this->names = $values['value'];
  57265. }
  57266. }
  57267. <?php
  57268. namespace Doctrine\Common\Annotations\Annotation;
  57269. final class Attribute
  57270. {
  57271. public $name;
  57272. public $type;
  57273. public $required = false;
  57274. }
  57275. <?php
  57276. namespace Doctrine\Common\Annotations\Annotation;
  57277. final class Attributes
  57278. {
  57279. public $value;
  57280. }
  57281. <?php
  57282. namespace Doctrine\Common\Annotations\Annotation;
  57283. /**
  57284. @Attributes({@Attribute("value",required=true,type="array"),@Attribute("literal",required=false,type="array")})
  57285. */
  57286. final class Enum
  57287. {
  57288. public $value;
  57289. public $literal;
  57290. public function __construct(array $values)
  57291. {
  57292. if ( ! isset($values['literal'])) {
  57293. $values['literal'] = array();
  57294. }
  57295. foreach ($values['value'] as $var) {
  57296. if( ! is_scalar($var)) {
  57297. throw new \InvalidArgumentException(sprintf(
  57298. '@Enum supports only scalar values "%s" given.',
  57299. is_object($var) ? get_class($var) : gettype($var)
  57300. ));
  57301. }
  57302. }
  57303. foreach ($values['literal'] as $key => $var) {
  57304. if( ! in_array($key, $values['value'])) {
  57305. throw new \InvalidArgumentException(sprintf(
  57306. 'Undefined enumerator value "%s" for literal "%s".',
  57307. $key , $var
  57308. ));
  57309. }
  57310. }
  57311. $this->value = $values['value'];
  57312. $this->literal = $values['literal'];
  57313. }
  57314. }
  57315. <?php
  57316. namespace Doctrine\Common\Annotations\Annotation;
  57317. final class Target
  57318. {
  57319. const TARGET_CLASS = 1;
  57320. const TARGET_METHOD = 2;
  57321. const TARGET_PROPERTY = 4;
  57322. const TARGET_ANNOTATION = 8;
  57323. const TARGET_ALL = 15;
  57324. private static $map = array(
  57325. 'ALL' => self::TARGET_ALL,
  57326. 'CLASS' => self::TARGET_CLASS,
  57327. 'METHOD' => self::TARGET_METHOD,
  57328. 'PROPERTY' => self::TARGET_PROPERTY,
  57329. 'ANNOTATION' => self::TARGET_ANNOTATION,
  57330. );
  57331. public $value;
  57332. public $targets;
  57333. public $literal;
  57334. public function __construct(array $values)
  57335. {
  57336. if (!isset($values['value'])){
  57337. $values['value'] = null;
  57338. }
  57339. if (is_string($values['value'])){
  57340. $values['value'] = array($values['value']);
  57341. }
  57342. if (!is_array($values['value'])){
  57343. throw new \InvalidArgumentException(
  57344. sprintf('@Target expects either a string value, or an array of strings, "%s" given.',
  57345. is_object($values['value']) ? get_class($values['value']) : gettype($values['value'])
  57346. )
  57347. );
  57348. }
  57349. $bitmask = 0;
  57350. foreach ($values['value'] as $literal) {
  57351. if(!isset(self::$map[$literal])){
  57352. throw new \InvalidArgumentException(
  57353. sprintf('Invalid Target "%s". Available targets: [%s]',
  57354. $literal, implode(', ', array_keys(self::$map)))
  57355. );
  57356. }
  57357. $bitmask |= self::$map[$literal];
  57358. }
  57359. $this->targets = $bitmask;
  57360. $this->value = $values['value'];
  57361. $this->literal = implode(', ', $this->value);
  57362. }
  57363. }
  57364. <?php
  57365. namespace Doctrine\Common\Annotations;
  57366. /**
  57367. @beberlei
  57368. */
  57369. class FileCacheReader implements Reader
  57370. {
  57371. private $reader;
  57372. private $dir;
  57373. private $debug;
  57374. private $loadedAnnotations = array();
  57375. private $classNameHashes = array();
  57376. private $umask;
  57377. public function __construct(Reader $reader, $cacheDir, $debug = false, $umask = 0002)
  57378. {
  57379. if ( ! is_int($umask)) {
  57380. throw new \InvalidArgumentException(sprintf(
  57381. 'The parameter umask must be an integer, was: %s',
  57382. gettype($umask)
  57383. ));
  57384. }
  57385. $this->reader = $reader;
  57386. $this->umask = $umask;
  57387. if (!is_dir($cacheDir) && !@mkdir($cacheDir, 0777 & (~$this->umask), true)) {
  57388. throw new \InvalidArgumentException(sprintf('The directory "%s" does not exist and could not be created.', $cacheDir));
  57389. }
  57390. $this->dir = rtrim($cacheDir, '\\/');
  57391. $this->debug = $debug;
  57392. }
  57393. public function getClassAnnotations(\ReflectionClass $class)
  57394. {
  57395. if ( ! isset($this->classNameHashes[$class->name])) {
  57396. $this->classNameHashes[$class->name] = sha1($class->name);
  57397. }
  57398. $key = $this->classNameHashes[$class->name];
  57399. if (isset($this->loadedAnnotations[$key])) {
  57400. return $this->loadedAnnotations[$key];
  57401. }
  57402. $path = $this->dir.'/'.strtr($key, '\\', '-').'.cache.php';
  57403. if (!is_file($path)) {
  57404. $annot = $this->reader->getClassAnnotations($class);
  57405. $this->saveCacheFile($path, $annot);
  57406. return $this->loadedAnnotations[$key] = $annot;
  57407. }
  57408. if ($this->debug
  57409. && (false !== $filename = $class->getFileName())
  57410. && filemtime($path) < filemtime($filename)) {
  57411. @unlink($path);
  57412. $annot = $this->reader->getClassAnnotations($class);
  57413. $this->saveCacheFile($path, $annot);
  57414. return $this->loadedAnnotations[$key] = $annot;
  57415. }
  57416. return $this->loadedAnnotations[$key] = include $path;
  57417. }
  57418. public function getPropertyAnnotations(\ReflectionProperty $property)
  57419. {
  57420. $class = $property->getDeclaringClass();
  57421. if ( ! isset($this->classNameHashes[$class->name])) {
  57422. $this->classNameHashes[$class->name] = sha1($class->name);
  57423. }
  57424. $key = $this->classNameHashes[$class->name].'$'.$property->getName();
  57425. if (isset($this->loadedAnnotations[$key])) {
  57426. return $this->loadedAnnotations[$key];
  57427. }
  57428. $path = $this->dir.'/'.strtr($key, '\\', '-').'.cache.php';
  57429. if (!is_file($path)) {
  57430. $annot = $this->reader->getPropertyAnnotations($property);
  57431. $this->saveCacheFile($path, $annot);
  57432. return $this->loadedAnnotations[$key] = $annot;
  57433. }
  57434. if ($this->debug
  57435. && (false !== $filename = $class->getFilename())
  57436. && filemtime($path) < filemtime($filename)) {
  57437. @unlink($path);
  57438. $annot = $this->reader->getPropertyAnnotations($property);
  57439. $this->saveCacheFile($path, $annot);
  57440. return $this->loadedAnnotations[$key] = $annot;
  57441. }
  57442. return $this->loadedAnnotations[$key] = include $path;
  57443. }
  57444. public function getMethodAnnotations(\ReflectionMethod $method)
  57445. {
  57446. $class = $method->getDeclaringClass();
  57447. if ( ! isset($this->classNameHashes[$class->name])) {
  57448. $this->classNameHashes[$class->name] = sha1($class->name);
  57449. }
  57450. $key = $this->classNameHashes[$class->name].'#'.$method->getName();
  57451. if (isset($this->loadedAnnotations[$key])) {
  57452. return $this->loadedAnnotations[$key];
  57453. }
  57454. $path = $this->dir.'/'.strtr($key, '\\', '-').'.cache.php';
  57455. if (!is_file($path)) {
  57456. $annot = $this->reader->getMethodAnnotations($method);
  57457. $this->saveCacheFile($path, $annot);
  57458. return $this->loadedAnnotations[$key] = $annot;
  57459. }
  57460. if ($this->debug
  57461. && (false !== $filename = $class->getFilename())
  57462. && filemtime($path) < filemtime($filename)) {
  57463. @unlink($path);
  57464. $annot = $this->reader->getMethodAnnotations($method);
  57465. $this->saveCacheFile($path, $annot);
  57466. return $this->loadedAnnotations[$key] = $annot;
  57467. }
  57468. return $this->loadedAnnotations[$key] = include $path;
  57469. }
  57470. private function saveCacheFile($path, $data)
  57471. {
  57472. if (!is_writable($this->dir)) {
  57473. throw new \InvalidArgumentException(sprintf('The directory "%s" is not writable. Both, the webserver and the console user need access. You can manage access rights for multiple users with "chmod +a". If your system does not support this, check out the acl package.', $this->dir));
  57474. }
  57475. $tempfile = tempnam($this->dir, uniqid('', true));
  57476. if (false === $tempfile) {
  57477. throw new \RuntimeException(sprintf('Unable to create tempfile in directory: %s', $this->dir));
  57478. }
  57479. @chmod($tempfile, 0666 & (~$this->umask));
  57480. $written = file_put_contents($tempfile, '<?php return unserialize('.var_export(serialize($data), true).');');
  57481. if (false === $written) {
  57482. throw new \RuntimeException(sprintf('Unable to write cached file to: %s', $tempfile));
  57483. }
  57484. @chmod($tempfile, 0666 & (~$this->umask));
  57485. if (false === rename($tempfile, $path)) {
  57486. @unlink($tempfile);
  57487. throw new \RuntimeException(sprintf('Unable to rename %s to %s', $tempfile, $path));
  57488. }
  57489. }
  57490. public function getClassAnnotation(\ReflectionClass $class, $annotationName)
  57491. {
  57492. $annotations = $this->getClassAnnotations($class);
  57493. foreach ($annotations as $annotation) {
  57494. if ($annotation instanceof $annotationName) {
  57495. return $annotation;
  57496. }
  57497. }
  57498. return null;
  57499. }
  57500. public function getMethodAnnotation(\ReflectionMethod $method, $annotationName)
  57501. {
  57502. $annotations = $this->getMethodAnnotations($method);
  57503. foreach ($annotations as $annotation) {
  57504. if ($annotation instanceof $annotationName) {
  57505. return $annotation;
  57506. }
  57507. }
  57508. return null;
  57509. }
  57510. public function getPropertyAnnotation(\ReflectionProperty $property, $annotationName)
  57511. {
  57512. $annotations = $this->getPropertyAnnotations($property);
  57513. foreach ($annotations as $annotation) {
  57514. if ($annotation instanceof $annotationName) {
  57515. return $annotation;
  57516. }
  57517. }
  57518. return null;
  57519. }
  57520. public function clearLoadedAnnotations()
  57521. {
  57522. $this->loadedAnnotations = array();
  57523. }
  57524. }
  57525. <?php
  57526. namespace Doctrine\Common\Annotations;
  57527. use SplFileObject;
  57528. /**
  57529. @mohiva
  57530. */
  57531. final class PhpParser
  57532. {
  57533. public function parseClass(\ReflectionClass $class)
  57534. {
  57535. if (method_exists($class, 'getUseStatements')) {
  57536. return $class->getUseStatements();
  57537. }
  57538. if (false === $filename = $class->getFileName()) {
  57539. return array();
  57540. }
  57541. $content = $this->getFileContent($filename, $class->getStartLine());
  57542. if (null === $content) {
  57543. return array();
  57544. }
  57545. $namespace = preg_quote($class->getNamespaceName());
  57546. $content = preg_replace('/^.*?(\bnamespace\s+' . $namespace . '\s*[;{].*)$/s', '\\1', $content);
  57547. $tokenizer = new TokenParser('<?php ' . $content);
  57548. $statements = $tokenizer->parseUseStatements($class->getNamespaceName());
  57549. return $statements;
  57550. }
  57551. private function getFileContent($filename, $lineNumber)
  57552. {
  57553. if ( ! is_file($filename)) {
  57554. return null;
  57555. }
  57556. $content = '';
  57557. $lineCnt = 0;
  57558. $file = new SplFileObject($filename);
  57559. while (!$file->eof()) {
  57560. if ($lineCnt++ == $lineNumber) {
  57561. break;
  57562. }
  57563. $content .= $file->fgets();
  57564. }
  57565. return $content;
  57566. }
  57567. }
  57568. <?php
  57569. namespace Doctrine\Common\Annotations;
  57570. use Doctrine\Common\Lexer\AbstractLexer;
  57571. /**
  57572. @hotmail
  57573. @gmail
  57574. @gmail
  57575. */
  57576. final class DocLexer extends AbstractLexer
  57577. {
  57578. const T_NONE = 1;
  57579. const T_INTEGER = 2;
  57580. const T_STRING = 3;
  57581. const T_FLOAT = 4;
  57582. const T_IDENTIFIER = 100;
  57583. const T_AT = 101;
  57584. const T_CLOSE_CURLY_BRACES = 102;
  57585. const T_CLOSE_PARENTHESIS = 103;
  57586. const T_COMMA = 104;
  57587. const T_EQUALS = 105;
  57588. const T_FALSE = 106;
  57589. const T_NAMESPACE_SEPARATOR = 107;
  57590. const T_OPEN_CURLY_BRACES = 108;
  57591. const T_OPEN_PARENTHESIS = 109;
  57592. const T_TRUE = 110;
  57593. const T_NULL = 111;
  57594. const T_COLON = 112;
  57595. protected $noCase = array(
  57596. '@' => self::T_AT,
  57597. ',' => self::T_COMMA,
  57598. '(' => self::T_OPEN_PARENTHESIS,
  57599. ')' => self::T_CLOSE_PARENTHESIS,
  57600. '{' => self::T_OPEN_CURLY_BRACES,
  57601. '}' => self::T_CLOSE_CURLY_BRACES,
  57602. '=' => self::T_EQUALS,
  57603. ':' => self::T_COLON,
  57604. '\\' => self::T_NAMESPACE_SEPARATOR
  57605. );
  57606. protected $withCase = array(
  57607. 'true' => self::T_TRUE,
  57608. 'false' => self::T_FALSE,
  57609. 'null' => self::T_NULL
  57610. );
  57611. protected function getCatchablePatterns()
  57612. {
  57613. return array(
  57614. '[a-z_\\\][a-z0-9_\:\\\]*[a-z_][a-z0-9_]*',
  57615. '(?:[+-]?[0-9]+(?:[\.][0-9]+)*)(?:[eE][+-]?[0-9]+)?',
  57616. '"(?:""|[^"])*+"',
  57617. );
  57618. }
  57619. protected function getNonCatchablePatterns()
  57620. {
  57621. return array('\s+', '\*+', '(.)');
  57622. }
  57623. protected function getType(&$value)
  57624. {
  57625. $type = self::T_NONE;
  57626. if ($value[0] === '"') {
  57627. $value = str_replace('""', '"', substr($value, 1, strlen($value) - 2));
  57628. return self::T_STRING;
  57629. }
  57630. if (isset($this->noCase[$value])) {
  57631. return $this->noCase[$value];
  57632. }
  57633. if ($value[0] === '_' || $value[0] === '\\' || ctype_alpha($value[0])) {
  57634. return self::T_IDENTIFIER;
  57635. }
  57636. $lowerValue = strtolower($value);
  57637. if (isset($this->withCase[$lowerValue])) {
  57638. return $this->withCase[$lowerValue];
  57639. }
  57640. if (is_numeric($value)) {
  57641. return (strpos($value, '.') !== false || stripos($value, 'e') !== false)
  57642. ? self::T_FLOAT : self::T_INTEGER;
  57643. }
  57644. return $type;
  57645. }
  57646. }
  57647. <?php
  57648. namespace Doctrine\Common\Annotations;
  57649. use Doctrine\Common\Cache\Cache;
  57650. use ReflectionClass;
  57651. /**
  57652. @beberlei
  57653. */
  57654. final class CachedReader implements Reader
  57655. {
  57656. private $delegate;
  57657. private $cache;
  57658. private $debug;
  57659. private $loadedAnnotations = array();
  57660. public function __construct(Reader $reader, Cache $cache, $debug = false)
  57661. {
  57662. $this->delegate = $reader;
  57663. $this->cache = $cache;
  57664. $this->debug = (boolean) $debug;
  57665. }
  57666. public function getClassAnnotations(ReflectionClass $class)
  57667. {
  57668. $cacheKey = $class->getName();
  57669. if (isset($this->loadedAnnotations[$cacheKey])) {
  57670. return $this->loadedAnnotations[$cacheKey];
  57671. }
  57672. if (false === ($annots = $this->fetchFromCache($cacheKey, $class))) {
  57673. $annots = $this->delegate->getClassAnnotations($class);
  57674. $this->saveToCache($cacheKey, $annots);
  57675. }
  57676. return $this->loadedAnnotations[$cacheKey] = $annots;
  57677. }
  57678. public function getClassAnnotation(ReflectionClass $class, $annotationName)
  57679. {
  57680. foreach ($this->getClassAnnotations($class) as $annot) {
  57681. if ($annot instanceof $annotationName) {
  57682. return $annot;
  57683. }
  57684. }
  57685. return null;
  57686. }
  57687. public function getPropertyAnnotations(\ReflectionProperty $property)
  57688. {
  57689. $class = $property->getDeclaringClass();
  57690. $cacheKey = $class->getName().'$'.$property->getName();
  57691. if (isset($this->loadedAnnotations[$cacheKey])) {
  57692. return $this->loadedAnnotations[$cacheKey];
  57693. }
  57694. if (false === ($annots = $this->fetchFromCache($cacheKey, $class))) {
  57695. $annots = $this->delegate->getPropertyAnnotations($property);
  57696. $this->saveToCache($cacheKey, $annots);
  57697. }
  57698. return $this->loadedAnnotations[$cacheKey] = $annots;
  57699. }
  57700. public function getPropertyAnnotation(\ReflectionProperty $property, $annotationName)
  57701. {
  57702. foreach ($this->getPropertyAnnotations($property) as $annot) {
  57703. if ($annot instanceof $annotationName) {
  57704. return $annot;
  57705. }
  57706. }
  57707. return null;
  57708. }
  57709. public function getMethodAnnotations(\ReflectionMethod $method)
  57710. {
  57711. $class = $method->getDeclaringClass();
  57712. $cacheKey = $class->getName().'#'.$method->getName();
  57713. if (isset($this->loadedAnnotations[$cacheKey])) {
  57714. return $this->loadedAnnotations[$cacheKey];
  57715. }
  57716. if (false === ($annots = $this->fetchFromCache($cacheKey, $class))) {
  57717. $annots = $this->delegate->getMethodAnnotations($method);
  57718. $this->saveToCache($cacheKey, $annots);
  57719. }
  57720. return $this->loadedAnnotations[$cacheKey] = $annots;
  57721. }
  57722. public function getMethodAnnotation(\ReflectionMethod $method, $annotationName)
  57723. {
  57724. foreach ($this->getMethodAnnotations($method) as $annot) {
  57725. if ($annot instanceof $annotationName) {
  57726. return $annot;
  57727. }
  57728. }
  57729. return null;
  57730. }
  57731. public function clearLoadedAnnotations()
  57732. {
  57733. $this->loadedAnnotations = array();
  57734. }
  57735. private function fetchFromCache($cacheKey, ReflectionClass $class)
  57736. {
  57737. if (($data = $this->cache->fetch($cacheKey)) !== false) {
  57738. if (!$this->debug || $this->isCacheFresh($cacheKey, $class)) {
  57739. return $data;
  57740. }
  57741. }
  57742. return false;
  57743. }
  57744. private function saveToCache($cacheKey, $value)
  57745. {
  57746. $this->cache->save($cacheKey, $value);
  57747. if ($this->debug) {
  57748. $this->cache->save('[C]'.$cacheKey, time());
  57749. }
  57750. }
  57751. private function isCacheFresh($cacheKey, ReflectionClass $class)
  57752. {
  57753. if (null === $lastModification = $this->getLastModification($class)) {
  57754. return true;
  57755. }
  57756. return $this->cache->fetch('[C]'.$cacheKey) >= $lastModification;
  57757. }
  57758. private function getLastModification(ReflectionClass $class)
  57759. {
  57760. $filename = $class->getFileName();
  57761. $parent = $class->getParentClass();
  57762. return max(array_merge(
  57763. [$filename ? filemtime($filename) : 0],
  57764. array_map([$this, 'getTraitLastModificationTime'], $class->getTraits()),
  57765. array_map([$this, 'getLastModification'], $class->getInterfaces()),
  57766. $parent ? [$this->getLastModification($parent)] : []
  57767. ));
  57768. }
  57769. private function getTraitLastModificationTime(ReflectionClass $reflectionTrait)
  57770. {
  57771. $fileName = $reflectionTrait->getFileName();
  57772. return max(array_merge(
  57773. [$fileName ? filemtime($fileName) : 0],
  57774. array_map([$this, 'getTraitLastModificationTime'], $reflectionTrait->getTraits())
  57775. ));
  57776. }
  57777. }
  57778. <?php
  57779. namespace Doctrine\Common\Annotations;
  57780. /**
  57781. @hotmail
  57782. @gmail
  57783. */
  57784. class AnnotationException extends \Exception
  57785. {
  57786. public static function syntaxError($message)
  57787. {
  57788. return new self('[Syntax Error] ' . $message);
  57789. }
  57790. public static function semanticalError($message)
  57791. {
  57792. return new self('[Semantical Error] ' . $message);
  57793. }
  57794. public static function creationError($message)
  57795. {
  57796. return new self('[Creation Error] ' . $message);
  57797. }
  57798. public static function typeError($message)
  57799. {
  57800. return new self('[Type Error] ' . $message);
  57801. }
  57802. public static function semanticalErrorConstants($identifier, $context = null)
  57803. {
  57804. return self::semanticalError(sprintf(
  57805. "Couldn't find constant %s%s.",
  57806. $identifier,
  57807. $context ? ', ' . $context : ''
  57808. ));
  57809. }
  57810. public static function attributeTypeError($attributeName, $annotationName, $context, $expected, $actual)
  57811. {
  57812. return self::typeError(sprintf(
  57813. 'Attribute "%s" of @%s declared on %s expects %s, but got %s.',
  57814. $attributeName,
  57815. $annotationName,
  57816. $context,
  57817. $expected,
  57818. is_object($actual) ? 'an instance of ' . get_class($actual) : gettype($actual)
  57819. ));
  57820. }
  57821. public static function requiredError($attributeName, $annotationName, $context, $expected)
  57822. {
  57823. return self::typeError(sprintf(
  57824. 'Attribute "%s" of @%s declared on %s expects %s. This value should not be null.',
  57825. $attributeName,
  57826. $annotationName,
  57827. $context,
  57828. $expected
  57829. ));
  57830. }
  57831. public static function enumeratorError($attributeName, $annotationName, $context, $available, $given)
  57832. {
  57833. return new self(sprintf(
  57834. '[Enum Error] Attribute "%s" of @%s declared on %s accept only [%s], but got %s.',
  57835. $attributeName,
  57836. $annotationName,
  57837. $context,
  57838. implode(', ', $available),
  57839. is_object($given) ? get_class($given) : $given
  57840. ));
  57841. }
  57842. public static function optimizerPlusSaveComments()
  57843. {
  57844. return new self(
  57845. "You have to enable opcache.save_comments=1 or zend_optimizerplus.save_comments=1."
  57846. );
  57847. }
  57848. public static function optimizerPlusLoadComments()
  57849. {
  57850. return new self(
  57851. "You have to enable opcache.load_comments=1 or zend_optimizerplus.load_comments=1."
  57852. );
  57853. }
  57854. }
  57855. <?php
  57856. namespace Doctrine\Common\Annotations;
  57857. use Doctrine\Common\Annotations\Annotation\Attribute;
  57858. use ReflectionClass;
  57859. use Doctrine\Common\Annotations\Annotation\Enum;
  57860. use Doctrine\Common\Annotations\Annotation\Target;
  57861. use Doctrine\Common\Annotations\Annotation\Attributes;
  57862. /**
  57863. @hotmail
  57864. @gmail
  57865. @gmail
  57866. @gmail
  57867. */
  57868. final class DocParser
  57869. {
  57870. private static $classIdentifiers = array(
  57871. DocLexer::T_IDENTIFIER,
  57872. DocLexer::T_TRUE,
  57873. DocLexer::T_FALSE,
  57874. DocLexer::T_NULL
  57875. );
  57876. private $lexer;
  57877. private $target;
  57878. private static $metadataParser;
  57879. private $isNestedAnnotation = false;
  57880. private $imports = array();
  57881. private $classExists = array();
  57882. private $ignoreNotImportedAnnotations = false;
  57883. private $namespaces = array();
  57884. private $ignoredAnnotationNames = array();
  57885. private $ignoredAnnotationNamespaces = array();
  57886. private $context = '';
  57887. private static $annotationMetadata = array(
  57888. 'Doctrine\Common\Annotations\Annotation\Target' => array(
  57889. 'is_annotation' => true,
  57890. 'has_constructor' => true,
  57891. 'properties' => array(),
  57892. 'targets_literal' => 'ANNOTATION_CLASS',
  57893. 'targets' => Target::TARGET_CLASS,
  57894. 'default_property' => 'value',
  57895. 'attribute_types' => array(
  57896. 'value' => array(
  57897. 'required' => false,
  57898. 'type' =>'array',
  57899. 'array_type'=>'string',
  57900. 'value' =>'array<string>'
  57901. )
  57902. ),
  57903. ),
  57904. 'Doctrine\Common\Annotations\Annotation\Attribute' => array(
  57905. 'is_annotation' => true,
  57906. 'has_constructor' => false,
  57907. 'targets_literal' => 'ANNOTATION_ANNOTATION',
  57908. 'targets' => Target::TARGET_ANNOTATION,
  57909. 'default_property' => 'name',
  57910. 'properties' => array(
  57911. 'name' => 'name',
  57912. 'type' => 'type',
  57913. 'required' => 'required'
  57914. ),
  57915. 'attribute_types' => array(
  57916. 'value' => array(
  57917. 'required' => true,
  57918. 'type' =>'string',
  57919. 'value' =>'string'
  57920. ),
  57921. 'type' => array(
  57922. 'required' =>true,
  57923. 'type' =>'string',
  57924. 'value' =>'string'
  57925. ),
  57926. 'required' => array(
  57927. 'required' =>false,
  57928. 'type' =>'boolean',
  57929. 'value' =>'boolean'
  57930. )
  57931. ),
  57932. ),
  57933. 'Doctrine\Common\Annotations\Annotation\Attributes' => array(
  57934. 'is_annotation' => true,
  57935. 'has_constructor' => false,
  57936. 'targets_literal' => 'ANNOTATION_CLASS',
  57937. 'targets' => Target::TARGET_CLASS,
  57938. 'default_property' => 'value',
  57939. 'properties' => array(
  57940. 'value' => 'value'
  57941. ),
  57942. 'attribute_types' => array(
  57943. 'value' => array(
  57944. 'type' =>'array',
  57945. 'required' =>true,
  57946. 'array_type'=>'Doctrine\Common\Annotations\Annotation\Attribute',
  57947. 'value' =>'array<Doctrine\Common\Annotations\Annotation\Attribute>'
  57948. )
  57949. ),
  57950. ),
  57951. 'Doctrine\Common\Annotations\Annotation\Enum' => array(
  57952. 'is_annotation' => true,
  57953. 'has_constructor' => true,
  57954. 'targets_literal' => 'ANNOTATION_PROPERTY',
  57955. 'targets' => Target::TARGET_PROPERTY,
  57956. 'default_property' => 'value',
  57957. 'properties' => array(
  57958. 'value' => 'value'
  57959. ),
  57960. 'attribute_types' => array(
  57961. 'value' => array(
  57962. 'type' => 'array',
  57963. 'required' => true,
  57964. ),
  57965. 'literal' => array(
  57966. 'type' => 'array',
  57967. 'required' => false,
  57968. ),
  57969. ),
  57970. ),
  57971. );
  57972. private static $typeMap = array(
  57973. 'float' => 'double',
  57974. 'bool' => 'boolean',
  57975. 'Boolean' => 'boolean',
  57976. 'int' => 'integer',
  57977. );
  57978. public function __construct()
  57979. {
  57980. $this->lexer = new DocLexer;
  57981. }
  57982. public function setIgnoredAnnotationNames(array $names)
  57983. {
  57984. $this->ignoredAnnotationNames = $names;
  57985. }
  57986. public function setIgnoredAnnotationNamespaces($ignoredAnnotationNamespaces)
  57987. {
  57988. $this->ignoredAnnotationNamespaces = $ignoredAnnotationNamespaces;
  57989. }
  57990. public function setIgnoreNotImportedAnnotations($bool)
  57991. {
  57992. $this->ignoreNotImportedAnnotations = (boolean) $bool;
  57993. }
  57994. public function addNamespace($namespace)
  57995. {
  57996. if ($this->imports) {
  57997. throw new \RuntimeException('You must either use addNamespace(), or setImports(), but not both.');
  57998. }
  57999. $this->namespaces[] = $namespace;
  58000. }
  58001. public function setImports(array $imports)
  58002. {
  58003. if ($this->namespaces) {
  58004. throw new \RuntimeException('You must either use addNamespace(), or setImports(), but not both.');
  58005. }
  58006. $this->imports = $imports;
  58007. }
  58008. public function setTarget($target)
  58009. {
  58010. $this->target = $target;
  58011. }
  58012. public function parse($input, $context = '')
  58013. {
  58014. $pos = $this->findInitialTokenPosition($input);
  58015. if ($pos === null) {
  58016. return array();
  58017. }
  58018. $this->context = $context;
  58019. $this->lexer->setInput(trim(substr($input, $pos), '* /'));
  58020. $this->lexer->moveNext();
  58021. return $this->Annotations();
  58022. }
  58023. private function findInitialTokenPosition($input)
  58024. {
  58025. $pos = 0;
  58026. while (($pos = strpos($input, '@', $pos)) !== false) {
  58027. $preceding = substr($input, $pos - 1, 1);
  58028. if ($pos === 0 || $preceding === ' ' || $preceding === '*' || $preceding === "\t") {
  58029. return $pos;
  58030. }
  58031. $pos++;
  58032. }
  58033. return null;
  58034. }
  58035. private function match($token)
  58036. {
  58037. if ( ! $this->lexer->isNextToken($token) ) {
  58038. $this->syntaxError($this->lexer->getLiteral($token));
  58039. }
  58040. return $this->lexer->moveNext();
  58041. }
  58042. private function matchAny(array $tokens)
  58043. {
  58044. if ( ! $this->lexer->isNextTokenAny($tokens)) {
  58045. $this->syntaxError(implode(' or ', array_map(array($this->lexer, 'getLiteral'), $tokens)));
  58046. }
  58047. return $this->lexer->moveNext();
  58048. }
  58049. private function syntaxError($expected, $token = null)
  58050. {
  58051. if ($token === null) {
  58052. $token = $this->lexer->lookahead;
  58053. }
  58054. $message = sprintf('Expected %s, got ', $expected);
  58055. $message .= ($this->lexer->lookahead === null)
  58056. ? 'end of string'
  58057. : sprintf("'%s' at position %s", $token['value'], $token['position']);
  58058. if (strlen($this->context)) {
  58059. $message .= ' in ' . $this->context;
  58060. }
  58061. $message .= '.';
  58062. throw AnnotationException::syntaxError($message);
  58063. }
  58064. private function classExists($fqcn)
  58065. {
  58066. if (isset($this->classExists[$fqcn])) {
  58067. return $this->classExists[$fqcn];
  58068. }
  58069. if (class_exists($fqcn, false)) {
  58070. return $this->classExists[$fqcn] = true;
  58071. }
  58072. return $this->classExists[$fqcn] = AnnotationRegistry::loadAnnotationClass($fqcn);
  58073. }
  58074. private function collectAnnotationMetadata($name)
  58075. {
  58076. if (self::$metadataParser === null) {
  58077. self::$metadataParser = new self();
  58078. self::$metadataParser->setIgnoreNotImportedAnnotations(true);
  58079. self::$metadataParser->setIgnoredAnnotationNames($this->ignoredAnnotationNames);
  58080. self::$metadataParser->setImports(array(
  58081. 'enum' => 'Doctrine\Common\Annotations\Annotation\Enum',
  58082. 'target' => 'Doctrine\Common\Annotations\Annotation\Target',
  58083. 'attribute' => 'Doctrine\Common\Annotations\Annotation\Attribute',
  58084. 'attributes' => 'Doctrine\Common\Annotations\Annotation\Attributes'
  58085. ));
  58086. AnnotationRegistry::registerFile(__DIR__ . '/Annotation/Enum.php');
  58087. AnnotationRegistry::registerFile(__DIR__ . '/Annotation/Target.php');
  58088. AnnotationRegistry::registerFile(__DIR__ . '/Annotation/Attribute.php');
  58089. AnnotationRegistry::registerFile(__DIR__ . '/Annotation/Attributes.php');
  58090. }
  58091. $class = new \ReflectionClass($name);
  58092. $docComment = $class->getDocComment();
  58093. $metadata = array(
  58094. 'default_property' => null,
  58095. 'has_constructor' => (null !== $constructor = $class->getConstructor()) && $constructor->getNumberOfParameters() > 0,
  58096. 'properties' => array(),
  58097. 'property_types' => array(),
  58098. 'attribute_types' => array(),
  58099. 'targets_literal' => null,
  58100. 'targets' => Target::TARGET_ALL,
  58101. 'is_annotation' => false !== strpos($docComment, '@Annotation'),
  58102. );
  58103. if ($metadata['is_annotation']) {
  58104. self::$metadataParser->setTarget(Target::TARGET_CLASS);
  58105. foreach (self::$metadataParser->parse($docComment, 'class @' . $name) as $annotation) {
  58106. if ($annotation instanceof Target) {
  58107. $metadata['targets'] = $annotation->targets;
  58108. $metadata['targets_literal'] = $annotation->literal;
  58109. continue;
  58110. }
  58111. if ($annotation instanceof Attributes) {
  58112. foreach ($annotation->value as $attribute) {
  58113. $this->collectAttributeTypeMetadata($metadata, $attribute);
  58114. }
  58115. }
  58116. }
  58117. if (false === $metadata['has_constructor']) {
  58118. foreach ($class->getProperties(\ReflectionProperty::IS_PUBLIC) as $property) {
  58119. $metadata['properties'][$property->name] = $property->name;
  58120. if (false === ($propertyComment = $property->getDocComment())) {
  58121. continue;
  58122. }
  58123. $attribute = new Attribute();
  58124. $attribute->required = (false !== strpos($propertyComment, '@Required'));
  58125. $attribute->name = $property->name;
  58126. $attribute->type = (false !== strpos($propertyComment, '@var') && preg_match('/@var\s+([^\s]+)/',$propertyComment, $matches))
  58127. ? $matches[1]
  58128. : 'mixed';
  58129. $this->collectAttributeTypeMetadata($metadata, $attribute);
  58130. if (false !== strpos($propertyComment, '@Enum')) {
  58131. $context = 'property ' . $class->name . "::\$" . $property->name;
  58132. self::$metadataParser->setTarget(Target::TARGET_PROPERTY);
  58133. foreach (self::$metadataParser->parse($propertyComment, $context) as $annotation) {
  58134. if ( ! $annotation instanceof Enum) {
  58135. continue;
  58136. }
  58137. $metadata['enum'][$property->name]['value'] = $annotation->value;
  58138. $metadata['enum'][$property->name]['literal'] = ( ! empty($annotation->literal))
  58139. ? $annotation->literal
  58140. : $annotation->value;
  58141. }
  58142. }
  58143. }
  58144. $metadata['default_property'] = reset($metadata['properties']);
  58145. }
  58146. }
  58147. self::$annotationMetadata[$name] = $metadata;
  58148. }
  58149. private function collectAttributeTypeMetadata(&$metadata, Attribute $attribute)
  58150. {
  58151. $type = isset(self::$typeMap[$attribute->type])
  58152. ? self::$typeMap[$attribute->type]
  58153. : $attribute->type;
  58154. if ('mixed' === $type) {
  58155. return;
  58156. }
  58157. switch (true) {
  58158. case (false !== $pos = strpos($type, '<')):
  58159. $arrayType = substr($type, $pos + 1, -1);
  58160. $type = 'array';
  58161. if (isset(self::$typeMap[$arrayType])) {
  58162. $arrayType = self::$typeMap[$arrayType];
  58163. }
  58164. $metadata['attribute_types'][$attribute->name]['array_type'] = $arrayType;
  58165. break;
  58166. case (false !== $pos = strrpos($type, '[')):
  58167. $arrayType = substr($type, 0, $pos);
  58168. $type = 'array';
  58169. if (isset(self::$typeMap[$arrayType])) {
  58170. $arrayType = self::$typeMap[$arrayType];
  58171. }
  58172. $metadata['attribute_types'][$attribute->name]['array_type'] = $arrayType;
  58173. break;
  58174. }
  58175. $metadata['attribute_types'][$attribute->name]['type'] = $type;
  58176. $metadata['attribute_types'][$attribute->name]['value'] = $attribute->type;
  58177. $metadata['attribute_types'][$attribute->name]['required'] = $attribute->required;
  58178. }
  58179. private function Annotations()
  58180. {
  58181. $annotations = array();
  58182. while (null !== $this->lexer->lookahead) {
  58183. if (DocLexer::T_AT !== $this->lexer->lookahead['type']) {
  58184. $this->lexer->moveNext();
  58185. continue;
  58186. }
  58187. if (null !== $this->lexer->token && $this->lexer->lookahead['position'] === $this->lexer->token['position'] + strlen($this->lexer->token['value'])) {
  58188. $this->lexer->moveNext();
  58189. continue;
  58190. }
  58191. if ((null === $peek = $this->lexer->glimpse())
  58192. || (DocLexer::T_NAMESPACE_SEPARATOR !== $peek['type'] && !in_array($peek['type'], self::$classIdentifiers, true))
  58193. || $peek['position'] !== $this->lexer->lookahead['position'] + 1) {
  58194. $this->lexer->moveNext();
  58195. continue;
  58196. }
  58197. $this->isNestedAnnotation = false;
  58198. if (false !== $annot = $this->Annotation()) {
  58199. $annotations[] = $annot;
  58200. }
  58201. }
  58202. return $annotations;
  58203. }
  58204. /**
  58205. * Annotation ::= "@" AnnotationName MethodCall
  58206. * AnnotationName ::= QualifiedName | SimpleName
  58207. * QualifiedName ::= NameSpacePart "\" {NameSpacePart "\"}* SimpleName
  58208. * NameSpacePart ::= identifier | null | false | true
  58209. * SimpleName ::= identifier | null | false | true
  58210. *
  58211. * @return mixed False if it is not a valid annotation.
  58212. *
  58213. * @throws AnnotationException
  58214. */
  58215. private function Annotation()
  58216. {
  58217. $this->match(DocLexer::T_AT);
  58218. $name = $this->Identifier();
  58219. $originalName = $name;
  58220. if ('\\' !== $name[0]) {
  58221. $pos = strpos($name, '\\');
  58222. $alias = (false === $pos)? $name : substr($name, 0, $pos);
  58223. $found = false;
  58224. $loweredAlias = strtolower($alias);
  58225. if ($this->namespaces) {
  58226. foreach ($this->namespaces as $namespace) {
  58227. if ($this->classExists($namespace.'\\'.$name)) {
  58228. $name = $namespace.'\\'.$name;
  58229. $found = true;
  58230. break;
  58231. }
  58232. }
  58233. } elseif (isset($this->imports[$loweredAlias])) {
  58234. $found = true;
  58235. $name = (false !== $pos)
  58236. ? $this->imports[$loweredAlias] . substr($name, $pos)
  58237. : $this->imports[$loweredAlias];
  58238. } elseif ( ! isset($this->ignoredAnnotationNames[$name])
  58239. && isset($this->imports['__NAMESPACE__'])
  58240. && $this->classExists($this->imports['__NAMESPACE__'] . '\\' . $name)
  58241. ) {
  58242. $name = $this->imports['__NAMESPACE__'].'\\'.$name;
  58243. $found = true;
  58244. } elseif (! isset($this->ignoredAnnotationNames[$name]) && $this->classExists($name)) {
  58245. $found = true;
  58246. }
  58247. if ( ! $found) {
  58248. if ($this->isIgnoredAnnotation($name)) {
  58249. return false;
  58250. }
  58251. throw AnnotationException::semanticalError(sprintf('The annotation "@%s" in %s was never imported. Did you maybe forget to add a "use" statement for this annotation?', $name, $this->context));
  58252. }
  58253. }
  58254. $name = ltrim($name,'\\');
  58255. if ( ! $this->classExists($name)) {
  58256. throw AnnotationException::semanticalError(sprintf('The annotation "@%s" in %s does not exist, or could not be auto-loaded.', $name, $this->context));
  58257. }
  58258. if ( ! isset(self::$annotationMetadata[$name])) {
  58259. $this->collectAnnotationMetadata($name);
  58260. }
  58261. if (self::$annotationMetadata[$name]['is_annotation'] === false) {
  58262. if ($this->ignoreNotImportedAnnotations || isset($this->ignoredAnnotationNames[$originalName])) {
  58263. return false;
  58264. }
  58265. throw AnnotationException::semanticalError(sprintf('The class "%s" is not annotated with @Annotation. Are you sure this class can be used as annotation? If so, then you need to add @Annotation to the _class_ doc comment of "%s". If it is indeed no annotation, then you need to add @IgnoreAnnotation("%s") to the _class_ doc comment of %s.', $name, $name, $originalName, $this->context));
  58266. }
  58267. $target = $this->isNestedAnnotation ? Target::TARGET_ANNOTATION : $this->target;
  58268. $this->isNestedAnnotation = true;
  58269. if (0 === (self::$annotationMetadata[$name]['targets'] & $target) && $target) {
  58270. throw AnnotationException::semanticalError(
  58271. sprintf('Annotation @%s is not allowed to be declared on %s. You may only use this annotation on these code elements: %s.',
  58272. $originalName, $this->context, self::$annotationMetadata[$name]['targets_literal'])
  58273. );
  58274. }
  58275. $values = $this->MethodCall();
  58276. if (isset(self::$annotationMetadata[$name]['enum'])) {
  58277. foreach (self::$annotationMetadata[$name]['enum'] as $property => $enum) {
  58278. if (isset($values[$property]) && ! in_array($values[$property], $enum['value'])) {
  58279. throw AnnotationException::enumeratorError($property, $name, $this->context, $enum['literal'], $values[$property]);
  58280. }
  58281. }
  58282. }
  58283. foreach (self::$annotationMetadata[$name]['attribute_types'] as $property => $type) {
  58284. if ($property === self::$annotationMetadata[$name]['default_property']
  58285. && !isset($values[$property]) && isset($values['value'])) {
  58286. $property = 'value';
  58287. }
  58288. if (!isset($values[$property])) {
  58289. if ($type['required']) {
  58290. throw AnnotationException::requiredError($property, $originalName, $this->context, 'a(n) '.$type['value']);
  58291. }
  58292. continue;
  58293. }
  58294. if ($type['type'] === 'array') {
  58295. if ( ! is_array($values[$property])) {
  58296. $values[$property] = array($values[$property]);
  58297. }
  58298. if (isset($type['array_type'])) {
  58299. foreach ($values[$property] as $item) {
  58300. if (gettype($item) !== $type['array_type'] && !$item instanceof $type['array_type']) {
  58301. throw AnnotationException::attributeTypeError($property, $originalName, $this->context, 'either a(n) '.$type['array_type'].', or an array of '.$type['array_type'].'s', $item);
  58302. }
  58303. }
  58304. }
  58305. } elseif (gettype($values[$property]) !== $type['type'] && !$values[$property] instanceof $type['type']) {
  58306. throw AnnotationException::attributeTypeError($property, $originalName, $this->context, 'a(n) '.$type['value'], $values[$property]);
  58307. }
  58308. }
  58309. if (self::$annotationMetadata[$name]['has_constructor'] === true) {
  58310. return new $name($values);
  58311. }
  58312. $instance = new $name();
  58313. foreach ($values as $property => $value) {
  58314. if (!isset(self::$annotationMetadata[$name]['properties'][$property])) {
  58315. if ('value' !== $property) {
  58316. throw AnnotationException::creationError(sprintf('The annotation @%s declared on %s does not have a property named "%s". Available properties: %s', $originalName, $this->context, $property, implode(', ', self::$annotationMetadata[$name]['properties'])));
  58317. }
  58318. if ( ! $property = self::$annotationMetadata[$name]['default_property']) {
  58319. throw AnnotationException::creationError(sprintf('The annotation @%s declared on %s does not accept any values, but got %s.', $originalName, $this->context, json_encode($values)));
  58320. }
  58321. }
  58322. $instance->{$property} = $value;
  58323. }
  58324. return $instance;
  58325. }
  58326. private function MethodCall()
  58327. {
  58328. $values = array();
  58329. if ( ! $this->lexer->isNextToken(DocLexer::T_OPEN_PARENTHESIS)) {
  58330. return $values;
  58331. }
  58332. $this->match(DocLexer::T_OPEN_PARENTHESIS);
  58333. if ( ! $this->lexer->isNextToken(DocLexer::T_CLOSE_PARENTHESIS)) {
  58334. $values = $this->Values();
  58335. }
  58336. $this->match(DocLexer::T_CLOSE_PARENTHESIS);
  58337. return $values;
  58338. }
  58339. private function Values()
  58340. {
  58341. $values = array($this->Value());
  58342. while ($this->lexer->isNextToken(DocLexer::T_COMMA)) {
  58343. $this->match(DocLexer::T_COMMA);
  58344. if ($this->lexer->isNextToken(DocLexer::T_CLOSE_PARENTHESIS)) {
  58345. break;
  58346. }
  58347. $token = $this->lexer->lookahead;
  58348. $value = $this->Value();
  58349. if ( ! is_object($value) && ! is_array($value)) {
  58350. $this->syntaxError('Value', $token);
  58351. }
  58352. $values[] = $value;
  58353. }
  58354. foreach ($values as $k => $value) {
  58355. if (is_object($value) && $value instanceof \stdClass) {
  58356. $values[$value->name] = $value->value;
  58357. } else if ( ! isset($values['value'])){
  58358. $values['value'] = $value;
  58359. } else {
  58360. if ( ! is_array($values['value'])) {
  58361. $values['value'] = array($values['value']);
  58362. }
  58363. $values['value'][] = $value;
  58364. }
  58365. unset($values[$k]);
  58366. }
  58367. return $values;
  58368. }
  58369. private function Constant()
  58370. {
  58371. $identifier = $this->Identifier();
  58372. if ( ! defined($identifier) && false !== strpos($identifier, '::') && '\\' !== $identifier[0]) {
  58373. list($className, $const) = explode('::', $identifier);
  58374. $pos = strpos($className, '\\');
  58375. $alias = (false === $pos) ? $className : substr($className, 0, $pos);
  58376. $found = false;
  58377. $loweredAlias = strtolower($alias);
  58378. switch (true) {
  58379. case !empty ($this->namespaces):
  58380. foreach ($this->namespaces as $ns) {
  58381. if (class_exists($ns.'\\'.$className) || interface_exists($ns.'\\'.$className)) {
  58382. $className = $ns.'\\'.$className;
  58383. $found = true;
  58384. break;
  58385. }
  58386. }
  58387. break;
  58388. case isset($this->imports[$loweredAlias]):
  58389. $found = true;
  58390. $className = (false !== $pos)
  58391. ? $this->imports[$loweredAlias] . substr($className, $pos)
  58392. : $this->imports[$loweredAlias];
  58393. break;
  58394. default:
  58395. if(isset($this->imports['__NAMESPACE__'])) {
  58396. $ns = $this->imports['__NAMESPACE__'];
  58397. if (class_exists($ns.'\\'.$className) || interface_exists($ns.'\\'.$className)) {
  58398. $className = $ns.'\\'.$className;
  58399. $found = true;
  58400. }
  58401. }
  58402. break;
  58403. }
  58404. if ($found) {
  58405. $identifier = $className . '::' . $const;
  58406. }
  58407. }
  58408. $classPos = stripos($identifier, '::class');
  58409. if ($classPos === strlen($identifier) - 7) {
  58410. return substr($identifier, 0, $classPos);
  58411. }
  58412. if (!defined($identifier)) {
  58413. throw AnnotationException::semanticalErrorConstants($identifier, $this->context);
  58414. }
  58415. return constant($identifier);
  58416. }
  58417. private function Identifier()
  58418. {
  58419. if ( ! $this->lexer->isNextTokenAny(self::$classIdentifiers)) {
  58420. $this->syntaxError('namespace separator or identifier');
  58421. }
  58422. $this->lexer->moveNext();
  58423. $className = $this->lexer->token['value'];
  58424. while ($this->lexer->lookahead['position'] === ($this->lexer->token['position'] + strlen($this->lexer->token['value']))
  58425. && $this->lexer->isNextToken(DocLexer::T_NAMESPACE_SEPARATOR)) {
  58426. $this->match(DocLexer::T_NAMESPACE_SEPARATOR);
  58427. $this->matchAny(self::$classIdentifiers);
  58428. $className .= '\\' . $this->lexer->token['value'];
  58429. }
  58430. return $className;
  58431. }
  58432. private function Value()
  58433. {
  58434. $peek = $this->lexer->glimpse();
  58435. if (DocLexer::T_EQUALS === $peek['type']) {
  58436. return $this->FieldAssignment();
  58437. }
  58438. return $this->PlainValue();
  58439. }
  58440. private function PlainValue()
  58441. {
  58442. if ($this->lexer->isNextToken(DocLexer::T_OPEN_CURLY_BRACES)) {
  58443. return $this->Arrayx();
  58444. }
  58445. if ($this->lexer->isNextToken(DocLexer::T_AT)) {
  58446. return $this->Annotation();
  58447. }
  58448. if ($this->lexer->isNextToken(DocLexer::T_IDENTIFIER)) {
  58449. return $this->Constant();
  58450. }
  58451. switch ($this->lexer->lookahead['type']) {
  58452. case DocLexer::T_STRING:
  58453. $this->match(DocLexer::T_STRING);
  58454. return $this->lexer->token['value'];
  58455. case DocLexer::T_INTEGER:
  58456. $this->match(DocLexer::T_INTEGER);
  58457. return (int)$this->lexer->token['value'];
  58458. case DocLexer::T_FLOAT:
  58459. $this->match(DocLexer::T_FLOAT);
  58460. return (float)$this->lexer->token['value'];
  58461. case DocLexer::T_TRUE:
  58462. $this->match(DocLexer::T_TRUE);
  58463. return true;
  58464. case DocLexer::T_FALSE:
  58465. $this->match(DocLexer::T_FALSE);
  58466. return false;
  58467. case DocLexer::T_NULL:
  58468. $this->match(DocLexer::T_NULL);
  58469. return null;
  58470. default:
  58471. $this->syntaxError('PlainValue');
  58472. }
  58473. }
  58474. private function FieldAssignment()
  58475. {
  58476. $this->match(DocLexer::T_IDENTIFIER);
  58477. $fieldName = $this->lexer->token['value'];
  58478. $this->match(DocLexer::T_EQUALS);
  58479. $item = new \stdClass();
  58480. $item->name = $fieldName;
  58481. $item->value = $this->PlainValue();
  58482. return $item;
  58483. }
  58484. private function Arrayx()
  58485. {
  58486. $array = $values = array();
  58487. $this->match(DocLexer::T_OPEN_CURLY_BRACES);
  58488. if ($this->lexer->isNextToken(DocLexer::T_CLOSE_CURLY_BRACES)) {
  58489. $this->match(DocLexer::T_CLOSE_CURLY_BRACES);
  58490. return $array;
  58491. }
  58492. $values[] = $this->ArrayEntry();
  58493. while ($this->lexer->isNextToken(DocLexer::T_COMMA)) {
  58494. $this->match(DocLexer::T_COMMA);
  58495. if ($this->lexer->isNextToken(DocLexer::T_CLOSE_CURLY_BRACES)) {
  58496. break;
  58497. }
  58498. $values[] = $this->ArrayEntry();
  58499. }
  58500. $this->match(DocLexer::T_CLOSE_CURLY_BRACES);
  58501. foreach ($values as $value) {
  58502. list ($key, $val) = $value;
  58503. if ($key !== null) {
  58504. $array[$key] = $val;
  58505. } else {
  58506. $array[] = $val;
  58507. }
  58508. }
  58509. return $array;
  58510. }
  58511. private function ArrayEntry()
  58512. {
  58513. $peek = $this->lexer->glimpse();
  58514. if (DocLexer::T_EQUALS === $peek['type']
  58515. || DocLexer::T_COLON === $peek['type']) {
  58516. if ($this->lexer->isNextToken(DocLexer::T_IDENTIFIER)) {
  58517. $key = $this->Constant();
  58518. } else {
  58519. $this->matchAny(array(DocLexer::T_INTEGER, DocLexer::T_STRING));
  58520. $key = $this->lexer->token['value'];
  58521. }
  58522. $this->matchAny(array(DocLexer::T_EQUALS, DocLexer::T_COLON));
  58523. return array($key, $this->PlainValue());
  58524. }
  58525. return array(null, $this->Value());
  58526. }
  58527. private function isIgnoredAnnotation($name)
  58528. {
  58529. if ($this->ignoreNotImportedAnnotations || isset($this->ignoredAnnotationNames[$name])) {
  58530. return true;
  58531. }
  58532. foreach (array_keys($this->ignoredAnnotationNamespaces) as $ignoredAnnotationNamespace) {
  58533. $ignoredAnnotationNamespace = rtrim($ignoredAnnotationNamespace, '\\') . '\\';
  58534. if (0 === stripos(rtrim($name, '\\') . '\\', $ignoredAnnotationNamespace)) {
  58535. return true;
  58536. }
  58537. }
  58538. return false;
  58539. }
  58540. }
  58541. <?php
  58542. namespace Doctrine\Common\Annotations;
  58543. /**
  58544. @hotmail
  58545. @gmail
  58546. */
  58547. class Annotation
  58548. {
  58549. public $value;
  58550. public final function __construct(array $data)
  58551. {
  58552. foreach ($data as $key => $value) {
  58553. $this->$key = $value;
  58554. }
  58555. }
  58556. public function __get($name)
  58557. {
  58558. throw new \BadMethodCallException(
  58559. sprintf("Unknown property '%s' on annotation '%s'.", $name, get_class($this))
  58560. );
  58561. }
  58562. public function __set($name, $value)
  58563. {
  58564. throw new \BadMethodCallException(
  58565. sprintf("Unknown property '%s' on annotation '%s'.", $name, get_class($this))
  58566. );
  58567. }
  58568. }
  58569. <?php
  58570. namespace Doctrine\Common\Annotations;
  58571. final class AnnotationRegistry
  58572. {
  58573. static private $autoloadNamespaces = array();
  58574. static private $loaders = array();
  58575. static public function reset()
  58576. {
  58577. self::$autoloadNamespaces = array();
  58578. self::$loaders = array();
  58579. }
  58580. static public function registerFile($file)
  58581. {
  58582. require_once $file;
  58583. }
  58584. static public function registerAutoloadNamespace($namespace, $dirs = null)
  58585. {
  58586. self::$autoloadNamespaces[$namespace] = $dirs;
  58587. }
  58588. static public function registerAutoloadNamespaces(array $namespaces)
  58589. {
  58590. self::$autoloadNamespaces = array_merge(self::$autoloadNamespaces, $namespaces);
  58591. }
  58592. static public function registerLoader($callable)
  58593. {
  58594. if (!is_callable($callable)) {
  58595. throw new \InvalidArgumentException("A callable is expected in AnnotationRegistry::registerLoader().");
  58596. }
  58597. self::$loaders[] = $callable;
  58598. }
  58599. static public function loadAnnotationClass($class)
  58600. {
  58601. foreach (self::$autoloadNamespaces AS $namespace => $dirs) {
  58602. if (strpos($class, $namespace) === 0) {
  58603. $file = str_replace("\\", DIRECTORY_SEPARATOR, $class) . ".php";
  58604. if ($dirs === null) {
  58605. if ($path = stream_resolve_include_path($file)) {
  58606. require $path;
  58607. return true;
  58608. }
  58609. } else {
  58610. foreach((array)$dirs AS $dir) {
  58611. if (is_file($dir . DIRECTORY_SEPARATOR . $file)) {
  58612. require $dir . DIRECTORY_SEPARATOR . $file;
  58613. return true;
  58614. }
  58615. }
  58616. }
  58617. }
  58618. }
  58619. foreach (self::$loaders AS $loader) {
  58620. if (call_user_func($loader, $class) === true) {
  58621. return true;
  58622. }
  58623. }
  58624. return false;
  58625. }
  58626. }
  58627. <?php
  58628. namespace Doctrine\Common\Annotations;
  58629. /**
  58630. @gmail
  58631. */
  58632. class SimpleAnnotationReader implements Reader
  58633. {
  58634. private $parser;
  58635. public function __construct()
  58636. {
  58637. $this->parser = new DocParser();
  58638. $this->parser->setIgnoreNotImportedAnnotations(true);
  58639. }
  58640. public function addNamespace($namespace)
  58641. {
  58642. $this->parser->addNamespace($namespace);
  58643. }
  58644. public function getClassAnnotations(\ReflectionClass $class)
  58645. {
  58646. return $this->parser->parse($class->getDocComment(), 'class '.$class->getName());
  58647. }
  58648. public function getMethodAnnotations(\ReflectionMethod $method)
  58649. {
  58650. return $this->parser->parse($method->getDocComment(), 'method '.$method->getDeclaringClass()->name.'::'.$method->getName().'()');
  58651. }
  58652. public function getPropertyAnnotations(\ReflectionProperty $property)
  58653. {
  58654. return $this->parser->parse($property->getDocComment(), 'property '.$property->getDeclaringClass()->name.'::$'.$property->getName());
  58655. }
  58656. public function getClassAnnotation(\ReflectionClass $class, $annotationName)
  58657. {
  58658. foreach ($this->getClassAnnotations($class) as $annot) {
  58659. if ($annot instanceof $annotationName) {
  58660. return $annot;
  58661. }
  58662. }
  58663. return null;
  58664. }
  58665. public function getMethodAnnotation(\ReflectionMethod $method, $annotationName)
  58666. {
  58667. foreach ($this->getMethodAnnotations($method) as $annot) {
  58668. if ($annot instanceof $annotationName) {
  58669. return $annot;
  58670. }
  58671. }
  58672. return null;
  58673. }
  58674. public function getPropertyAnnotation(\ReflectionProperty $property, $annotationName)
  58675. {
  58676. foreach ($this->getPropertyAnnotations($property) as $annot) {
  58677. if ($annot instanceof $annotationName) {
  58678. return $annot;
  58679. }
  58680. }
  58681. return null;
  58682. }
  58683. }
  58684. <?php
  58685. namespace Doctrine\Common\Lexer;
  58686. /**
  58687. @gmail
  58688. */
  58689. abstract class AbstractLexer
  58690. {
  58691. private $input;
  58692. private $tokens = array();
  58693. private $position = 0;
  58694. private $peek = 0;
  58695. public $lookahead;
  58696. public $token;
  58697. public function setInput($input)
  58698. {
  58699. $this->input = $input;
  58700. $this->tokens = array();
  58701. $this->reset();
  58702. $this->scan($input);
  58703. }
  58704. public function reset()
  58705. {
  58706. $this->lookahead = null;
  58707. $this->token = null;
  58708. $this->peek = 0;
  58709. $this->position = 0;
  58710. }
  58711. public function resetPeek()
  58712. {
  58713. $this->peek = 0;
  58714. }
  58715. public function resetPosition($position = 0)
  58716. {
  58717. $this->position = $position;
  58718. }
  58719. public function getInputUntilPosition($position)
  58720. {
  58721. return substr($this->input, 0, $position);
  58722. }
  58723. public function isNextToken($token)
  58724. {
  58725. return null !== $this->lookahead && $this->lookahead['type'] === $token;
  58726. }
  58727. public function isNextTokenAny(array $tokens)
  58728. {
  58729. return null !== $this->lookahead && in_array($this->lookahead['type'], $tokens, true);
  58730. }
  58731. public function moveNext()
  58732. {
  58733. $this->peek = 0;
  58734. $this->token = $this->lookahead;
  58735. $this->lookahead = (isset($this->tokens[$this->position]))
  58736. ? $this->tokens[$this->position++] : null;
  58737. return $this->lookahead !== null;
  58738. }
  58739. public function skipUntil($type)
  58740. {
  58741. while ($this->lookahead !== null && $this->lookahead['type'] !== $type) {
  58742. $this->moveNext();
  58743. }
  58744. }
  58745. public function isA($value, $token)
  58746. {
  58747. return $this->getType($value) === $token;
  58748. }
  58749. public function peek()
  58750. {
  58751. if (isset($this->tokens[$this->position + $this->peek])) {
  58752. return $this->tokens[$this->position + $this->peek++];
  58753. } else {
  58754. return null;
  58755. }
  58756. }
  58757. public function glimpse()
  58758. {
  58759. $peek = $this->peek();
  58760. $this->peek = 0;
  58761. return $peek;
  58762. }
  58763. protected function scan($input)
  58764. {
  58765. static $regex;
  58766. if ( ! isset($regex)) {
  58767. $regex = sprintf(
  58768. '/(%s)|%s/%s',
  58769. implode(')|(', $this->getCatchablePatterns()),
  58770. implode('|', $this->getNonCatchablePatterns()),
  58771. $this->getModifiers()
  58772. );
  58773. }
  58774. $flags = PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_OFFSET_CAPTURE;
  58775. $matches = preg_split($regex, $input, -1, $flags);
  58776. if (false === $matches) {
  58777. $matches = array(array($input, 0));
  58778. }
  58779. foreach ($matches as $match) {
  58780. $type = $this->getType($match[0]);
  58781. $this->tokens[] = array(
  58782. 'value' => $match[0],
  58783. 'type' => $type,
  58784. 'position' => $match[1],
  58785. );
  58786. }
  58787. }
  58788. public function getLiteral($token)
  58789. {
  58790. $className = get_class($this);
  58791. $reflClass = new \ReflectionClass($className);
  58792. $constants = $reflClass->getConstants();
  58793. foreach ($constants as $name => $value) {
  58794. if ($value === $token) {
  58795. return $className . '::' . $name;
  58796. }
  58797. }
  58798. return $token;
  58799. }
  58800. protected function getModifiers()
  58801. {
  58802. return 'i';
  58803. }
  58804. abstract protected function getCatchablePatterns();
  58805. abstract protected function getNonCatchablePatterns();
  58806. abstract protected function getType(&$value);
  58807. }
  58808. <?php
  58809. namespace Psr\Log;
  58810. interface LoggerAwareInterface
  58811. {
  58812. public function setLogger(LoggerInterface $logger);
  58813. }
  58814. <?php
  58815. namespace Psr\Log;
  58816. trait LoggerAwareTrait
  58817. {
  58818. protected $logger;
  58819. public function setLogger(LoggerInterface $logger)
  58820. {
  58821. $this->logger = $logger;
  58822. }
  58823. }
  58824. <?php
  58825. namespace Psr\Log;
  58826. abstract class AbstractLogger implements LoggerInterface
  58827. {
  58828. public function emergency($message, array $context = array())
  58829. {
  58830. $this->log(LogLevel::EMERGENCY, $message, $context);
  58831. }
  58832. public function alert($message, array $context = array())
  58833. {
  58834. $this->log(LogLevel::ALERT, $message, $context);
  58835. }
  58836. public function critical($message, array $context = array())
  58837. {
  58838. $this->log(LogLevel::CRITICAL, $message, $context);
  58839. }
  58840. public function error($message, array $context = array())
  58841. {
  58842. $this->log(LogLevel::ERROR, $message, $context);
  58843. }
  58844. public function warning($message, array $context = array())
  58845. {
  58846. $this->log(LogLevel::WARNING, $message, $context);
  58847. }
  58848. public function notice($message, array $context = array())
  58849. {
  58850. $this->log(LogLevel::NOTICE, $message, $context);
  58851. }
  58852. public function info($message, array $context = array())
  58853. {
  58854. $this->log(LogLevel::INFO, $message, $context);
  58855. }
  58856. public function debug($message, array $context = array())
  58857. {
  58858. $this->log(LogLevel::DEBUG, $message, $context);
  58859. }
  58860. }
  58861. <?php
  58862. namespace Psr\Log;
  58863. class NullLogger extends AbstractLogger
  58864. {
  58865. public function log($level, $message, array $context = array())
  58866. {
  58867. }
  58868. }
  58869. <?php
  58870. namespace Psr\Log;
  58871. class LogLevel
  58872. {
  58873. const EMERGENCY = 'emergency';
  58874. const ALERT = 'alert';
  58875. const CRITICAL = 'critical';
  58876. const ERROR = 'error';
  58877. const WARNING = 'warning';
  58878. const NOTICE = 'notice';
  58879. const INFO = 'info';
  58880. const DEBUG = 'debug';
  58881. }
  58882. <?php
  58883. namespace Psr\Log;
  58884. trait LoggerTrait
  58885. {
  58886. public function emergency($message, array $context = array())
  58887. {
  58888. $this->log(LogLevel::EMERGENCY, $message, $context);
  58889. }
  58890. public function alert($message, array $context = array())
  58891. {
  58892. $this->log(LogLevel::ALERT, $message, $context);
  58893. }
  58894. public function critical($message, array $context = array())
  58895. {
  58896. $this->log(LogLevel::CRITICAL, $message, $context);
  58897. }
  58898. public function error($message, array $context = array())
  58899. {
  58900. $this->log(LogLevel::ERROR, $message, $context);
  58901. }
  58902. public function warning($message, array $context = array())
  58903. {
  58904. $this->log(LogLevel::WARNING, $message, $context);
  58905. }
  58906. public function notice($message, array $context = array())
  58907. {
  58908. $this->log(LogLevel::NOTICE, $message, $context);
  58909. }
  58910. public function info($message, array $context = array())
  58911. {
  58912. $this->log(LogLevel::INFO, $message, $context);
  58913. }
  58914. public function debug($message, array $context = array())
  58915. {
  58916. $this->log(LogLevel::DEBUG, $message, $context);
  58917. }
  58918. abstract public function log($level, $message, array $context = array());
  58919. }
  58920. <?php
  58921. namespace Psr\Log;
  58922. interface LoggerInterface
  58923. {
  58924. public function emergency($message, array $context = array());
  58925. public function alert($message, array $context = array());
  58926. public function critical($message, array $context = array());
  58927. public function error($message, array $context = array());
  58928. public function warning($message, array $context = array());
  58929. public function notice($message, array $context = array());
  58930. public function info($message, array $context = array());
  58931. public function debug($message, array $context = array());
  58932. public function log($level, $message, array $context = array());
  58933. }
  58934. <?php
  58935. namespace Psr\Log;
  58936. class InvalidArgumentException extends \InvalidArgumentException
  58937. {
  58938. }
  58939. <?php
  58940. namespace PhpCsFixer\Diff\v1_4;
  58941. class Chunk
  58942. {
  58943. private $start;
  58944. private $startRange;
  58945. private $end;
  58946. private $endRange;
  58947. private $lines;
  58948. public function __construct($start = 0, $startRange = 1, $end = 0, $endRange = 1, array $lines = array())
  58949. {
  58950. $this->start = (int) $start;
  58951. $this->startRange = (int) $startRange;
  58952. $this->end = (int) $end;
  58953. $this->endRange = (int) $endRange;
  58954. $this->lines = $lines;
  58955. }
  58956. public function getStart()
  58957. {
  58958. return $this->start;
  58959. }
  58960. public function getStartRange()
  58961. {
  58962. return $this->startRange;
  58963. }
  58964. public function getEnd()
  58965. {
  58966. return $this->end;
  58967. }
  58968. public function getEndRange()
  58969. {
  58970. return $this->endRange;
  58971. }
  58972. public function getLines()
  58973. {
  58974. return $this->lines;
  58975. }
  58976. public function setLines(array $lines)
  58977. {
  58978. $this->lines = $lines;
  58979. }
  58980. }
  58981. <?php
  58982. namespace PhpCsFixer\Diff\v1_4;
  58983. class Line
  58984. {
  58985. const ADDED = 1;
  58986. const REMOVED = 2;
  58987. const UNCHANGED = 3;
  58988. private $type;
  58989. private $content;
  58990. public function __construct($type = self::UNCHANGED, $content = '')
  58991. {
  58992. $this->type = $type;
  58993. $this->content = $content;
  58994. }
  58995. public function getContent()
  58996. {
  58997. return $this->content;
  58998. }
  58999. public function getType()
  59000. {
  59001. return $this->type;
  59002. }
  59003. }
  59004. <?php
  59005. namespace PhpCsFixer\Diff\v1_4;
  59006. use PhpCsFixer\Diff\v1_4\LCS\LongestCommonSubsequence;
  59007. use PhpCsFixer\Diff\v1_4\LCS\TimeEfficientImplementation;
  59008. use PhpCsFixer\Diff\v1_4\LCS\MemoryEfficientImplementation;
  59009. class Differ
  59010. {
  59011. private $header;
  59012. private $showNonDiffLines;
  59013. public function __construct($header = "--- Original\n+++ New\n", $showNonDiffLines = true)
  59014. {
  59015. $this->header = $header;
  59016. $this->showNonDiffLines = $showNonDiffLines;
  59017. }
  59018. public function diff($from, $to, LongestCommonSubsequence $lcs = null)
  59019. {
  59020. $from = $this->validateDiffInput($from);
  59021. $to = $this->validateDiffInput($to);
  59022. $diff = $this->diffToArray($from, $to, $lcs);
  59023. $old = $this->checkIfDiffInOld($diff);
  59024. $start = isset($old[0]) ? $old[0] : 0;
  59025. $end = \count($diff);
  59026. if ($tmp = \array_search($end, $old)) {
  59027. $end = $tmp;
  59028. }
  59029. return $this->getBuffer($diff, $old, $start, $end);
  59030. }
  59031. private function validateDiffInput($input)
  59032. {
  59033. if (!\is_array($input) && !\is_string($input)) {
  59034. return (string) $input;
  59035. }
  59036. return $input;
  59037. }
  59038. private function checkIfDiffInOld(array $diff)
  59039. {
  59040. $inOld = false;
  59041. $i = 0;
  59042. $old = array();
  59043. foreach ($diff as $line) {
  59044. if ($line[1] === 0 ) {
  59045. if ($inOld === false) {
  59046. $inOld = $i;
  59047. }
  59048. } elseif ($inOld !== false) {
  59049. if (($i - $inOld) > 5) {
  59050. $old[$inOld] = $i - 1;
  59051. }
  59052. $inOld = false;
  59053. }
  59054. ++$i;
  59055. }
  59056. return $old;
  59057. }
  59058. private function getBuffer(array $diff, array $old, $start, $end)
  59059. {
  59060. $buffer = $this->header;
  59061. if (!isset($old[$start])) {
  59062. $buffer = $this->getDiffBufferElementNew($diff, $buffer, $start);
  59063. ++$start;
  59064. }
  59065. for ($i = $start; $i < $end; $i++) {
  59066. if (isset($old[$i])) {
  59067. $i = $old[$i];
  59068. $buffer = $this->getDiffBufferElementNew($diff, $buffer, $i);
  59069. } else {
  59070. $buffer = $this->getDiffBufferElement($diff, $buffer, $i);
  59071. }
  59072. }
  59073. return $buffer;
  59074. }
  59075. private function getDiffBufferElement(array $diff, $buffer, $diffIndex)
  59076. {
  59077. if ($diff[$diffIndex][1] === 1 ) {
  59078. $buffer .= '+' . $diff[$diffIndex][0] . "\n";
  59079. } elseif ($diff[$diffIndex][1] === 2 ) {
  59080. $buffer .= '-' . $diff[$diffIndex][0] . "\n";
  59081. } elseif ($this->showNonDiffLines === true) {
  59082. $buffer .= ' ' . $diff[$diffIndex][0] . "\n";
  59083. }
  59084. return $buffer;
  59085. }
  59086. private function getDiffBufferElementNew(array $diff, $buffer, $diffIndex)
  59087. {
  59088. if ($this->showNonDiffLines === true) {
  59089. $buffer .= "@@ @@\n";
  59090. }
  59091. return $this->getDiffBufferElement($diff, $buffer, $diffIndex);
  59092. }
  59093. public function diffToArray($from, $to, LongestCommonSubsequence $lcs = null)
  59094. {
  59095. if (\is_string($from)) {
  59096. $fromMatches = $this->getNewLineMatches($from);
  59097. $from = $this->splitStringByLines($from);
  59098. } elseif (\is_array($from)) {
  59099. $fromMatches = array();
  59100. } else {
  59101. throw new \InvalidArgumentException('"from" must be an array or string.');
  59102. }
  59103. if (\is_string($to)) {
  59104. $toMatches = $this->getNewLineMatches($to);
  59105. $to = $this->splitStringByLines($to);
  59106. } elseif (\is_array($to)) {
  59107. $toMatches = array();
  59108. } else {
  59109. throw new \InvalidArgumentException('"to" must be an array or string.');
  59110. }
  59111. list($from, $to, $start, $end) = self::getArrayDiffParted($from, $to);
  59112. if ($lcs === null) {
  59113. $lcs = $this->selectLcsImplementation($from, $to);
  59114. }
  59115. $common = $lcs->calculate(\array_values($from), \array_values($to));
  59116. $diff = array();
  59117. if ($this->detectUnmatchedLineEndings($fromMatches, $toMatches)) {
  59118. $diff[] = array(
  59119. '#Warnings contain different line endings!',
  59120. 0
  59121. );
  59122. }
  59123. foreach ($start as $token) {
  59124. $diff[] = array($token, 0 );
  59125. }
  59126. \reset($from);
  59127. \reset($to);
  59128. foreach ($common as $token) {
  59129. while (($fromToken = \reset($from)) !== $token) {
  59130. $diff[] = array(\array_shift($from), 2 );
  59131. }
  59132. while (($toToken = \reset($to)) !== $token) {
  59133. $diff[] = array(\array_shift($to), 1 );
  59134. }
  59135. $diff[] = array($token, 0 );
  59136. \array_shift($from);
  59137. \array_shift($to);
  59138. }
  59139. while (($token = \array_shift($from)) !== null) {
  59140. $diff[] = array($token, 2 );
  59141. }
  59142. while (($token = \array_shift($to)) !== null) {
  59143. $diff[] = array($token, 1 );
  59144. }
  59145. foreach ($end as $token) {
  59146. $diff[] = array($token, 0 );
  59147. }
  59148. return $diff;
  59149. }
  59150. private function getNewLineMatches($string)
  59151. {
  59152. \preg_match_all('(\r\n|\r|\n)', $string, $stringMatches);
  59153. return $stringMatches;
  59154. }
  59155. private function splitStringByLines($input)
  59156. {
  59157. return \preg_split('(\r\n|\r|\n)', $input);
  59158. }
  59159. private function selectLcsImplementation(array $from, array $to)
  59160. {
  59161. $memoryLimit = 100 * 1024 * 1024;
  59162. if ($this->calculateEstimatedFootprint($from, $to) > $memoryLimit) {
  59163. return new MemoryEfficientImplementation;
  59164. }
  59165. return new TimeEfficientImplementation;
  59166. }
  59167. private function calculateEstimatedFootprint(array $from, array $to)
  59168. {
  59169. $itemSize = PHP_INT_SIZE === 4 ? 76 : 144;
  59170. return $itemSize * \pow(\min(\count($from), \count($to)), 2);
  59171. }
  59172. private function detectUnmatchedLineEndings(array $fromMatches, array $toMatches)
  59173. {
  59174. return isset($fromMatches[0], $toMatches[0]) &&
  59175. \count($fromMatches[0]) === \count($toMatches[0]) &&
  59176. $fromMatches[0] !== $toMatches[0];
  59177. }
  59178. private static function getArrayDiffParted(array &$from, array &$to)
  59179. {
  59180. $start = array();
  59181. $end = array();
  59182. \reset($to);
  59183. foreach ($from as $k => $v) {
  59184. $toK = \key($to);
  59185. if ($toK === $k && $v === $to[$k]) {
  59186. $start[$k] = $v;
  59187. unset($from[$k], $to[$k]);
  59188. } else {
  59189. break;
  59190. }
  59191. }
  59192. \end($from);
  59193. \end($to);
  59194. do {
  59195. $fromK = \key($from);
  59196. $toK = \key($to);
  59197. if (null === $fromK || null === $toK || \current($from) !== \current($to)) {
  59198. break;
  59199. }
  59200. \prev($from);
  59201. \prev($to);
  59202. $end = array($fromK => $from[$fromK]) + $end;
  59203. unset($from[$fromK], $to[$toK]);
  59204. } while (true);
  59205. return array($from, $to, $start, $end);
  59206. }
  59207. }
  59208. <?php
  59209. namespace PhpCsFixer\Diff\v1_4\LCS;
  59210. class TimeEfficientImplementation implements LongestCommonSubsequence
  59211. {
  59212. public function calculate(array $from, array $to)
  59213. {
  59214. $common = array();
  59215. $fromLength = \count($from);
  59216. $toLength = \count($to);
  59217. $width = $fromLength + 1;
  59218. $matrix = new \SplFixedArray($width * ($toLength + 1));
  59219. for ($i = 0; $i <= $fromLength; ++$i) {
  59220. $matrix[$i] = 0;
  59221. }
  59222. for ($j = 0; $j <= $toLength; ++$j) {
  59223. $matrix[$j * $width] = 0;
  59224. }
  59225. for ($i = 1; $i <= $fromLength; ++$i) {
  59226. for ($j = 1; $j <= $toLength; ++$j) {
  59227. $o = ($j * $width) + $i;
  59228. $matrix[$o] = \max(
  59229. $matrix[$o - 1],
  59230. $matrix[$o - $width],
  59231. $from[$i - 1] === $to[$j - 1] ? $matrix[$o - $width - 1] + 1 : 0
  59232. );
  59233. }
  59234. }
  59235. $i = $fromLength;
  59236. $j = $toLength;
  59237. while ($i > 0 && $j > 0) {
  59238. if ($from[$i - 1] === $to[$j - 1]) {
  59239. $common[] = $from[$i - 1];
  59240. --$i;
  59241. --$j;
  59242. } else {
  59243. $o = ($j * $width) + $i;
  59244. if ($matrix[$o - $width] > $matrix[$o - 1]) {
  59245. --$j;
  59246. } else {
  59247. --$i;
  59248. }
  59249. }
  59250. }
  59251. return \array_reverse($common);
  59252. }
  59253. }
  59254. <?php
  59255. namespace PhpCsFixer\Diff\v1_4\LCS;
  59256. class MemoryEfficientImplementation implements LongestCommonSubsequence
  59257. {
  59258. public function calculate(array $from, array $to)
  59259. {
  59260. $cFrom = \count($from);
  59261. $cTo = \count($to);
  59262. if ($cFrom === 0) {
  59263. return array();
  59264. }
  59265. if ($cFrom === 1) {
  59266. if (\in_array($from[0], $to, true)) {
  59267. return array($from[0]);
  59268. }
  59269. return array();
  59270. }
  59271. $i = (int) ($cFrom / 2);
  59272. $fromStart = \array_slice($from, 0, $i);
  59273. $fromEnd = \array_slice($from, $i);
  59274. $llB = $this->length($fromStart, $to);
  59275. $llE = $this->length(\array_reverse($fromEnd), \array_reverse($to));
  59276. $jMax = 0;
  59277. $max = 0;
  59278. for ($j = 0; $j <= $cTo; $j++) {
  59279. $m = $llB[$j] + $llE[$cTo - $j];
  59280. if ($m >= $max) {
  59281. $max = $m;
  59282. $jMax = $j;
  59283. }
  59284. }
  59285. $toStart = \array_slice($to, 0, $jMax);
  59286. $toEnd = \array_slice($to, $jMax);
  59287. return \array_merge(
  59288. $this->calculate($fromStart, $toStart),
  59289. $this->calculate($fromEnd, $toEnd)
  59290. );
  59291. }
  59292. private function length(array $from, array $to)
  59293. {
  59294. $current = \array_fill(0, \count($to) + 1, 0);
  59295. $cFrom = \count($from);
  59296. $cTo = \count($to);
  59297. for ($i = 0; $i < $cFrom; $i++) {
  59298. $prev = $current;
  59299. for ($j = 0; $j < $cTo; $j++) {
  59300. if ($from[$i] === $to[$j]) {
  59301. $current[$j + 1] = $prev[$j] + 1;
  59302. } else {
  59303. $current[$j + 1] = \max($current[$j], $prev[$j + 1]);
  59304. }
  59305. }
  59306. }
  59307. return $current;
  59308. }
  59309. }
  59310. <?php
  59311. namespace PhpCsFixer\Diff\v1_4\LCS;
  59312. interface LongestCommonSubsequence
  59313. {
  59314. public function calculate(array $from, array $to);
  59315. }
  59316. <?php
  59317. namespace PhpCsFixer\Diff\v1_4;
  59318. class Parser
  59319. {
  59320. public function parse($string)
  59321. {
  59322. $lines = \preg_split('(\r\n|\r|\n)', $string);
  59323. if (!empty($lines) && $lines[\count($lines) - 1] == '') {
  59324. \array_pop($lines);
  59325. }
  59326. $lineCount = \count($lines);
  59327. $diffs = array();
  59328. $diff = null;
  59329. $collected = array();
  59330. for ($i = 0; $i < $lineCount; ++$i) {
  59331. if (\preg_match('(^---\\s+(?P<file>\\S+))', $lines[$i], $fromMatch) &&
  59332. \preg_match('(^\\+\\+\\+\\s+(?P<file>\\S+))', $lines[$i + 1], $toMatch)) {
  59333. if ($diff !== null) {
  59334. $this->parseFileDiff($diff, $collected);
  59335. $diffs[] = $diff;
  59336. $collected = array();
  59337. }
  59338. $diff = new Diff($fromMatch['file'], $toMatch['file']);
  59339. ++$i;
  59340. } else {
  59341. if (\preg_match('/^(?:diff --git |index [\da-f\.]+|[+-]{3} [ab])/', $lines[$i])) {
  59342. continue;
  59343. }
  59344. $collected[] = $lines[$i];
  59345. }
  59346. }
  59347. if ($diff !== null && \count($collected)) {
  59348. $this->parseFileDiff($diff, $collected);
  59349. $diffs[] = $diff;
  59350. }
  59351. return $diffs;
  59352. }
  59353. private function parseFileDiff(Diff $diff, array $lines)
  59354. {
  59355. $chunks = array();
  59356. $chunk = null;
  59357. foreach ($lines as $line) {
  59358. if (\preg_match('/^@@\s+-(?P<start>\d+)(?:,\s*(?P<startrange>\d+))?\s+\+(?P<end>\d+)(?:,\s*(?P<endrange>\d+))?\s+@@/', $line, $match)) {
  59359. $chunk = new Chunk(
  59360. $match['start'],
  59361. isset($match['startrange']) ? \max(1, $match['startrange']) : 1,
  59362. $match['end'],
  59363. isset($match['endrange']) ? \max(1, $match['endrange']) : 1
  59364. );
  59365. $chunks[] = $chunk;
  59366. $diffLines = array();
  59367. continue;
  59368. }
  59369. if (\preg_match('/^(?P<type>[+ -])?(?P<line>.*)/', $line, $match)) {
  59370. $type = Line::UNCHANGED;
  59371. if ($match['type'] === '+') {
  59372. $type = Line::ADDED;
  59373. } elseif ($match['type'] === '-') {
  59374. $type = Line::REMOVED;
  59375. }
  59376. $diffLines[] = new Line($type, $match['line']);
  59377. if (null !== $chunk) {
  59378. $chunk->setLines($diffLines);
  59379. }
  59380. }
  59381. }
  59382. $diff->setChunks($chunks);
  59383. }
  59384. }
  59385. <?php
  59386. namespace PhpCsFixer\Diff\v1_4;
  59387. class Diff
  59388. {
  59389. private $from;
  59390. private $to;
  59391. private $chunks;
  59392. public function __construct($from, $to, array $chunks = array())
  59393. {
  59394. $this->from = $from;
  59395. $this->to = $to;
  59396. $this->chunks = $chunks;
  59397. }
  59398. public function getFrom()
  59399. {
  59400. return $this->from;
  59401. }
  59402. public function getTo()
  59403. {
  59404. return $this->to;
  59405. }
  59406. public function getChunks()
  59407. {
  59408. return $this->chunks;
  59409. }
  59410. public function setChunks(array $chunks)
  59411. {
  59412. $this->chunks = $chunks;
  59413. }
  59414. }
  59415. <?php
  59416. namespace PhpCsFixer\Diff\v3_0;
  59417. final class Chunk
  59418. {
  59419. private $start;
  59420. private $startRange;
  59421. private $end;
  59422. private $endRange;
  59423. private $lines;
  59424. public function __construct($start = 0, $startRange = 1, $end = 0, $endRange = 1, array $lines = [])
  59425. {
  59426. $this->start = $start;
  59427. $this->startRange = $startRange;
  59428. $this->end = $end;
  59429. $this->endRange = $endRange;
  59430. $this->lines = $lines;
  59431. }
  59432. public function getStart()
  59433. {
  59434. return $this->start;
  59435. }
  59436. public function getStartRange()
  59437. {
  59438. return $this->startRange;
  59439. }
  59440. public function getEnd()
  59441. {
  59442. return $this->end;
  59443. }
  59444. public function getEndRange()
  59445. {
  59446. return $this->endRange;
  59447. }
  59448. public function getLines()
  59449. {
  59450. return $this->lines;
  59451. }
  59452. public function setLines(array $lines)
  59453. {
  59454. $this->lines = $lines;
  59455. }
  59456. }
  59457. <?php
  59458. namespace PhpCsFixer\Diff\v3_0;
  59459. final class Line
  59460. {
  59461. const ADDED = 1;
  59462. const REMOVED = 2;
  59463. const UNCHANGED = 3;
  59464. private $type;
  59465. private $content;
  59466. public function __construct($type = self::UNCHANGED, $content = '')
  59467. {
  59468. $this->type = $type;
  59469. $this->content = $content;
  59470. }
  59471. public function getContent()
  59472. {
  59473. return $this->content;
  59474. }
  59475. public function getType()
  59476. {
  59477. return $this->type;
  59478. }
  59479. }
  59480. <?php
  59481. namespace PhpCsFixer\Diff\v3_0;
  59482. use PhpCsFixer\Diff\v3_0\Output\DiffOutputBuilderInterface;
  59483. use PhpCsFixer\Diff\v3_0\Output\UnifiedDiffOutputBuilder;
  59484. final class Differ
  59485. {
  59486. const OLD = 0;
  59487. const ADDED = 1;
  59488. const REMOVED = 2;
  59489. const DIFF_LINE_END_WARNING = 3;
  59490. const NO_LINE_END_EOF_WARNING = 4;
  59491. private $outputBuilder;
  59492. public function __construct($outputBuilder = null)
  59493. {
  59494. if ($outputBuilder instanceof DiffOutputBuilderInterface) {
  59495. $this->outputBuilder = $outputBuilder;
  59496. } elseif (null === $outputBuilder) {
  59497. $this->outputBuilder = new UnifiedDiffOutputBuilder;
  59498. } elseif (\is_string($outputBuilder)) {
  59499. $this->outputBuilder = new UnifiedDiffOutputBuilder($outputBuilder);
  59500. } else {
  59501. throw new InvalidArgumentException(
  59502. \sprintf(
  59503. 'Expected builder to be an instance of DiffOutputBuilderInterface, <null> or a string, got %s.',
  59504. \is_object($outputBuilder) ? 'instance of "' . \get_class($outputBuilder) . '"' : \gettype($outputBuilder) . ' "' . $outputBuilder . '"'
  59505. )
  59506. );
  59507. }
  59508. }
  59509. public function diff($from, $to, LongestCommonSubsequenceCalculator $lcs = null)
  59510. {
  59511. $diff = $this->diffToArray(
  59512. $this->normalizeDiffInput($from),
  59513. $this->normalizeDiffInput($to),
  59514. $lcs
  59515. );
  59516. return $this->outputBuilder->getDiff($diff);
  59517. }
  59518. public function diffToArray($from, $to, LongestCommonSubsequenceCalculator $lcs = null)
  59519. {
  59520. if (\is_string($from)) {
  59521. $from = $this->splitStringByLines($from);
  59522. } elseif (!\is_array($from)) {
  59523. throw new InvalidArgumentException('"from" must be an array or string.');
  59524. }
  59525. if (\is_string($to)) {
  59526. $to = $this->splitStringByLines($to);
  59527. } elseif (!\is_array($to)) {
  59528. throw new InvalidArgumentException('"to" must be an array or string.');
  59529. }
  59530. list($from, $to, $start, $end) = self::getArrayDiffParted($from, $to);
  59531. if ($lcs === null) {
  59532. $lcs = $this->selectLcsImplementation($from, $to);
  59533. }
  59534. $common = $lcs->calculate(\array_values($from), \array_values($to));
  59535. $diff = [];
  59536. foreach ($start as $token) {
  59537. $diff[] = [$token, self::OLD];
  59538. }
  59539. \reset($from);
  59540. \reset($to);
  59541. foreach ($common as $token) {
  59542. while (($fromToken = \reset($from)) !== $token) {
  59543. $diff[] = [\array_shift($from), self::REMOVED];
  59544. }
  59545. while (($toToken = \reset($to)) !== $token) {
  59546. $diff[] = [\array_shift($to), self::ADDED];
  59547. }
  59548. $diff[] = [$token, self::OLD];
  59549. \array_shift($from);
  59550. \array_shift($to);
  59551. }
  59552. while (($token = \array_shift($from)) !== null) {
  59553. $diff[] = [$token, self::REMOVED];
  59554. }
  59555. while (($token = \array_shift($to)) !== null) {
  59556. $diff[] = [$token, self::ADDED];
  59557. }
  59558. foreach ($end as $token) {
  59559. $diff[] = [$token, self::OLD];
  59560. }
  59561. if ($this->detectUnmatchedLineEndings($diff)) {
  59562. \array_unshift($diff, ["#Warnings contain different line endings!\n", self::DIFF_LINE_END_WARNING]);
  59563. }
  59564. return $diff;
  59565. }
  59566. private function normalizeDiffInput($input)
  59567. {
  59568. if (!\is_array($input) && !\is_string($input)) {
  59569. return (string) $input;
  59570. }
  59571. return $input;
  59572. }
  59573. private function splitStringByLines($input)
  59574. {
  59575. return \preg_split('/(.*\R)/', $input, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
  59576. }
  59577. private function selectLcsImplementation(array $from, array $to)
  59578. {
  59579. $memoryLimit = 100 * 1024 * 1024;
  59580. if ($this->calculateEstimatedFootprint($from, $to) > $memoryLimit) {
  59581. return new MemoryEfficientLongestCommonSubsequenceCalculator;
  59582. }
  59583. return new TimeEfficientLongestCommonSubsequenceCalculator;
  59584. }
  59585. private function calculateEstimatedFootprint(array $from, array $to)
  59586. {
  59587. $itemSize = PHP_INT_SIZE === 4 ? 76 : 144;
  59588. return $itemSize * \min(\count($from), \count($to)) ** 2;
  59589. }
  59590. private function detectUnmatchedLineEndings(array $diff)
  59591. {
  59592. $newLineBreaks = ['' => true];
  59593. $oldLineBreaks = ['' => true];
  59594. foreach ($diff as $entry) {
  59595. if (self::OLD === $entry[1]) {
  59596. $ln = $this->getLinebreak($entry[0]);
  59597. $oldLineBreaks[$ln] = true;
  59598. $newLineBreaks[$ln] = true;
  59599. } elseif (self::ADDED === $entry[1]) {
  59600. $newLineBreaks[$this->getLinebreak($entry[0])] = true;
  59601. } elseif (self::REMOVED === $entry[1]) {
  59602. $oldLineBreaks[$this->getLinebreak($entry[0])] = true;
  59603. }
  59604. }
  59605. if (['' => true] === $newLineBreaks || ['' => true] === $oldLineBreaks) {
  59606. return false;
  59607. }
  59608. foreach ($newLineBreaks as $break => $set) {
  59609. if (!isset($oldLineBreaks[$break])) {
  59610. return true;
  59611. }
  59612. }
  59613. foreach ($oldLineBreaks as $break => $set) {
  59614. if (!isset($newLineBreaks[$break])) {
  59615. return true;
  59616. }
  59617. }
  59618. return false;
  59619. }
  59620. private function getLinebreak($line)
  59621. {
  59622. if (!\is_string($line)) {
  59623. return '';
  59624. }
  59625. $lc = \substr($line, -1);
  59626. if ("\r" === $lc) {
  59627. return "\r";
  59628. }
  59629. if ("\n" !== $lc) {
  59630. return '';
  59631. }
  59632. if ("\r\n" === \substr($line, -2)) {
  59633. return "\r\n";
  59634. }
  59635. return "\n";
  59636. }
  59637. private static function getArrayDiffParted(array &$from, array &$to)
  59638. {
  59639. $start = [];
  59640. $end = [];
  59641. \reset($to);
  59642. foreach ($from as $k => $v) {
  59643. $toK = \key($to);
  59644. if ($toK === $k && $v === $to[$k]) {
  59645. $start[$k] = $v;
  59646. unset($from[$k], $to[$k]);
  59647. } else {
  59648. break;
  59649. }
  59650. }
  59651. \end($from);
  59652. \end($to);
  59653. do {
  59654. $fromK = \key($from);
  59655. $toK = \key($to);
  59656. if (null === $fromK || null === $toK || \current($from) !== \current($to)) {
  59657. break;
  59658. }
  59659. \prev($from);
  59660. \prev($to);
  59661. $end = [$fromK => $from[$fromK]] + $end;
  59662. unset($from[$fromK], $to[$toK]);
  59663. } while (true);
  59664. return [$from, $to, $start, $end];
  59665. }
  59666. }
  59667. <?php
  59668. namespace PhpCsFixer\Diff\v3_0;
  59669. final class Parser
  59670. {
  59671. public function parse($string)
  59672. {
  59673. $lines = \preg_split('(\r\n|\r|\n)', $string);
  59674. if (!empty($lines) && $lines[\count($lines) - 1] === '') {
  59675. \array_pop($lines);
  59676. }
  59677. $lineCount = \count($lines);
  59678. $diffs = [];
  59679. $diff = null;
  59680. $collected = [];
  59681. for ($i = 0; $i < $lineCount; ++$i) {
  59682. if (\preg_match('(^---\\s+(?P<file>\\S+))', $lines[$i], $fromMatch) &&
  59683. \preg_match('(^\\+\\+\\+\\s+(?P<file>\\S+))', $lines[$i + 1], $toMatch)) {
  59684. if ($diff !== null) {
  59685. $this->parseFileDiff($diff, $collected);
  59686. $diffs[] = $diff;
  59687. $collected = [];
  59688. }
  59689. $diff = new Diff($fromMatch['file'], $toMatch['file']);
  59690. ++$i;
  59691. } else {
  59692. if (\preg_match('/^(?:diff --git |index [\da-f\.]+|[+-]{3} [ab])/', $lines[$i])) {
  59693. continue;
  59694. }
  59695. $collected[] = $lines[$i];
  59696. }
  59697. }
  59698. if ($diff !== null && \count($collected)) {
  59699. $this->parseFileDiff($diff, $collected);
  59700. $diffs[] = $diff;
  59701. }
  59702. return $diffs;
  59703. }
  59704. private function parseFileDiff(Diff $diff, array $lines)
  59705. {
  59706. $chunks = [];
  59707. $chunk = null;
  59708. foreach ($lines as $line) {
  59709. if (\preg_match('/^@@\s+-(?P<start>\d+)(?:,\s*(?P<startrange>\d+))?\s+\+(?P<end>\d+)(?:,\s*(?P<endrange>\d+))?\s+@@/', $line, $match)) {
  59710. $chunk = new Chunk(
  59711. (int) $match['start'],
  59712. isset($match['startrange']) ? \max(1, (int) $match['startrange']) : 1,
  59713. (int) $match['end'],
  59714. isset($match['endrange']) ? \max(1, (int) $match['endrange']) : 1
  59715. );
  59716. $chunks[] = $chunk;
  59717. $diffLines = [];
  59718. continue;
  59719. }
  59720. if (\preg_match('/^(?P<type>[+ -])?(?P<line>.*)/', $line, $match)) {
  59721. $type = Line::UNCHANGED;
  59722. if ($match['type'] === '+') {
  59723. $type = Line::ADDED;
  59724. } elseif ($match['type'] === '-') {
  59725. $type = Line::REMOVED;
  59726. }
  59727. $diffLines[] = new Line($type, $match['line']);
  59728. if (null !== $chunk) {
  59729. $chunk->setLines($diffLines);
  59730. }
  59731. }
  59732. }
  59733. $diff->setChunks($chunks);
  59734. }
  59735. }
  59736. <?php
  59737. namespace PhpCsFixer\Diff\v3_0;
  59738. final class TimeEfficientLongestCommonSubsequenceCalculator implements LongestCommonSubsequenceCalculator
  59739. {
  59740. public function calculate(array $from, array $to)
  59741. {
  59742. $common = [];
  59743. $fromLength = \count($from);
  59744. $toLength = \count($to);
  59745. $width = $fromLength + 1;
  59746. $matrix = new \SplFixedArray($width * ($toLength + 1));
  59747. for ($i = 0; $i <= $fromLength; ++$i) {
  59748. $matrix[$i] = 0;
  59749. }
  59750. for ($j = 0; $j <= $toLength; ++$j) {
  59751. $matrix[$j * $width] = 0;
  59752. }
  59753. for ($i = 1; $i <= $fromLength; ++$i) {
  59754. for ($j = 1; $j <= $toLength; ++$j) {
  59755. $o = ($j * $width) + $i;
  59756. $matrix[$o] = \max(
  59757. $matrix[$o - 1],
  59758. $matrix[$o - $width],
  59759. $from[$i - 1] === $to[$j - 1] ? $matrix[$o - $width - 1] + 1 : 0
  59760. );
  59761. }
  59762. }
  59763. $i = $fromLength;
  59764. $j = $toLength;
  59765. while ($i > 0 && $j > 0) {
  59766. if ($from[$i - 1] === $to[$j - 1]) {
  59767. $common[] = $from[$i - 1];
  59768. --$i;
  59769. --$j;
  59770. } else {
  59771. $o = ($j * $width) + $i;
  59772. if ($matrix[$o - $width] > $matrix[$o - 1]) {
  59773. --$j;
  59774. } else {
  59775. --$i;
  59776. }
  59777. }
  59778. }
  59779. return \array_reverse($common);
  59780. }
  59781. }
  59782. <?php
  59783. namespace PhpCsFixer\Diff\v3_0\Output;
  59784. use PhpCsFixer\Diff\v3_0\ConfigurationException;
  59785. use PhpCsFixer\Diff\v3_0\Differ;
  59786. final class StrictUnifiedDiffOutputBuilder implements DiffOutputBuilderInterface
  59787. {
  59788. private $changed;
  59789. private $collapseRanges;
  59790. private $commonLineThreshold;
  59791. private $header;
  59792. private $contextLines;
  59793. private static $default = [
  59794. 'collapseRanges' => true,
  59795. 'commonLineThreshold' => 6,
  59796. 'contextLines' => 3,
  59797. 'fromFile' => null,
  59798. 'fromFileDate' => null,
  59799. 'toFile' => null,
  59800. 'toFileDate' => null,
  59801. ];
  59802. public function __construct(array $options = [])
  59803. {
  59804. $options = \array_merge(self::$default, $options);
  59805. if (!\is_bool($options['collapseRanges'])) {
  59806. throw new ConfigurationException('collapseRanges', 'a bool', $options['collapseRanges']);
  59807. }
  59808. if (!\is_int($options['contextLines']) || $options['contextLines'] < 0) {
  59809. throw new ConfigurationException('contextLines', 'an int >= 0', $options['contextLines']);
  59810. }
  59811. if (!\is_int($options['commonLineThreshold']) || $options['commonLineThreshold'] <= 0) {
  59812. throw new ConfigurationException('commonLineThreshold', 'an int > 0', $options['commonLineThreshold']);
  59813. }
  59814. foreach (['fromFile', 'toFile'] as $option) {
  59815. if (!\is_string($options[$option])) {
  59816. throw new ConfigurationException($option, 'a string', $options[$option]);
  59817. }
  59818. }
  59819. foreach (['fromFileDate', 'toFileDate'] as $option) {
  59820. if (null !== $options[$option] && !\is_string($options[$option])) {
  59821. throw new ConfigurationException($option, 'a string or <null>', $options[$option]);
  59822. }
  59823. }
  59824. $this->header = \sprintf(
  59825. "--- %s%s\n+++ %s%s\n",
  59826. $options['fromFile'],
  59827. null === $options['fromFileDate'] ? '' : "\t" . $options['fromFileDate'],
  59828. $options['toFile'],
  59829. null === $options['toFileDate'] ? '' : "\t" . $options['toFileDate']
  59830. );
  59831. $this->collapseRanges = $options['collapseRanges'];
  59832. $this->commonLineThreshold = $options['commonLineThreshold'];
  59833. $this->contextLines = $options['contextLines'];
  59834. }
  59835. public function getDiff(array $diff)
  59836. {
  59837. if (0 === \count($diff)) {
  59838. return '';
  59839. }
  59840. $this->changed = false;
  59841. $buffer = \fopen('php://memory', 'r+b');
  59842. \fwrite($buffer, $this->header);
  59843. $this->writeDiffHunks($buffer, $diff);
  59844. if (!$this->changed) {
  59845. \fclose($buffer);
  59846. return '';
  59847. }
  59848. $diff = \stream_get_contents($buffer, -1, 0);
  59849. \fclose($buffer);
  59850. $last = \substr($diff, -1);
  59851. return "\n" !== $last && "\r" !== $last
  59852. ? $diff . "\n"
  59853. : $diff
  59854. ;
  59855. }
  59856. private function writeDiffHunks($output, array $diff)
  59857. {
  59858. $upperLimit = \count($diff);
  59859. if (0 === $diff[$upperLimit - 1][1]) {
  59860. $lc = \substr($diff[$upperLimit - 1][0], -1);
  59861. if ("\n" !== $lc) {
  59862. \array_splice($diff, $upperLimit, 0, [["\n\\ No newline at end of file\n", Differ::NO_LINE_END_EOF_WARNING]]);
  59863. }
  59864. } else {
  59865. $toFind = [1 => true, 2 => true];
  59866. for ($i = $upperLimit - 1; $i >= 0; --$i) {
  59867. if (isset($toFind[$diff[$i][1]])) {
  59868. unset($toFind[$diff[$i][1]]);
  59869. $lc = \substr($diff[$i][0], -1);
  59870. if ("\n" !== $lc) {
  59871. \array_splice($diff, $i + 1, 0, [["\n\\ No newline at end of file\n", Differ::NO_LINE_END_EOF_WARNING]]);
  59872. }
  59873. if (!\count($toFind)) {
  59874. break;
  59875. }
  59876. }
  59877. }
  59878. }
  59879. $cutOff = \max($this->commonLineThreshold, $this->contextLines);
  59880. $hunkCapture = false;
  59881. $sameCount = $toRange = $fromRange = 0;
  59882. $toStart = $fromStart = 1;
  59883. foreach ($diff as $i => $entry) {
  59884. if (0 === $entry[1]) {
  59885. if (false === $hunkCapture) {
  59886. ++$fromStart;
  59887. ++$toStart;
  59888. continue;
  59889. }
  59890. ++$sameCount;
  59891. ++$toRange;
  59892. ++$fromRange;
  59893. if ($sameCount === $cutOff) {
  59894. $contextStartOffset = ($hunkCapture - $this->contextLines) < 0
  59895. ? $hunkCapture
  59896. : $this->contextLines
  59897. ;
  59898. $this->writeHunk(
  59899. $diff,
  59900. $hunkCapture - $contextStartOffset,
  59901. $i - $cutOff + $this->contextLines + 1,
  59902. $fromStart - $contextStartOffset,
  59903. $fromRange - $cutOff + $contextStartOffset + $this->contextLines,
  59904. $toStart - $contextStartOffset,
  59905. $toRange - $cutOff + $contextStartOffset + $this->contextLines,
  59906. $output
  59907. );
  59908. $fromStart += $fromRange;
  59909. $toStart += $toRange;
  59910. $hunkCapture = false;
  59911. $sameCount = $toRange = $fromRange = 0;
  59912. }
  59913. continue;
  59914. }
  59915. $sameCount = 0;
  59916. if ($entry[1] === Differ::NO_LINE_END_EOF_WARNING) {
  59917. continue;
  59918. }
  59919. $this->changed = true;
  59920. if (false === $hunkCapture) {
  59921. $hunkCapture = $i;
  59922. }
  59923. if (Differ::ADDED === $entry[1]) {
  59924. ++$toRange;
  59925. }
  59926. if (Differ::REMOVED === $entry[1]) {
  59927. ++$fromRange;
  59928. }
  59929. }
  59930. if (false === $hunkCapture) {
  59931. return;
  59932. }
  59933. $contextStartOffset = $hunkCapture - $this->contextLines < 0
  59934. ? $hunkCapture
  59935. : $this->contextLines
  59936. ;
  59937. $contextEndOffset = \min($sameCount, $this->contextLines);
  59938. $fromRange -= $sameCount;
  59939. $toRange -= $sameCount;
  59940. $this->writeHunk(
  59941. $diff,
  59942. $hunkCapture - $contextStartOffset,
  59943. $i - $sameCount + $contextEndOffset + 1,
  59944. $fromStart - $contextStartOffset,
  59945. $fromRange + $contextStartOffset + $contextEndOffset,
  59946. $toStart - $contextStartOffset,
  59947. $toRange + $contextStartOffset + $contextEndOffset,
  59948. $output
  59949. );
  59950. }
  59951. private function writeHunk(
  59952. array $diff,
  59953. $diffStartIndex,
  59954. $diffEndIndex,
  59955. $fromStart,
  59956. $fromRange,
  59957. $toStart,
  59958. $toRange,
  59959. $output
  59960. ) {
  59961. \fwrite($output, '@@ -' . $fromStart);
  59962. if (!$this->collapseRanges || 1 !== $fromRange) {
  59963. \fwrite($output, ',' . $fromRange);
  59964. }
  59965. \fwrite($output, ' +' . $toStart);
  59966. if (!$this->collapseRanges || 1 !== $toRange) {
  59967. \fwrite($output, ',' . $toRange);
  59968. }
  59969. \fwrite($output, " @@\n");
  59970. for ($i = $diffStartIndex; $i < $diffEndIndex; ++$i) {
  59971. if ($diff[$i][1] === Differ::ADDED) {
  59972. $this->changed = true;
  59973. \fwrite($output, '+' . $diff[$i][0]);
  59974. } elseif ($diff[$i][1] === Differ::REMOVED) {
  59975. $this->changed = true;
  59976. \fwrite($output, '-' . $diff[$i][0]);
  59977. } elseif ($diff[$i][1] === Differ::OLD) {
  59978. \fwrite($output, ' ' . $diff[$i][0]);
  59979. } elseif ($diff[$i][1] === Differ::NO_LINE_END_EOF_WARNING) {
  59980. $this->changed = true;
  59981. \fwrite($output, $diff[$i][0]);
  59982. }
  59983. }
  59984. }
  59985. }
  59986. <?php
  59987. namespace PhpCsFixer\Diff\v3_0\Output;
  59988. use PhpCsFixer\Diff\v3_0\Differ;
  59989. final class DiffOnlyOutputBuilder implements DiffOutputBuilderInterface
  59990. {
  59991. private $header;
  59992. public function __construct($header = "--- Original\n+++ New\n")
  59993. {
  59994. $this->header = $header;
  59995. }
  59996. public function getDiff(array $diff)
  59997. {
  59998. $buffer = \fopen('php://memory', 'r+b');
  59999. if ('' !== $this->header) {
  60000. \fwrite($buffer, $this->header);
  60001. if ("\n" !== \substr($this->header, -1, 1)) {
  60002. \fwrite($buffer, "\n");
  60003. }
  60004. }
  60005. foreach ($diff as $diffEntry) {
  60006. if ($diffEntry[1] === Differ::ADDED) {
  60007. \fwrite($buffer, '+' . $diffEntry[0]);
  60008. } elseif ($diffEntry[1] === Differ::REMOVED) {
  60009. \fwrite($buffer, '-' . $diffEntry[0]);
  60010. } elseif ($diffEntry[1] === Differ::DIFF_LINE_END_WARNING) {
  60011. \fwrite($buffer, ' ' . $diffEntry[0]);
  60012. continue;
  60013. } else {
  60014. continue;
  60015. }
  60016. $lc = \substr($diffEntry[0], -1);
  60017. if ($lc !== "\n" && $lc !== "\r") {
  60018. \fwrite($buffer, "\n");
  60019. }
  60020. }
  60021. $diff = \stream_get_contents($buffer, -1, 0);
  60022. \fclose($buffer);
  60023. return $diff;
  60024. }
  60025. }
  60026. <?php
  60027. namespace PhpCsFixer\Diff\v3_0\Output;
  60028. abstract class AbstractChunkOutputBuilder implements DiffOutputBuilderInterface
  60029. {
  60030. protected function getCommonChunks(array $diff, $lineThreshold = 5)
  60031. {
  60032. $diffSize = \count($diff);
  60033. $capturing = false;
  60034. $chunkStart = 0;
  60035. $chunkSize = 0;
  60036. $commonChunks = [];
  60037. for ($i = 0; $i < $diffSize; ++$i) {
  60038. if ($diff[$i][1] === 0 ) {
  60039. if ($capturing === false) {
  60040. $capturing = true;
  60041. $chunkStart = $i;
  60042. $chunkSize = 0;
  60043. } else {
  60044. ++$chunkSize;
  60045. }
  60046. } elseif ($capturing !== false) {
  60047. if ($chunkSize >= $lineThreshold) {
  60048. $commonChunks[$chunkStart] = $chunkStart + $chunkSize;
  60049. }
  60050. $capturing = false;
  60051. }
  60052. }
  60053. if ($capturing !== false && $chunkSize >= $lineThreshold) {
  60054. $commonChunks[$chunkStart] = $chunkStart + $chunkSize;
  60055. }
  60056. return $commonChunks;
  60057. }
  60058. }
  60059. <?php
  60060. namespace PhpCsFixer\Diff\v3_0\Output;
  60061. interface DiffOutputBuilderInterface
  60062. {
  60063. public function getDiff(array $diff);
  60064. }
  60065. <?php
  60066. namespace PhpCsFixer\Diff\v3_0\Output;
  60067. use PhpCsFixer\Diff\v3_0\Differ;
  60068. final class UnifiedDiffOutputBuilder extends AbstractChunkOutputBuilder
  60069. {
  60070. private $collapseRanges = true;
  60071. private $commonLineThreshold = 6;
  60072. private $contextLines = 3;
  60073. private $header;
  60074. private $addLineNumbers;
  60075. public function __construct($header = "--- Original\n+++ New\n", $addLineNumbers = false)
  60076. {
  60077. $this->header = $header;
  60078. $this->addLineNumbers = $addLineNumbers;
  60079. }
  60080. public function getDiff(array $diff)
  60081. {
  60082. $buffer = \fopen('php://memory', 'r+b');
  60083. if ('' !== $this->header) {
  60084. \fwrite($buffer, $this->header);
  60085. if ("\n" !== \substr($this->header, -1, 1)) {
  60086. \fwrite($buffer, "\n");
  60087. }
  60088. }
  60089. if (0 !== \count($diff)) {
  60090. $this->writeDiffHunks($buffer, $diff);
  60091. }
  60092. $diff = \stream_get_contents($buffer, -1, 0);
  60093. \fclose($buffer);
  60094. $last = \substr($diff, -1);
  60095. return "\n" !== $last && "\r" !== $last
  60096. ? $diff . "\n"
  60097. : $diff
  60098. ;
  60099. }
  60100. private function writeDiffHunks($output, array $diff)
  60101. {
  60102. $upperLimit = \count($diff);
  60103. if (0 === $diff[$upperLimit - 1][1]) {
  60104. $lc = \substr($diff[$upperLimit - 1][0], -1);
  60105. if ("\n" !== $lc) {
  60106. \array_splice($diff, $upperLimit, 0, [["\n\\ No newline at end of file\n", Differ::NO_LINE_END_EOF_WARNING]]);
  60107. }
  60108. } else {
  60109. $toFind = [1 => true, 2 => true];
  60110. for ($i = $upperLimit - 1; $i >= 0; --$i) {
  60111. if (isset($toFind[$diff[$i][1]])) {
  60112. unset($toFind[$diff[$i][1]]);
  60113. $lc = \substr($diff[$i][0], -1);
  60114. if ("\n" !== $lc) {
  60115. \array_splice($diff, $i + 1, 0, [["\n\\ No newline at end of file\n", Differ::NO_LINE_END_EOF_WARNING]]);
  60116. }
  60117. if (!\count($toFind)) {
  60118. break;
  60119. }
  60120. }
  60121. }
  60122. }
  60123. $cutOff = \max($this->commonLineThreshold, $this->contextLines);
  60124. $hunkCapture = false;
  60125. $sameCount = $toRange = $fromRange = 0;
  60126. $toStart = $fromStart = 1;
  60127. foreach ($diff as $i => $entry) {
  60128. if (0 === $entry[1]) {
  60129. if (false === $hunkCapture) {
  60130. ++$fromStart;
  60131. ++$toStart;
  60132. continue;
  60133. }
  60134. ++$sameCount;
  60135. ++$toRange;
  60136. ++$fromRange;
  60137. if ($sameCount === $cutOff) {
  60138. $contextStartOffset = ($hunkCapture - $this->contextLines) < 0
  60139. ? $hunkCapture
  60140. : $this->contextLines
  60141. ;
  60142. $this->writeHunk(
  60143. $diff,
  60144. $hunkCapture - $contextStartOffset,
  60145. $i - $cutOff + $this->contextLines + 1,
  60146. $fromStart - $contextStartOffset,
  60147. $fromRange - $cutOff + $contextStartOffset + $this->contextLines,
  60148. $toStart - $contextStartOffset,
  60149. $toRange - $cutOff + $contextStartOffset + $this->contextLines,
  60150. $output
  60151. );
  60152. $fromStart += $fromRange;
  60153. $toStart += $toRange;
  60154. $hunkCapture = false;
  60155. $sameCount = $toRange = $fromRange = 0;
  60156. }
  60157. continue;
  60158. }
  60159. $sameCount = 0;
  60160. if ($entry[1] === Differ::NO_LINE_END_EOF_WARNING) {
  60161. continue;
  60162. }
  60163. if (false === $hunkCapture) {
  60164. $hunkCapture = $i;
  60165. }
  60166. if (Differ::ADDED === $entry[1]) {
  60167. ++$toRange;
  60168. }
  60169. if (Differ::REMOVED === $entry[1]) {
  60170. ++$fromRange;
  60171. }
  60172. }
  60173. if (false === $hunkCapture) {
  60174. return;
  60175. }
  60176. $contextStartOffset = $hunkCapture - $this->contextLines < 0
  60177. ? $hunkCapture
  60178. : $this->contextLines
  60179. ;
  60180. $contextEndOffset = \min($sameCount, $this->contextLines);
  60181. $fromRange -= $sameCount;
  60182. $toRange -= $sameCount;
  60183. $this->writeHunk(
  60184. $diff,
  60185. $hunkCapture - $contextStartOffset,
  60186. $i - $sameCount + $contextEndOffset + 1,
  60187. $fromStart - $contextStartOffset,
  60188. $fromRange + $contextStartOffset + $contextEndOffset,
  60189. $toStart - $contextStartOffset,
  60190. $toRange + $contextStartOffset + $contextEndOffset,
  60191. $output
  60192. );
  60193. }
  60194. private function writeHunk(
  60195. array $diff,
  60196. $diffStartIndex,
  60197. $diffEndIndex,
  60198. $fromStart,
  60199. $fromRange,
  60200. $toStart,
  60201. $toRange,
  60202. $output
  60203. ) {
  60204. if ($this->addLineNumbers) {
  60205. \fwrite($output, '@@ -' . $fromStart);
  60206. if (!$this->collapseRanges || 1 !== $fromRange) {
  60207. \fwrite($output, ',' . $fromRange);
  60208. }
  60209. \fwrite($output, ' +' . $toStart);
  60210. if (!$this->collapseRanges || 1 !== $toRange) {
  60211. \fwrite($output, ',' . $toRange);
  60212. }
  60213. \fwrite($output, " @@\n");
  60214. } else {
  60215. \fwrite($output, "@@ @@\n");
  60216. }
  60217. for ($i = $diffStartIndex; $i < $diffEndIndex; ++$i) {
  60218. if ($diff[$i][1] === Differ::ADDED) {
  60219. \fwrite($output, '+' . $diff[$i][0]);
  60220. } elseif ($diff[$i][1] === Differ::REMOVED) {
  60221. \fwrite($output, '-' . $diff[$i][0]);
  60222. } elseif ($diff[$i][1] === Differ::OLD) {
  60223. \fwrite($output, ' ' . $diff[$i][0]);
  60224. } elseif ($diff[$i][1] === Differ::NO_LINE_END_EOF_WARNING) {
  60225. \fwrite($output, "\n");
  60226. } else {
  60227. \fwrite($output, ' ' . $diff[$i][0]);
  60228. }
  60229. }
  60230. }
  60231. }
  60232. <?php
  60233. namespace PhpCsFixer\Diff\v3_0;
  60234. interface LongestCommonSubsequenceCalculator
  60235. {
  60236. public function calculate(array $from, array $to);
  60237. }
  60238. <?php
  60239. namespace PhpCsFixer\Diff\v3_0;
  60240. final class ConfigurationException extends InvalidArgumentException
  60241. {
  60242. public function __construct(
  60243. $option,
  60244. $expected,
  60245. $value,
  60246. $code = 0,
  60247. \Exception $previous = null
  60248. ) {
  60249. parent::__construct(
  60250. \sprintf(
  60251. 'Option "%s" must be %s, got "%s".',
  60252. $option,
  60253. $expected,
  60254. \is_object($value) ? \get_class($value) : (null === $value ? '<null>' : \gettype($value) . '#' . $value)
  60255. ),
  60256. $code,
  60257. $previous
  60258. );
  60259. }
  60260. }
  60261. <?php
  60262. namespace PhpCsFixer\Diff\v3_0;
  60263. interface Exception
  60264. {
  60265. }
  60266. <?php
  60267. namespace PhpCsFixer\Diff\v3_0;
  60268. class InvalidArgumentException extends \InvalidArgumentException implements Exception
  60269. {
  60270. }
  60271. <?php
  60272. namespace PhpCsFixer\Diff\v3_0;
  60273. final class Diff
  60274. {
  60275. private $from;
  60276. private $to;
  60277. private $chunks;
  60278. public function __construct($from, $to, array $chunks = [])
  60279. {
  60280. $this->from = $from;
  60281. $this->to = $to;
  60282. $this->chunks = $chunks;
  60283. }
  60284. public function getFrom()
  60285. {
  60286. return $this->from;
  60287. }
  60288. public function getTo()
  60289. {
  60290. return $this->to;
  60291. }
  60292. public function getChunks()
  60293. {
  60294. return $this->chunks;
  60295. }
  60296. public function setChunks(array $chunks)
  60297. {
  60298. $this->chunks = $chunks;
  60299. }
  60300. }
  60301. <?php
  60302. namespace PhpCsFixer\Diff\v3_0;
  60303. final class MemoryEfficientLongestCommonSubsequenceCalculator implements LongestCommonSubsequenceCalculator
  60304. {
  60305. public function calculate(array $from, array $to)
  60306. {
  60307. $cFrom = \count($from);
  60308. $cTo = \count($to);
  60309. if ($cFrom === 0) {
  60310. return [];
  60311. }
  60312. if ($cFrom === 1) {
  60313. if (\in_array($from[0], $to, true)) {
  60314. return [$from[0]];
  60315. }
  60316. return [];
  60317. }
  60318. $i = (int) ($cFrom / 2);
  60319. $fromStart = \array_slice($from, 0, $i);
  60320. $fromEnd = \array_slice($from, $i);
  60321. $llB = $this->length($fromStart, $to);
  60322. $llE = $this->length(\array_reverse($fromEnd), \array_reverse($to));
  60323. $jMax = 0;
  60324. $max = 0;
  60325. for ($j = 0; $j <= $cTo; $j++) {
  60326. $m = $llB[$j] + $llE[$cTo - $j];
  60327. if ($m >= $max) {
  60328. $max = $m;
  60329. $jMax = $j;
  60330. }
  60331. }
  60332. $toStart = \array_slice($to, 0, $jMax);
  60333. $toEnd = \array_slice($to, $jMax);
  60334. return \array_merge(
  60335. $this->calculate($fromStart, $toStart),
  60336. $this->calculate($fromEnd, $toEnd)
  60337. );
  60338. }
  60339. private function length(array $from, array $to)
  60340. {
  60341. $current = \array_fill(0, \count($to) + 1, 0);
  60342. $cFrom = \count($from);
  60343. $cTo = \count($to);
  60344. for ($i = 0; $i < $cFrom; $i++) {
  60345. $prev = $current;
  60346. for ($j = 0; $j < $cTo; $j++) {
  60347. if ($from[$i] === $to[$j]) {
  60348. $current[$j + 1] = $prev[$j] + 1;
  60349. } else {
  60350. $current[$j + 1] = \max($current[$j], $prev[$j + 1]);
  60351. }
  60352. }
  60353. }
  60354. return $current;
  60355. }
  60356. }
  60357. <?php
  60358. namespace PhpCsFixer\Diff\GeckoPackages\DiffOutputBuilder;
  60359. use Exception;
  60360. final class ConfigurationException extends \InvalidArgumentException
  60361. {
  60362. public function __construct(
  60363. $option,
  60364. $expected,
  60365. $value,
  60366. $code = 0,
  60367. Exception $previous = null
  60368. ) {
  60369. parent::__construct(
  60370. \sprintf(
  60371. 'Option "%s" must be %s, got "%s".',
  60372. $option,
  60373. $expected,
  60374. \is_object($value) ? \get_class($value) : (null === $value ? '<null>' : \gettype($value).'#'.$value)
  60375. ),
  60376. $code,
  60377. $previous
  60378. );
  60379. }
  60380. }
  60381. <?php
  60382. namespace PhpCsFixer\Diff\GeckoPackages\DiffOutputBuilder;
  60383. use PhpCsFixer\Diff\v2_0\Output\DiffOutputBuilderInterface;
  60384. /**
  60385. @description
  60386. */
  60387. final class UnifiedDiffOutputBuilder implements DiffOutputBuilderInterface
  60388. {
  60389. private static $noNewlineAtOEFid = 998877;
  60390. private $changed;
  60391. private $collapseRanges;
  60392. private $commonLineThreshold;
  60393. private $header;
  60394. private $contextLines;
  60395. private static $default = [
  60396. 'contextLines' => 3,
  60397. 'collapseRanges' => true,
  60398. 'fromFile' => null,
  60399. 'fromFileDate' => null,
  60400. 'toFile' => null,
  60401. 'toFileDate' => null,
  60402. 'commonLineThreshold' => 6,
  60403. ];
  60404. public function __construct(array $options = [])
  60405. {
  60406. $options = \array_merge(self::$default, $options);
  60407. if (!\is_bool($options['collapseRanges'])) {
  60408. throw new ConfigurationException('collapseRanges', 'a bool', $options['collapseRanges']);
  60409. }
  60410. if (!\is_int($options['contextLines']) || $options['contextLines'] < 0) {
  60411. throw new ConfigurationException('contextLines', 'an int >= 0', $options['contextLines']);
  60412. }
  60413. if (!\is_int($options['commonLineThreshold']) || $options['commonLineThreshold'] < 1) {
  60414. throw new ConfigurationException('commonLineThreshold', 'an int > 0', $options['commonLineThreshold']);
  60415. }
  60416. foreach (['fromFile', 'toFile'] as $option) {
  60417. if (!\is_string($options[$option])) {
  60418. throw new ConfigurationException($option, 'a string', $options[$option]);
  60419. }
  60420. }
  60421. foreach (['fromFileDate', 'toFileDate'] as $option) {
  60422. if (null !== $options[$option] && !\is_string($options[$option])) {
  60423. throw new ConfigurationException($option, 'a string or <null>', $options[$option]);
  60424. }
  60425. }
  60426. $this->header = \sprintf(
  60427. "--- %s%s\n+++ %s%s\n",
  60428. $options['fromFile'],
  60429. null === $options['fromFileDate'] ? '' : "\t".$options['fromFileDate'],
  60430. $options['toFile'],
  60431. null === $options['toFileDate'] ? '' : "\t".$options['toFileDate']
  60432. );
  60433. $this->collapseRanges = $options['collapseRanges'];
  60434. $this->commonLineThreshold = $options['commonLineThreshold'];
  60435. $this->contextLines = $options['contextLines'];
  60436. }
  60437. public function getDiff(array $diff)
  60438. {
  60439. if (0 === \count($diff)) {
  60440. return '';
  60441. }
  60442. $this->changed = false;
  60443. $buffer = \fopen('php://memory', 'r+b');
  60444. \fwrite($buffer, $this->header);
  60445. $this->writeDiffHunks($buffer, $diff);
  60446. $diff = \stream_get_contents($buffer, -1, 0);
  60447. \fclose($buffer);
  60448. if (!$this->changed) {
  60449. return '';
  60450. }
  60451. return $diff;
  60452. }
  60453. private function writeDiffHunks($output, array $diff)
  60454. {
  60455. $upperLimit = \count($diff);
  60456. if (0 === $diff[$upperLimit - 1][1]) {
  60457. $lc = \substr($diff[$upperLimit - 1][0], -1);
  60458. if ("\n" !== $lc) {
  60459. \array_splice($diff, $upperLimit, 0, [["\n\\ No newline at end of file\n", self::$noNewlineAtOEFid]]);
  60460. }
  60461. } else {
  60462. $toFind = [1 => true, 2 => true];
  60463. for ($i = $upperLimit - 1; $i >= 0; --$i) {
  60464. if (isset($toFind[$diff[$i][1]])) {
  60465. unset($toFind[$diff[$i][1]]);
  60466. $lc = \substr($diff[$i][0], -1);
  60467. if ("\n" !== $lc) {
  60468. \array_splice($diff, $i + 1, 0, [["\n\\ No newline at end of file\n", self::$noNewlineAtOEFid]]);
  60469. }
  60470. if (!\count($toFind)) {
  60471. break;
  60472. }
  60473. }
  60474. }
  60475. }
  60476. $cutOff = \max($this->commonLineThreshold, $this->contextLines);
  60477. $hunkCapture = false;
  60478. $sameCount = $toRange = $fromRange = 0;
  60479. $toStart = $fromStart = 1;
  60480. foreach ($diff as $i => $entry) {
  60481. if (0 === $entry[1]) {
  60482. if (false === $hunkCapture) {
  60483. ++$fromStart;
  60484. ++$toStart;
  60485. continue;
  60486. }
  60487. ++$sameCount;
  60488. ++$toRange;
  60489. ++$fromRange;
  60490. if ($sameCount === $cutOff) {
  60491. $contextStartOffset = $hunkCapture - $this->contextLines < 0
  60492. ? $hunkCapture
  60493. : $this->contextLines
  60494. ;
  60495. $contextEndOffset = $i + $this->contextLines >= \count($diff)
  60496. ? \count($diff) - $i
  60497. : $this->contextLines
  60498. ;
  60499. $this->writeHunk(
  60500. $diff,
  60501. $hunkCapture - $contextStartOffset,
  60502. $i - $cutOff + $contextEndOffset + 1,
  60503. $fromStart - $contextStartOffset,
  60504. $fromRange - $cutOff + $contextStartOffset + $contextEndOffset,
  60505. $toStart - $contextStartOffset,
  60506. $toRange - $cutOff + $contextStartOffset + $contextEndOffset,
  60507. $output
  60508. );
  60509. $fromStart += $fromRange;
  60510. $toStart += $toRange;
  60511. $hunkCapture = false;
  60512. $sameCount = $toRange = $fromRange = 0;
  60513. }
  60514. continue;
  60515. }
  60516. $sameCount = 0;
  60517. if ($entry[1] === self::$noNewlineAtOEFid) {
  60518. continue;
  60519. }
  60520. $this->changed = true;
  60521. if (false === $hunkCapture) {
  60522. $hunkCapture = $i;
  60523. }
  60524. if (1 === $entry[1]) {
  60525. ++$toRange;
  60526. }
  60527. if (2 === $entry[1]) {
  60528. ++$fromRange;
  60529. }
  60530. }
  60531. if (false !== $hunkCapture) {
  60532. $contextStartOffset = $hunkCapture - $this->contextLines < 0
  60533. ? $hunkCapture
  60534. : $this->contextLines
  60535. ;
  60536. $this->writeHunk(
  60537. $diff,
  60538. $hunkCapture - $contextStartOffset,
  60539. \count($diff),
  60540. $fromStart - $contextStartOffset,
  60541. $fromRange + $contextStartOffset,
  60542. $toStart - $contextStartOffset,
  60543. $toRange + $contextStartOffset,
  60544. $output
  60545. );
  60546. }
  60547. }
  60548. private function writeHunk(
  60549. array $diff,
  60550. $diffStartIndex,
  60551. $diffEndIndex,
  60552. $fromStart,
  60553. $fromRange,
  60554. $toStart,
  60555. $toRange,
  60556. $output
  60557. ) {
  60558. \fwrite($output, '@@ -'.$fromStart);
  60559. if (!$this->collapseRanges || 1 !== $fromRange) {
  60560. \fwrite($output, ','.$fromRange);
  60561. }
  60562. \fwrite($output, ' +'.$toStart);
  60563. if (!$this->collapseRanges || 1 !== $toRange) {
  60564. \fwrite($output, ','.$toRange);
  60565. }
  60566. \fwrite($output, " @@\n");
  60567. for ($i = $diffStartIndex; $i < $diffEndIndex; ++$i) {
  60568. if ($diff[$i][1] === 1) {
  60569. $this->changed = true;
  60570. \fwrite($output, '+'.$diff[$i][0]);
  60571. } elseif ($diff[$i][1] === 2) {
  60572. $this->changed = true;
  60573. \fwrite($output, '-'.$diff[$i][0]);
  60574. } elseif ($diff[$i][1] === 0) {
  60575. \fwrite($output, ' '.$diff[$i][0]);
  60576. } elseif ($diff[$i][1] === self::$noNewlineAtOEFid) {
  60577. $this->changed = true;
  60578. \fwrite($output, $diff[$i][0]);
  60579. }
  60580. }
  60581. }
  60582. }
  60583. <?php
  60584. namespace PhpCsFixer\Diff\v2_0;
  60585. final class Chunk
  60586. {
  60587. private $start;
  60588. private $startRange;
  60589. private $end;
  60590. private $endRange;
  60591. private $lines;
  60592. public function __construct($start = 0, $startRange = 1, $end = 0, $endRange = 1, array $lines = [])
  60593. {
  60594. $this->start = $start;
  60595. $this->startRange = $startRange;
  60596. $this->end = $end;
  60597. $this->endRange = $endRange;
  60598. $this->lines = $lines;
  60599. }
  60600. public function getStart()
  60601. {
  60602. return $this->start;
  60603. }
  60604. public function getStartRange()
  60605. {
  60606. return $this->startRange;
  60607. }
  60608. public function getEnd()
  60609. {
  60610. return $this->end;
  60611. }
  60612. public function getEndRange()
  60613. {
  60614. return $this->endRange;
  60615. }
  60616. public function getLines()
  60617. {
  60618. return $this->lines;
  60619. }
  60620. public function setLines(array $lines)
  60621. {
  60622. $this->lines = $lines;
  60623. }
  60624. }
  60625. <?php
  60626. namespace PhpCsFixer\Diff\v2_0;
  60627. final class Line
  60628. {
  60629. const ADDED = 1;
  60630. const REMOVED = 2;
  60631. const UNCHANGED = 3;
  60632. private $type;
  60633. private $content;
  60634. public function __construct($type = self::UNCHANGED, $content = '')
  60635. {
  60636. $this->type = $type;
  60637. $this->content = $content;
  60638. }
  60639. public function getContent()
  60640. {
  60641. return $this->content;
  60642. }
  60643. public function getType()
  60644. {
  60645. return $this->type;
  60646. }
  60647. }
  60648. <?php
  60649. namespace PhpCsFixer\Diff\v2_0;
  60650. use PhpCsFixer\Diff\v2_0\Output\DiffOutputBuilderInterface;
  60651. use PhpCsFixer\Diff\v2_0\Output\UnifiedDiffOutputBuilder;
  60652. final class Differ
  60653. {
  60654. private $outputBuilder;
  60655. public function __construct($outputBuilder = null)
  60656. {
  60657. if ($outputBuilder instanceof DiffOutputBuilderInterface) {
  60658. $this->outputBuilder = $outputBuilder;
  60659. } elseif (null === $outputBuilder) {
  60660. $this->outputBuilder = new UnifiedDiffOutputBuilder;
  60661. } elseif (\is_string($outputBuilder)) {
  60662. $this->outputBuilder = new UnifiedDiffOutputBuilder($outputBuilder);
  60663. } else {
  60664. throw new InvalidArgumentException(
  60665. \sprintf(
  60666. 'Expected builder to be an instance of DiffOutputBuilderInterface, <null> or a string, got %s.',
  60667. \is_object($outputBuilder) ? 'instance of "' . \get_class($outputBuilder) . '"' : \gettype($outputBuilder) . ' "' . $outputBuilder . '"'
  60668. )
  60669. );
  60670. }
  60671. }
  60672. public function diff($from, $to, LongestCommonSubsequenceCalculator $lcs = null)
  60673. {
  60674. $from = $this->validateDiffInput($from);
  60675. $to = $this->validateDiffInput($to);
  60676. $diff = $this->diffToArray($from, $to, $lcs);
  60677. return $this->outputBuilder->getDiff($diff);
  60678. }
  60679. private function validateDiffInput($input)
  60680. {
  60681. if (!\is_array($input) && !\is_string($input)) {
  60682. return (string) $input;
  60683. }
  60684. return $input;
  60685. }
  60686. public function diffToArray($from, $to, LongestCommonSubsequenceCalculator $lcs = null)
  60687. {
  60688. if (\is_string($from)) {
  60689. $from = $this->splitStringByLines($from);
  60690. } elseif (!\is_array($from)) {
  60691. throw new \InvalidArgumentException('"from" must be an array or string.');
  60692. }
  60693. if (\is_string($to)) {
  60694. $to = $this->splitStringByLines($to);
  60695. } elseif (!\is_array($to)) {
  60696. throw new \InvalidArgumentException('"to" must be an array or string.');
  60697. }
  60698. list($from, $to, $start, $end) = self::getArrayDiffParted($from, $to);
  60699. if ($lcs === null) {
  60700. $lcs = $this->selectLcsImplementation($from, $to);
  60701. }
  60702. $common = $lcs->calculate(\array_values($from), \array_values($to));
  60703. $diff = [];
  60704. foreach ($start as $token) {
  60705. $diff[] = [$token, 0 ];
  60706. }
  60707. \reset($from);
  60708. \reset($to);
  60709. foreach ($common as $token) {
  60710. while (($fromToken = \reset($from)) !== $token) {
  60711. $diff[] = [\array_shift($from), 2 ];
  60712. }
  60713. while (($toToken = \reset($to)) !== $token) {
  60714. $diff[] = [\array_shift($to), 1 ];
  60715. }
  60716. $diff[] = [$token, 0 ];
  60717. \array_shift($from);
  60718. \array_shift($to);
  60719. }
  60720. while (($token = \array_shift($from)) !== null) {
  60721. $diff[] = [$token, 2 ];
  60722. }
  60723. while (($token = \array_shift($to)) !== null) {
  60724. $diff[] = [$token, 1 ];
  60725. }
  60726. foreach ($end as $token) {
  60727. $diff[] = [$token, 0 ];
  60728. }
  60729. if ($this->detectUnmatchedLineEndings($diff)) {
  60730. \array_unshift($diff, ["#Warnings contain different line endings!\n", 3]);
  60731. }
  60732. return $diff;
  60733. }
  60734. private function splitStringByLines($input)
  60735. {
  60736. return \preg_split('/(.*\R)/', $input, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
  60737. }
  60738. private function selectLcsImplementation(array $from, array $to)
  60739. {
  60740. $memoryLimit = 100 * 1024 * 1024;
  60741. if ($this->calculateEstimatedFootprint($from, $to) > $memoryLimit) {
  60742. return new MemoryEfficientLongestCommonSubsequenceCalculator;
  60743. }
  60744. return new TimeEfficientLongestCommonSubsequenceCalculator;
  60745. }
  60746. private function calculateEstimatedFootprint(array $from, array $to)
  60747. {
  60748. $itemSize = PHP_INT_SIZE === 4 ? 76 : 144;
  60749. return $itemSize * \min(\count($from), \count($to)) ** 2;
  60750. }
  60751. private function detectUnmatchedLineEndings(array $diff)
  60752. {
  60753. $newLineBreaks = ['' => true];
  60754. $oldLineBreaks = ['' => true];
  60755. foreach ($diff as $entry) {
  60756. if (0 === $entry[1]) {
  60757. $ln = $this->getLinebreak($entry[0]);
  60758. $oldLineBreaks[$ln] = true;
  60759. $newLineBreaks[$ln] = true;
  60760. } elseif (1 === $entry[1]) {
  60761. $newLineBreaks[$this->getLinebreak($entry[0])] = true;
  60762. } elseif (2 === $entry[1]) {
  60763. $oldLineBreaks[$this->getLinebreak($entry[0])] = true;
  60764. }
  60765. }
  60766. if (['' => true] === $newLineBreaks || ['' => true] === $oldLineBreaks) {
  60767. return false;
  60768. }
  60769. foreach ($newLineBreaks as $break => $set) {
  60770. if (!isset($oldLineBreaks[$break])) {
  60771. return true;
  60772. }
  60773. }
  60774. foreach ($oldLineBreaks as $break => $set) {
  60775. if (!isset($newLineBreaks[$break])) {
  60776. return true;
  60777. }
  60778. }
  60779. return false;
  60780. }
  60781. private function getLinebreak($line)
  60782. {
  60783. if (!\is_string($line)) {
  60784. return '';
  60785. }
  60786. $lc = \substr($line, -1);
  60787. if ("\r" === $lc) {
  60788. return "\r";
  60789. }
  60790. if ("\n" !== $lc) {
  60791. return '';
  60792. }
  60793. if ("\r\n" === \substr($line, -2)) {
  60794. return "\r\n";
  60795. }
  60796. return "\n";
  60797. }
  60798. private static function getArrayDiffParted(array &$from, array &$to)
  60799. {
  60800. $start = [];
  60801. $end = [];
  60802. \reset($to);
  60803. foreach ($from as $k => $v) {
  60804. $toK = \key($to);
  60805. if ($toK === $k && $v === $to[$k]) {
  60806. $start[$k] = $v;
  60807. unset($from[$k], $to[$k]);
  60808. } else {
  60809. break;
  60810. }
  60811. }
  60812. \end($from);
  60813. \end($to);
  60814. do {
  60815. $fromK = \key($from);
  60816. $toK = \key($to);
  60817. if (null === $fromK || null === $toK || \current($from) !== \current($to)) {
  60818. break;
  60819. }
  60820. \prev($from);
  60821. \prev($to);
  60822. $end = [$fromK => $from[$fromK]] + $end;
  60823. unset($from[$fromK], $to[$toK]);
  60824. } while (true);
  60825. return [$from, $to, $start, $end];
  60826. }
  60827. }
  60828. <?php
  60829. namespace PhpCsFixer\Diff\v2_0;
  60830. final class Parser
  60831. {
  60832. public function parse($string)
  60833. {
  60834. $lines = \preg_split('(\r\n|\r|\n)', $string);
  60835. if (!empty($lines) && $lines[\count($lines) - 1] === '') {
  60836. \array_pop($lines);
  60837. }
  60838. $lineCount = \count($lines);
  60839. $diffs = [];
  60840. $diff = null;
  60841. $collected = [];
  60842. for ($i = 0; $i < $lineCount; ++$i) {
  60843. if (\preg_match('(^---\\s+(?P<file>\\S+))', $lines[$i], $fromMatch) &&
  60844. \preg_match('(^\\+\\+\\+\\s+(?P<file>\\S+))', $lines[$i + 1], $toMatch)) {
  60845. if ($diff !== null) {
  60846. $this->parseFileDiff($diff, $collected);
  60847. $diffs[] = $diff;
  60848. $collected = [];
  60849. }
  60850. $diff = new Diff($fromMatch['file'], $toMatch['file']);
  60851. ++$i;
  60852. } else {
  60853. if (\preg_match('/^(?:diff --git |index [\da-f\.]+|[+-]{3} [ab])/', $lines[$i])) {
  60854. continue;
  60855. }
  60856. $collected[] = $lines[$i];
  60857. }
  60858. }
  60859. if ($diff !== null && \count($collected)) {
  60860. $this->parseFileDiff($diff, $collected);
  60861. $diffs[] = $diff;
  60862. }
  60863. return $diffs;
  60864. }
  60865. private function parseFileDiff(Diff $diff, array $lines)
  60866. {
  60867. $chunks = [];
  60868. $chunk = null;
  60869. foreach ($lines as $line) {
  60870. if (\preg_match('/^@@\s+-(?P<start>\d+)(?:,\s*(?P<startrange>\d+))?\s+\+(?P<end>\d+)(?:,\s*(?P<endrange>\d+))?\s+@@/', $line, $match)) {
  60871. $chunk = new Chunk(
  60872. (int) $match['start'],
  60873. isset($match['startrange']) ? \max(1, (int) $match['startrange']) : 1,
  60874. (int) $match['end'],
  60875. isset($match['endrange']) ? \max(1, (int) $match['endrange']) : 1
  60876. );
  60877. $chunks[] = $chunk;
  60878. $diffLines = [];
  60879. continue;
  60880. }
  60881. if (\preg_match('/^(?P<type>[+ -])?(?P<line>.*)/', $line, $match)) {
  60882. $type = Line::UNCHANGED;
  60883. if ($match['type'] === '+') {
  60884. $type = Line::ADDED;
  60885. } elseif ($match['type'] === '-') {
  60886. $type = Line::REMOVED;
  60887. }
  60888. $diffLines[] = new Line($type, $match['line']);
  60889. if (null !== $chunk) {
  60890. $chunk->setLines($diffLines);
  60891. }
  60892. }
  60893. }
  60894. $diff->setChunks($chunks);
  60895. }
  60896. }
  60897. <?php
  60898. namespace PhpCsFixer\Diff\v2_0;
  60899. final class TimeEfficientLongestCommonSubsequenceCalculator implements LongestCommonSubsequenceCalculator
  60900. {
  60901. public function calculate(array $from, array $to)
  60902. {
  60903. $common = [];
  60904. $fromLength = \count($from);
  60905. $toLength = \count($to);
  60906. $width = $fromLength + 1;
  60907. $matrix = new \SplFixedArray($width * ($toLength + 1));
  60908. for ($i = 0; $i <= $fromLength; ++$i) {
  60909. $matrix[$i] = 0;
  60910. }
  60911. for ($j = 0; $j <= $toLength; ++$j) {
  60912. $matrix[$j * $width] = 0;
  60913. }
  60914. for ($i = 1; $i <= $fromLength; ++$i) {
  60915. for ($j = 1; $j <= $toLength; ++$j) {
  60916. $o = ($j * $width) + $i;
  60917. $matrix[$o] = \max(
  60918. $matrix[$o - 1],
  60919. $matrix[$o - $width],
  60920. $from[$i - 1] === $to[$j - 1] ? $matrix[$o - $width - 1] + 1 : 0
  60921. );
  60922. }
  60923. }
  60924. $i = $fromLength;
  60925. $j = $toLength;
  60926. while ($i > 0 && $j > 0) {
  60927. if ($from[$i - 1] === $to[$j - 1]) {
  60928. $common[] = $from[$i - 1];
  60929. --$i;
  60930. --$j;
  60931. } else {
  60932. $o = ($j * $width) + $i;
  60933. if ($matrix[$o - $width] > $matrix[$o - 1]) {
  60934. --$j;
  60935. } else {
  60936. --$i;
  60937. }
  60938. }
  60939. }
  60940. return \array_reverse($common);
  60941. }
  60942. }
  60943. <?php
  60944. namespace PhpCsFixer\Diff\v2_0\Output;
  60945. final class DiffOnlyOutputBuilder implements DiffOutputBuilderInterface
  60946. {
  60947. private $header;
  60948. public function __construct($header = "--- Original\n+++ New\n")
  60949. {
  60950. $this->header = $header;
  60951. }
  60952. public function getDiff(array $diff)
  60953. {
  60954. $buffer = \fopen('php://memory', 'r+b');
  60955. if ('' !== $this->header) {
  60956. \fwrite($buffer, $this->header);
  60957. if ("\n" !== \substr($this->header, -1, 1)) {
  60958. \fwrite($buffer, "\n");
  60959. }
  60960. }
  60961. foreach ($diff as $diffEntry) {
  60962. if ($diffEntry[1] === 1 ) {
  60963. \fwrite($buffer, '+' . $diffEntry[0]);
  60964. } elseif ($diffEntry[1] === 2 ) {
  60965. \fwrite($buffer, '-' . $diffEntry[0]);
  60966. } elseif ($diffEntry[1] === 3 ) {
  60967. \fwrite($buffer, ' ' . $diffEntry[0]);
  60968. continue;
  60969. } else {
  60970. continue;
  60971. }
  60972. $lc = \substr($diffEntry[0], -1);
  60973. if ($lc !== "\n" && $lc !== "\r") {
  60974. \fwrite($buffer, "\n");
  60975. }
  60976. }
  60977. $diff = \stream_get_contents($buffer, -1, 0);
  60978. \fclose($buffer);
  60979. return $diff;
  60980. }
  60981. }
  60982. <?php
  60983. namespace PhpCsFixer\Diff\v2_0\Output;
  60984. abstract class AbstractChunkOutputBuilder implements DiffOutputBuilderInterface
  60985. {
  60986. protected function getCommonChunks(array $diff, $lineThreshold = 5)
  60987. {
  60988. $diffSize = \count($diff);
  60989. $capturing = false;
  60990. $chunkStart = 0;
  60991. $chunkSize = 0;
  60992. $commonChunks = [];
  60993. for ($i = 0; $i < $diffSize; ++$i) {
  60994. if ($diff[$i][1] === 0 ) {
  60995. if ($capturing === false) {
  60996. $capturing = true;
  60997. $chunkStart = $i;
  60998. $chunkSize = 0;
  60999. } else {
  61000. ++$chunkSize;
  61001. }
  61002. } elseif ($capturing !== false) {
  61003. if ($chunkSize >= $lineThreshold) {
  61004. $commonChunks[$chunkStart] = $chunkStart + $chunkSize;
  61005. }
  61006. $capturing = false;
  61007. }
  61008. }
  61009. if ($capturing !== false && $chunkSize >= $lineThreshold) {
  61010. $commonChunks[$chunkStart] = $chunkStart + $chunkSize;
  61011. }
  61012. return $commonChunks;
  61013. }
  61014. }
  61015. <?php
  61016. namespace PhpCsFixer\Diff\v2_0\Output;
  61017. interface DiffOutputBuilderInterface
  61018. {
  61019. public function getDiff(array $diff);
  61020. }
  61021. <?php
  61022. namespace PhpCsFixer\Diff\v2_0\Output;
  61023. final class UnifiedDiffOutputBuilder extends AbstractChunkOutputBuilder
  61024. {
  61025. private $header;
  61026. private $addLineNumbers;
  61027. public function __construct($header = "--- Original\n+++ New\n", $addLineNumbers = false)
  61028. {
  61029. $this->header = $header;
  61030. $this->addLineNumbers = $addLineNumbers;
  61031. }
  61032. public function getDiff(array $diff)
  61033. {
  61034. $buffer = \fopen('php://memory', 'r+b');
  61035. if ('' !== $this->header) {
  61036. \fwrite($buffer, $this->header);
  61037. if ("\n" !== \substr($this->header, -1, 1)) {
  61038. \fwrite($buffer, "\n");
  61039. }
  61040. }
  61041. $this->writeDiffChunked($buffer, $diff, $this->getCommonChunks($diff));
  61042. $diff = \stream_get_contents($buffer, -1, 0);
  61043. \fclose($buffer);
  61044. return $diff;
  61045. }
  61046. private function writeDiffChunked($output, array $diff, array $old)
  61047. {
  61048. $upperLimit = \count($diff);
  61049. $start = 0;
  61050. $fromStart = 0;
  61051. $toStart = 0;
  61052. if (\count($old)) {
  61053. \reset($old);
  61054. do {
  61055. $commonStart = \key($old);
  61056. $commonEnd = \current($old);
  61057. if ($commonStart !== $start) {
  61058. list($fromRange, $toRange) = $this->getChunkRange($diff, $start, $commonStart);
  61059. $this->writeChunk($output, $diff, $start, $commonStart, $fromStart, $fromRange, $toStart, $toRange);
  61060. $fromStart += $fromRange;
  61061. $toStart += $toRange;
  61062. }
  61063. $start = $commonEnd + 1;
  61064. $commonLength = $commonEnd - $commonStart + 1;
  61065. $fromStart += $commonLength;
  61066. $toStart += $commonLength;
  61067. } while (false !== \next($old));
  61068. \end($old);
  61069. $tmp = \key($old);
  61070. \reset($old);
  61071. if ($old[$tmp] === $upperLimit - 1) {
  61072. $upperLimit = $tmp;
  61073. }
  61074. }
  61075. if ($start < $upperLimit - 1) {
  61076. do {
  61077. --$upperLimit;
  61078. } while (isset($diff[$upperLimit][1]) && $diff[$upperLimit][1] === 0);
  61079. ++$upperLimit;
  61080. list($fromRange, $toRange) = $this->getChunkRange($diff, $start, $upperLimit);
  61081. $this->writeChunk($output, $diff, $start, $upperLimit, $fromStart, $fromRange, $toStart, $toRange);
  61082. }
  61083. }
  61084. private function writeChunk(
  61085. $output,
  61086. array $diff,
  61087. $diffStartIndex,
  61088. $diffEndIndex,
  61089. $fromStart,
  61090. $fromRange,
  61091. $toStart,
  61092. $toRange
  61093. ) {
  61094. if ($this->addLineNumbers) {
  61095. \fwrite($output, '@@ -' . (1 + $fromStart));
  61096. if ($fromRange !== 1) {
  61097. \fwrite($output, ',' . $fromRange);
  61098. }
  61099. \fwrite($output, ' +' . (1 + $toStart));
  61100. if ($toRange !== 1) {
  61101. \fwrite($output, ',' . $toRange);
  61102. }
  61103. \fwrite($output, " @@\n");
  61104. } else {
  61105. \fwrite($output, "@@ @@\n");
  61106. }
  61107. for ($i = $diffStartIndex; $i < $diffEndIndex; ++$i) {
  61108. if ($diff[$i][1] === 1 ) {
  61109. \fwrite($output, '+' . $diff[$i][0]);
  61110. } elseif ($diff[$i][1] === 2 ) {
  61111. \fwrite($output, '-' . $diff[$i][0]);
  61112. } else {
  61113. \fwrite($output, ' ' . $diff[$i][0]);
  61114. }
  61115. $lc = \substr($diff[$i][0], -1);
  61116. if ($lc !== "\n" && $lc !== "\r") {
  61117. \fwrite($output, "\n");
  61118. }
  61119. }
  61120. }
  61121. private function getChunkRange(array $diff, $diffStartIndex, $diffEndIndex)
  61122. {
  61123. $toRange = 0;
  61124. $fromRange = 0;
  61125. for ($i = $diffStartIndex; $i < $diffEndIndex; ++$i) {
  61126. if ($diff[$i][1] === 1) {
  61127. ++$toRange;
  61128. } elseif ($diff[$i][1] === 2) {
  61129. ++$fromRange;
  61130. } elseif ($diff[$i][1] === 0) {
  61131. ++$fromRange;
  61132. ++$toRange;
  61133. }
  61134. }
  61135. return [$fromRange, $toRange];
  61136. }
  61137. }
  61138. <?php
  61139. namespace PhpCsFixer\Diff\v2_0;
  61140. interface LongestCommonSubsequenceCalculator
  61141. {
  61142. public function calculate(array $from, array $to);
  61143. }
  61144. <?php
  61145. namespace PhpCsFixer\Diff\v2_0;
  61146. interface Exception
  61147. {
  61148. }
  61149. <?php
  61150. namespace PhpCsFixer\Diff\v2_0;
  61151. class InvalidArgumentException extends \InvalidArgumentException implements Exception
  61152. {
  61153. }
  61154. <?php
  61155. namespace PhpCsFixer\Diff\v2_0;
  61156. final class Diff
  61157. {
  61158. private $from;
  61159. private $to;
  61160. private $chunks;
  61161. public function __construct($from, $to, array $chunks = [])
  61162. {
  61163. $this->from = $from;
  61164. $this->to = $to;
  61165. $this->chunks = $chunks;
  61166. }
  61167. public function getFrom()
  61168. {
  61169. return $this->from;
  61170. }
  61171. public function getTo()
  61172. {
  61173. return $this->to;
  61174. }
  61175. public function getChunks()
  61176. {
  61177. return $this->chunks;
  61178. }
  61179. public function setChunks(array $chunks)
  61180. {
  61181. $this->chunks = $chunks;
  61182. }
  61183. }
  61184. <?php
  61185. namespace PhpCsFixer\Diff\v2_0;
  61186. final class MemoryEfficientLongestCommonSubsequenceCalculator implements LongestCommonSubsequenceCalculator
  61187. {
  61188. public function calculate(array $from, array $to)
  61189. {
  61190. $cFrom = \count($from);
  61191. $cTo = \count($to);
  61192. if ($cFrom === 0) {
  61193. return [];
  61194. }
  61195. if ($cFrom === 1) {
  61196. if (\in_array($from[0], $to, true)) {
  61197. return [$from[0]];
  61198. }
  61199. return [];
  61200. }
  61201. $i = (int) ($cFrom / 2);
  61202. $fromStart = \array_slice($from, 0, $i);
  61203. $fromEnd = \array_slice($from, $i);
  61204. $llB = $this->length($fromStart, $to);
  61205. $llE = $this->length(\array_reverse($fromEnd), \array_reverse($to));
  61206. $jMax = 0;
  61207. $max = 0;
  61208. for ($j = 0; $j <= $cTo; $j++) {
  61209. $m = $llB[$j] + $llE[$cTo - $j];
  61210. if ($m >= $max) {
  61211. $max = $m;
  61212. $jMax = $j;
  61213. }
  61214. }
  61215. $toStart = \array_slice($to, 0, $jMax);
  61216. $toEnd = \array_slice($to, $jMax);
  61217. return \array_merge(
  61218. $this->calculate($fromStart, $toStart),
  61219. $this->calculate($fromEnd, $toEnd)
  61220. );
  61221. }
  61222. private function length(array $from, array $to)
  61223. {
  61224. $current = \array_fill(0, \count($to) + 1, 0);
  61225. $cFrom = \count($from);
  61226. $cTo = \count($to);
  61227. for ($i = 0; $i < $cFrom; $i++) {
  61228. $prev = $current;
  61229. for ($j = 0; $j < $cTo; $j++) {
  61230. if ($from[$i] === $to[$j]) {
  61231. $current[$j + 1] = $prev[$j] + 1;
  61232. } else {
  61233. $current[$j + 1] = \max($current[$j], $prev[$j + 1]);
  61234. }
  61235. }
  61236. }
  61237. return $current;
  61238. }
  61239. }
  61240. <?php
  61241. if (!is_callable('random_bytes')) {
  61242. function random_bytes($bytes)
  61243. {
  61244. try {
  61245. $bytes = RandomCompat_intval($bytes);
  61246. } catch (TypeError $ex) {
  61247. throw new TypeError(
  61248. 'random_bytes(): $bytes must be an integer'
  61249. );
  61250. }
  61251. if ($bytes < 1) {
  61252. throw new Error(
  61253. 'Length must be greater than 0'
  61254. );
  61255. }
  61256. $buf = '';
  61257. if (!class_exists('COM')) {
  61258. throw new Error(
  61259. 'COM does not exist'
  61260. );
  61261. }
  61262. $util = new COM('CAPICOM.Utilities.1');
  61263. $execCount = 0;
  61264. do {
  61265. $buf .= base64_decode((string) $util->GetRandom($bytes, 0));
  61266. if (RandomCompat_strlen($buf) >= $bytes) {
  61267. return (string) RandomCompat_substr($buf, 0, $bytes);
  61268. }
  61269. ++$execCount;
  61270. } while ($execCount < $bytes);
  61271. throw new Exception(
  61272. 'Could not gather sufficient random data'
  61273. );
  61274. }
  61275. }
  61276. <?php
  61277. if (!is_callable('random_bytes')) {
  61278. /**
  61279. @ref
  61280. @ref
  61281. */
  61282. function random_bytes($bytes)
  61283. {
  61284. try {
  61285. $bytes = RandomCompat_intval($bytes);
  61286. } catch (TypeError $ex) {
  61287. throw new TypeError(
  61288. 'random_bytes(): $bytes must be an integer'
  61289. );
  61290. }
  61291. if ($bytes < 1) {
  61292. throw new Error(
  61293. 'Length must be greater than 0'
  61294. );
  61295. }
  61296. $buf = @mcrypt_create_iv((int) $bytes, (int) MCRYPT_DEV_URANDOM);
  61297. if (
  61298. is_string($buf)
  61299. &&
  61300. RandomCompat_strlen($buf) === $bytes
  61301. ) {
  61302. return $buf;
  61303. }
  61304. throw new Exception(
  61305. 'Could not gather sufficient random data'
  61306. );
  61307. }
  61308. }
  61309. <?php
  61310. if (!is_callable('RandomCompat_strlen')) {
  61311. if (
  61312. defined('MB_OVERLOAD_STRING')
  61313. &&
  61314. ((int) ini_get('mbstring.func_overload')) & MB_OVERLOAD_STRING
  61315. ) {
  61316. function RandomCompat_strlen($binary_string)
  61317. {
  61318. if (!is_string($binary_string)) {
  61319. throw new TypeError(
  61320. 'RandomCompat_strlen() expects a string'
  61321. );
  61322. }
  61323. return (int) mb_strlen($binary_string, '8bit');
  61324. }
  61325. } else {
  61326. function RandomCompat_strlen($binary_string)
  61327. {
  61328. if (!is_string($binary_string)) {
  61329. throw new TypeError(
  61330. 'RandomCompat_strlen() expects a string'
  61331. );
  61332. }
  61333. return (int) strlen($binary_string);
  61334. }
  61335. }
  61336. }
  61337. if (!is_callable('RandomCompat_substr')) {
  61338. if (
  61339. defined('MB_OVERLOAD_STRING')
  61340. &&
  61341. ((int) ini_get('mbstring.func_overload')) & MB_OVERLOAD_STRING
  61342. ) {
  61343. function RandomCompat_substr($binary_string, $start, $length = null)
  61344. {
  61345. if (!is_string($binary_string)) {
  61346. throw new TypeError(
  61347. 'RandomCompat_substr(): First argument should be a string'
  61348. );
  61349. }
  61350. if (!is_int($start)) {
  61351. throw new TypeError(
  61352. 'RandomCompat_substr(): Second argument should be an integer'
  61353. );
  61354. }
  61355. if ($length === null) {
  61356. $length = RandomCompat_strlen($binary_string) - $start;
  61357. } elseif (!is_int($length)) {
  61358. throw new TypeError(
  61359. 'RandomCompat_substr(): Third argument should be an integer, or omitted'
  61360. );
  61361. }
  61362. if ($start === RandomCompat_strlen($binary_string) && $length === 0) {
  61363. return '';
  61364. }
  61365. if ($start > RandomCompat_strlen($binary_string)) {
  61366. return '';
  61367. }
  61368. return (string) mb_substr(
  61369. (string) $binary_string,
  61370. (int) $start,
  61371. (int) $length,
  61372. '8bit'
  61373. );
  61374. }
  61375. } else {
  61376. function RandomCompat_substr($binary_string, $start, $length = null)
  61377. {
  61378. if (!is_string($binary_string)) {
  61379. throw new TypeError(
  61380. 'RandomCompat_substr(): First argument should be a string'
  61381. );
  61382. }
  61383. if (!is_int($start)) {
  61384. throw new TypeError(
  61385. 'RandomCompat_substr(): Second argument should be an integer'
  61386. );
  61387. }
  61388. if ($length !== null) {
  61389. if (!is_int($length)) {
  61390. throw new TypeError(
  61391. 'RandomCompat_substr(): Third argument should be an integer, or omitted'
  61392. );
  61393. }
  61394. return (string) substr(
  61395. (string )$binary_string,
  61396. (int) $start,
  61397. (int) $length
  61398. );
  61399. }
  61400. return (string) substr(
  61401. (string) $binary_string,
  61402. (int) $start
  61403. );
  61404. }
  61405. }
  61406. }
  61407. <?php
  61408. /**
  61409. @released
  61410. */
  61411. if (!defined('PHP_VERSION_ID')) {
  61412. $RandomCompatversion = array_map('intval', explode('.', PHP_VERSION));
  61413. define(
  61414. 'PHP_VERSION_ID',
  61415. $RandomCompatversion[0] * 10000
  61416. + $RandomCompatversion[1] * 100
  61417. + $RandomCompatversion[2]
  61418. );
  61419. $RandomCompatversion = null;
  61420. }
  61421. if (PHP_VERSION_ID >= 70000) {
  61422. return;
  61423. }
  61424. if (!defined('RANDOM_COMPAT_READ_BUFFER')) {
  61425. define('RANDOM_COMPAT_READ_BUFFER', 8);
  61426. }
  61427. $RandomCompatDIR = dirname(__FILE__);
  61428. require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'byte_safe_strings.php';
  61429. require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'cast_to_int.php';
  61430. require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'error_polyfill.php';
  61431. if (!is_callable('random_bytes')) {
  61432. if (extension_loaded('libsodium')) {
  61433. if (PHP_VERSION_ID >= 50300 && is_callable('\\Sodium\\randombytes_buf')) {
  61434. require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'random_bytes_libsodium.php';
  61435. } elseif (method_exists('Sodium', 'randombytes_buf')) {
  61436. require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'random_bytes_libsodium_legacy.php';
  61437. }
  61438. }
  61439. if (DIRECTORY_SEPARATOR === '/') {
  61440. $RandomCompatUrandom = true;
  61441. $RandomCompat_basedir = ini_get('open_basedir');
  61442. if (!empty($RandomCompat_basedir)) {
  61443. $RandomCompat_open_basedir = explode(
  61444. PATH_SEPARATOR,
  61445. strtolower($RandomCompat_basedir)
  61446. );
  61447. $RandomCompatUrandom = (array() !== array_intersect(
  61448. array('/dev', '/dev/', '/dev/urandom'),
  61449. $RandomCompat_open_basedir
  61450. ));
  61451. $RandomCompat_open_basedir = null;
  61452. }
  61453. if (
  61454. !is_callable('random_bytes')
  61455. &&
  61456. $RandomCompatUrandom
  61457. &&
  61458. @is_readable('/dev/urandom')
  61459. ) {
  61460. require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'random_bytes_dev_urandom.php';
  61461. }
  61462. $RandomCompat_basedir = null;
  61463. } else {
  61464. $RandomCompatUrandom = false;
  61465. }
  61466. if (
  61467. !is_callable('random_bytes')
  61468. &&
  61469. (DIRECTORY_SEPARATOR === '/' || PHP_VERSION_ID >= 50307)
  61470. &&
  61471. (
  61472. DIRECTORY_SEPARATOR !== '/' ||
  61473. (PHP_VERSION_ID <= 50609 || PHP_VERSION_ID >= 50613)
  61474. )
  61475. &&
  61476. extension_loaded('mcrypt')
  61477. ) {
  61478. require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'random_bytes_mcrypt.php';
  61479. }
  61480. $RandomCompatUrandom = null;
  61481. if (
  61482. !is_callable('random_bytes')
  61483. &&
  61484. extension_loaded('com_dotnet')
  61485. &&
  61486. class_exists('COM')
  61487. ) {
  61488. $RandomCompat_disabled_classes = preg_split(
  61489. '#\s*,\s*#',
  61490. strtolower(ini_get('disable_classes'))
  61491. );
  61492. if (!in_array('com', $RandomCompat_disabled_classes)) {
  61493. try {
  61494. $RandomCompatCOMtest = new COM('CAPICOM.Utilities.1');
  61495. if (method_exists($RandomCompatCOMtest, 'GetRandom')) {
  61496. require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'random_bytes_com_dotnet.php';
  61497. }
  61498. } catch (com_exception $e) {
  61499. }
  61500. }
  61501. $RandomCompat_disabled_classes = null;
  61502. $RandomCompatCOMtest = null;
  61503. }
  61504. if (!is_callable('random_bytes')) {
  61505. /**
  61506. @psalm
  61507. */
  61508. function random_bytes($length)
  61509. {
  61510. unset($length);
  61511. throw new Exception(
  61512. 'There is no suitable CSPRNG installed on your system'
  61513. );
  61514. return '';
  61515. }
  61516. }
  61517. }
  61518. if (!is_callable('random_int')) {
  61519. require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'random_int.php';
  61520. }
  61521. $RandomCompatDIR = null;
  61522. <?php
  61523. if (!is_callable('random_bytes')) {
  61524. /**
  61525. @ref
  61526. */
  61527. function random_bytes($bytes)
  61528. {
  61529. try {
  61530. $bytes = RandomCompat_intval($bytes);
  61531. } catch (TypeError $ex) {
  61532. throw new TypeError(
  61533. 'random_bytes(): $bytes must be an integer'
  61534. );
  61535. }
  61536. if ($bytes < 1) {
  61537. throw new Error(
  61538. 'Length must be greater than 0'
  61539. );
  61540. }
  61541. if ($bytes > 2147483647) {
  61542. $buf = '';
  61543. for ($i = 0; $i < $bytes; $i += 1073741824) {
  61544. $n = ($bytes - $i) > 1073741824
  61545. ? 1073741824
  61546. : $bytes - $i;
  61547. $buf .= \Sodium\randombytes_buf($n);
  61548. }
  61549. } else {
  61550. $buf = \Sodium\randombytes_buf($bytes);
  61551. }
  61552. if (is_string($buf)) {
  61553. if (RandomCompat_strlen($buf) === $bytes) {
  61554. return $buf;
  61555. }
  61556. }
  61557. throw new Exception(
  61558. 'Could not gather sufficient random data'
  61559. );
  61560. }
  61561. }
  61562. <?php
  61563. if (!class_exists('Error', false)) {
  61564. class Error extends Exception
  61565. {
  61566. }
  61567. }
  61568. if (!class_exists('TypeError', false)) {
  61569. if (is_subclass_of('Error', 'Exception')) {
  61570. class TypeError extends Error
  61571. {
  61572. }
  61573. } else {
  61574. class TypeError extends Exception
  61575. {
  61576. }
  61577. }
  61578. }
  61579. <?php
  61580. if (!is_callable('RandomCompat_intval')) {
  61581. /**
  61582. @psalm
  61583. */
  61584. function RandomCompat_intval($number, $fail_open = false)
  61585. {
  61586. if (is_int($number) || is_float($number)) {
  61587. $number += 0;
  61588. } elseif (is_numeric($number)) {
  61589. /**
  61590. @psalm */
  61591. $number += 0;
  61592. }
  61593. if (
  61594. is_float($number)
  61595. &&
  61596. $number > ~PHP_INT_MAX
  61597. &&
  61598. $number < PHP_INT_MAX
  61599. ) {
  61600. $number = (int) $number;
  61601. }
  61602. if (is_int($number)) {
  61603. return (int) $number;
  61604. } elseif (!$fail_open) {
  61605. throw new TypeError(
  61606. 'Expected an integer.'
  61607. );
  61608. }
  61609. return $number;
  61610. }
  61611. }
  61612. <?php
  61613. if (!is_callable('random_bytes')) {
  61614. /**
  61615. @ref
  61616. */
  61617. function random_bytes($bytes)
  61618. {
  61619. try {
  61620. $bytes = RandomCompat_intval($bytes);
  61621. } catch (TypeError $ex) {
  61622. throw new TypeError(
  61623. 'random_bytes(): $bytes must be an integer'
  61624. );
  61625. }
  61626. if ($bytes < 1) {
  61627. throw new Error(
  61628. 'Length must be greater than 0'
  61629. );
  61630. }
  61631. $buf = '';
  61632. if ($bytes > 2147483647) {
  61633. for ($i = 0; $i < $bytes; $i += 1073741824) {
  61634. $n = ($bytes - $i) > 1073741824
  61635. ? 1073741824
  61636. : $bytes - $i;
  61637. $buf .= Sodium::randombytes_buf((int) $n);
  61638. }
  61639. } else {
  61640. $buf .= Sodium::randombytes_buf((int) $bytes);
  61641. }
  61642. if (is_string($buf)) {
  61643. if (RandomCompat_strlen($buf) === $bytes) {
  61644. return $buf;
  61645. }
  61646. }
  61647. throw new Exception(
  61648. 'Could not gather sufficient random data'
  61649. );
  61650. }
  61651. }
  61652. <?php
  61653. if (!defined('RANDOM_COMPAT_READ_BUFFER')) {
  61654. define('RANDOM_COMPAT_READ_BUFFER', 8);
  61655. }
  61656. if (!is_callable('random_bytes')) {
  61657. /**
  61658. @ref
  61659. @ref
  61660. */
  61661. function random_bytes($bytes)
  61662. {
  61663. static $fp = null;
  61664. if (empty($fp)) {
  61665. if (DIRECTORY_SEPARATOR === '/') {
  61666. if (!is_readable('/dev/urandom')) {
  61667. throw new Exception(
  61668. 'Environment misconfiguration: ' .
  61669. '/dev/urandom cannot be read.'
  61670. );
  61671. }
  61672. $fp = fopen('/dev/urandom', 'rb');
  61673. if (is_resource($fp)) {
  61674. $st = fstat($fp);
  61675. if (($st['mode'] & 0170000) !== 020000) {
  61676. fclose($fp);
  61677. $fp = false;
  61678. }
  61679. }
  61680. }
  61681. if (is_resource($fp)) {
  61682. if (is_callable('stream_set_read_buffer')) {
  61683. stream_set_read_buffer($fp, RANDOM_COMPAT_READ_BUFFER);
  61684. }
  61685. if (is_callable('stream_set_chunk_size')) {
  61686. stream_set_chunk_size($fp, RANDOM_COMPAT_READ_BUFFER);
  61687. }
  61688. }
  61689. }
  61690. try {
  61691. $bytes = RandomCompat_intval($bytes);
  61692. } catch (TypeError $ex) {
  61693. throw new TypeError(
  61694. 'random_bytes(): $bytes must be an integer'
  61695. );
  61696. }
  61697. if ($bytes < 1) {
  61698. throw new Error(
  61699. 'Length must be greater than 0'
  61700. );
  61701. }
  61702. if (is_resource($fp)) {
  61703. $remaining = $bytes;
  61704. $buf = '';
  61705. do {
  61706. $read = fread($fp, $remaining);
  61707. if (!is_string($read)) {
  61708. $buf = false;
  61709. break;
  61710. }
  61711. $remaining -= RandomCompat_strlen($read);
  61712. $buf .= $read;
  61713. } while ($remaining > 0);
  61714. if (is_string($buf)) {
  61715. if (RandomCompat_strlen($buf) === $bytes) {
  61716. return $buf;
  61717. }
  61718. }
  61719. }
  61720. throw new Exception(
  61721. 'Error reading from source device'
  61722. );
  61723. }
  61724. }
  61725. <?php
  61726. if (!is_callable('random_int')) {
  61727. function random_int($min, $max)
  61728. {
  61729. try {
  61730. $min = RandomCompat_intval($min);
  61731. } catch (TypeError $ex) {
  61732. throw new TypeError(
  61733. 'random_int(): $min must be an integer'
  61734. );
  61735. }
  61736. try {
  61737. $max = RandomCompat_intval($max);
  61738. } catch (TypeError $ex) {
  61739. throw new TypeError(
  61740. 'random_int(): $max must be an integer'
  61741. );
  61742. }
  61743. if ($min > $max) {
  61744. throw new Error(
  61745. 'Minimum value must be less than or equal to the maximum value'
  61746. );
  61747. }
  61748. if ($max === $min) {
  61749. return (int) $min;
  61750. }
  61751. $attempts = $bits = $bytes = $mask = $valueShift = 0;
  61752. $range = $max - $min;
  61753. if (!is_int($range)) {
  61754. /**
  61755. @CodesInChaos
  61756. @oittaa
  61757. @ref
  61758. @ref
  61759. @ref
  61760. */
  61761. $bytes = PHP_INT_SIZE;
  61762. $mask = ~0;
  61763. } else {
  61764. while ($range > 0) {
  61765. if ($bits % 8 === 0) {
  61766. ++$bytes;
  61767. }
  61768. ++$bits;
  61769. $range >>= 1;
  61770. $mask = $mask << 1 | 1;
  61771. }
  61772. $valueShift = $min;
  61773. }
  61774. $val = 0;
  61775. /**
  61776. @psalm */
  61777. do {
  61778. if ($attempts > 128) {
  61779. throw new Exception(
  61780. 'random_int: RNG is broken - too many rejections'
  61781. );
  61782. }
  61783. $randomByteString = random_bytes($bytes);
  61784. $val &= 0;
  61785. for ($i = 0; $i < $bytes; ++$i) {
  61786. $val |= ord($randomByteString[$i]) << ($i * 8);
  61787. }
  61788. $val &= $mask;
  61789. $val += $valueShift;
  61790. ++$attempts;
  61791. } while (!is_int($val) || $val > $max || $val < $min);
  61792. return (int) $val;
  61793. }
  61794. }
  61795. Copyright (c) 2012-2020 Fabien Potencier
  61796. Dariusz Rumiński
  61797. Permission is hereby granted, free of charge, to any person obtaining a copy
  61798. of this software and associated documentation files (the "Software"), to deal
  61799. in the Software without restriction, including without limitation the rights
  61800. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  61801. copies of the Software, and to permit persons to whom the Software is furnished
  61802. to do so, subject to the following conditions:
  61803. The above copyright notice and this permission notice shall be included in all
  61804. copies or substantial portions of the Software.
  61805. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  61806. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  61807. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  61808. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  61809. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  61810. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  61811. THE SOFTWARE.
  61812. <?php
  61813. /*
  61814. * This file is part of PHP CS Fixer.
  61815. *
  61816. * (c) Fabien Potencier <fabien@symfony.com>
  61817. * Dariusz Rumiński <dariusz.ruminski@gmail.com>
  61818. *
  61819. * This source file is subject to the MIT license that is bundled
  61820. * with this source code in the file LICENSE.
  61821. */
  61822. if (getenv('PHP_CS_FIXER_FUTURE_MODE')) {
  61823. error_reporting(E_ALL & ~E_DEPRECATED & ~E_USER_DEPRECATED);
  61824. }
  61825. if (defined('HHVM_VERSION_ID')) {
  61826. fwrite(STDERR, "HHVM is not supported.\n");
  61827. if (getenv('PHP_CS_FIXER_IGNORE_ENV')) {
  61828. fwrite(STDERR, "Ignoring environment requirements because `PHP_CS_FIXER_IGNORE_ENV` is set. Execution may be unstable.\n");
  61829. } else {
  61830. exit(1);
  61831. }
  61832. } elseif (!defined('PHP_VERSION_ID') || \PHP_VERSION_ID < 50600 || \PHP_VERSION_ID >= 70500) {
  61833. fwrite(STDERR, "PHP needs to be a minimum version of PHP 5.6.0 and maximum version of PHP 7.4.*.\n");
  61834. if (getenv('PHP_CS_FIXER_IGNORE_ENV')) {
  61835. fwrite(STDERR, "Ignoring environment requirements because `PHP_CS_FIXER_IGNORE_ENV` is set. Execution may be unstable.\n");
  61836. } else {
  61837. exit(1);
  61838. }
  61839. }
  61840. foreach (['json', 'tokenizer'] as $extension) {
  61841. if (!extension_loaded($extension)) {
  61842. fwrite(STDERR, sprintf("PHP extension ext-%s is missing from your system. Install or enable it.\n", $extension));
  61843. if (getenv('PHP_CS_FIXER_IGNORE_ENV')) {
  61844. fwrite(STDERR, "Ignoring environment requirements because `PHP_CS_FIXER_IGNORE_ENV` is set. Execution may be unstable.\n");
  61845. } else {
  61846. exit(1);
  61847. }
  61848. }
  61849. }
  61850. unset($extension);
  61851. set_error_handler(static function ($severity, $message, $file, $line) {
  61852. if ($severity & error_reporting()) {
  61853. throw new ErrorException($message, 0, $severity, $file, $line);
  61854. }
  61855. });
  61856. $require = true;
  61857. if (class_exists('Phar')) {
  61858. // Maybe this file is used as phar-stub? Let's try!
  61859. try {
  61860. Phar::mapPhar('php-cs-fixer.phar');
  61861. require_once 'phar://php-cs-fixer.phar/vendor/autoload.php';
  61862. $require = false;
  61863. } catch (PharException $e) {
  61864. }
  61865. }
  61866. if ($require) {
  61867. // OK, it's not, let give Composer autoloader a try!
  61868. $possibleFiles = [__DIR__.'/../../autoload.php', __DIR__.'/../autoload.php', __DIR__.'/vendor/autoload.php'];
  61869. $file = null;
  61870. foreach ($possibleFiles as $possibleFile) {
  61871. if (file_exists($possibleFile)) {
  61872. $file = $possibleFile;
  61873. break;
  61874. }
  61875. }
  61876. if (null === $file) {
  61877. throw new RuntimeException('Unable to locate autoload.php file.');
  61878. }
  61879. require_once $file;
  61880. unset($possibleFiles, $possibleFile, $file);
  61881. }
  61882. unset($require);
  61883. use Composer\XdebugHandler\XdebugHandler;
  61884. use PhpCsFixer\Console\Application;
  61885. // Restart if xdebug is loaded, unless the environment variable PHP_CS_FIXER_ALLOW_XDEBUG is set.
  61886. $xdebug = new XdebugHandler('PHP_CS_FIXER', '--ansi');
  61887. $xdebug->check();
  61888. unset($xdebug);
  61889. $application = new Application();
  61890. $application->run();
  61891. __HALT_COMPILER();
  61892. +5åç´ˆ21ö�¨·H€Õµh���GBMB