eslintrc.cjs 147 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431
  1. 'use strict';
  2. Object.defineProperty(exports, '__esModule', { value: true });
  3. var debugOrig = require('debug');
  4. var fs = require('fs');
  5. var importFresh = require('import-fresh');
  6. var Module = require('module');
  7. var path = require('path');
  8. var stripComments = require('strip-json-comments');
  9. var assert = require('assert');
  10. var ignore = require('ignore');
  11. var util = require('util');
  12. var minimatch = require('minimatch');
  13. var Ajv = require('ajv');
  14. var globals = require('globals');
  15. var os = require('os');
  16. function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
  17. var debugOrig__default = /*#__PURE__*/_interopDefaultLegacy(debugOrig);
  18. var fs__default = /*#__PURE__*/_interopDefaultLegacy(fs);
  19. var importFresh__default = /*#__PURE__*/_interopDefaultLegacy(importFresh);
  20. var Module__default = /*#__PURE__*/_interopDefaultLegacy(Module);
  21. var path__default = /*#__PURE__*/_interopDefaultLegacy(path);
  22. var stripComments__default = /*#__PURE__*/_interopDefaultLegacy(stripComments);
  23. var assert__default = /*#__PURE__*/_interopDefaultLegacy(assert);
  24. var ignore__default = /*#__PURE__*/_interopDefaultLegacy(ignore);
  25. var util__default = /*#__PURE__*/_interopDefaultLegacy(util);
  26. var minimatch__default = /*#__PURE__*/_interopDefaultLegacy(minimatch);
  27. var Ajv__default = /*#__PURE__*/_interopDefaultLegacy(Ajv);
  28. var globals__default = /*#__PURE__*/_interopDefaultLegacy(globals);
  29. var os__default = /*#__PURE__*/_interopDefaultLegacy(os);
  30. /**
  31. * @fileoverview `IgnorePattern` class.
  32. *
  33. * `IgnorePattern` class has the set of glob patterns and the base path.
  34. *
  35. * It provides two static methods.
  36. *
  37. * - `IgnorePattern.createDefaultIgnore(cwd)`
  38. * Create the default predicate function.
  39. * - `IgnorePattern.createIgnore(ignorePatterns)`
  40. * Create the predicate function from multiple `IgnorePattern` objects.
  41. *
  42. * It provides two properties and a method.
  43. *
  44. * - `patterns`
  45. * The glob patterns that ignore to lint.
  46. * - `basePath`
  47. * The base path of the glob patterns. If absolute paths existed in the
  48. * glob patterns, those are handled as relative paths to the base path.
  49. * - `getPatternsRelativeTo(basePath)`
  50. * Get `patterns` as modified for a given base path. It modifies the
  51. * absolute paths in the patterns as prepending the difference of two base
  52. * paths.
  53. *
  54. * `ConfigArrayFactory` creates `IgnorePattern` objects when it processes
  55. * `ignorePatterns` properties.
  56. *
  57. * @author Toru Nagashima <https://github.com/mysticatea>
  58. */
  59. const debug$3 = debugOrig__default["default"]("eslintrc:ignore-pattern");
  60. /** @typedef {ReturnType<import("ignore").default>} Ignore */
  61. //------------------------------------------------------------------------------
  62. // Helpers
  63. //------------------------------------------------------------------------------
  64. /**
  65. * Get the path to the common ancestor directory of given paths.
  66. * @param {string[]} sourcePaths The paths to calculate the common ancestor.
  67. * @returns {string} The path to the common ancestor directory.
  68. */
  69. function getCommonAncestorPath(sourcePaths) {
  70. let result = sourcePaths[0];
  71. for (let i = 1; i < sourcePaths.length; ++i) {
  72. const a = result;
  73. const b = sourcePaths[i];
  74. // Set the shorter one (it's the common ancestor if one includes the other).
  75. result = a.length < b.length ? a : b;
  76. // Set the common ancestor.
  77. for (let j = 0, lastSepPos = 0; j < a.length && j < b.length; ++j) {
  78. if (a[j] !== b[j]) {
  79. result = a.slice(0, lastSepPos);
  80. break;
  81. }
  82. if (a[j] === path__default["default"].sep) {
  83. lastSepPos = j;
  84. }
  85. }
  86. }
  87. let resolvedResult = result || path__default["default"].sep;
  88. // if Windows common ancestor is root of drive must have trailing slash to be absolute.
  89. if (resolvedResult && resolvedResult.endsWith(":") && process.platform === "win32") {
  90. resolvedResult += path__default["default"].sep;
  91. }
  92. return resolvedResult;
  93. }
  94. /**
  95. * Make relative path.
  96. * @param {string} from The source path to get relative path.
  97. * @param {string} to The destination path to get relative path.
  98. * @returns {string} The relative path.
  99. */
  100. function relative(from, to) {
  101. const relPath = path__default["default"].relative(from, to);
  102. if (path__default["default"].sep === "/") {
  103. return relPath;
  104. }
  105. return relPath.split(path__default["default"].sep).join("/");
  106. }
  107. /**
  108. * Get the trailing slash if existed.
  109. * @param {string} filePath The path to check.
  110. * @returns {string} The trailing slash if existed.
  111. */
  112. function dirSuffix(filePath) {
  113. const isDir = (
  114. filePath.endsWith(path__default["default"].sep) ||
  115. (process.platform === "win32" && filePath.endsWith("/"))
  116. );
  117. return isDir ? "/" : "";
  118. }
  119. const DefaultPatterns = Object.freeze(["/**/node_modules/*"]);
  120. const DotPatterns = Object.freeze([".*", "!.eslintrc.*", "!../"]);
  121. //------------------------------------------------------------------------------
  122. // Public
  123. //------------------------------------------------------------------------------
  124. class IgnorePattern {
  125. /**
  126. * The default patterns.
  127. * @type {string[]}
  128. */
  129. static get DefaultPatterns() {
  130. return DefaultPatterns;
  131. }
  132. /**
  133. * Create the default predicate function.
  134. * @param {string} cwd The current working directory.
  135. * @returns {((filePath:string, dot:boolean) => boolean) & {basePath:string; patterns:string[]}}
  136. * The preficate function.
  137. * The first argument is an absolute path that is checked.
  138. * The second argument is the flag to not ignore dotfiles.
  139. * If the predicate function returned `true`, it means the path should be ignored.
  140. */
  141. static createDefaultIgnore(cwd) {
  142. return this.createIgnore([new IgnorePattern(DefaultPatterns, cwd)]);
  143. }
  144. /**
  145. * Create the predicate function from multiple `IgnorePattern` objects.
  146. * @param {IgnorePattern[]} ignorePatterns The list of ignore patterns.
  147. * @returns {((filePath:string, dot?:boolean) => boolean) & {basePath:string; patterns:string[]}}
  148. * The preficate function.
  149. * The first argument is an absolute path that is checked.
  150. * The second argument is the flag to not ignore dotfiles.
  151. * If the predicate function returned `true`, it means the path should be ignored.
  152. */
  153. static createIgnore(ignorePatterns) {
  154. debug$3("Create with: %o", ignorePatterns);
  155. const basePath = getCommonAncestorPath(ignorePatterns.map(p => p.basePath));
  156. const patterns = [].concat(
  157. ...ignorePatterns.map(p => p.getPatternsRelativeTo(basePath))
  158. );
  159. const ig = ignore__default["default"]({ allowRelativePaths: true }).add([...DotPatterns, ...patterns]);
  160. const dotIg = ignore__default["default"]({ allowRelativePaths: true }).add(patterns);
  161. debug$3(" processed: %o", { basePath, patterns });
  162. return Object.assign(
  163. (filePath, dot = false) => {
  164. assert__default["default"](path__default["default"].isAbsolute(filePath), "'filePath' should be an absolute path.");
  165. const relPathRaw = relative(basePath, filePath);
  166. const relPath = relPathRaw && (relPathRaw + dirSuffix(filePath));
  167. const adoptedIg = dot ? dotIg : ig;
  168. const result = relPath !== "" && adoptedIg.ignores(relPath);
  169. debug$3("Check", { filePath, dot, relativePath: relPath, result });
  170. return result;
  171. },
  172. { basePath, patterns }
  173. );
  174. }
  175. /**
  176. * Initialize a new `IgnorePattern` instance.
  177. * @param {string[]} patterns The glob patterns that ignore to lint.
  178. * @param {string} basePath The base path of `patterns`.
  179. */
  180. constructor(patterns, basePath) {
  181. assert__default["default"](path__default["default"].isAbsolute(basePath), "'basePath' should be an absolute path.");
  182. /**
  183. * The glob patterns that ignore to lint.
  184. * @type {string[]}
  185. */
  186. this.patterns = patterns;
  187. /**
  188. * The base path of `patterns`.
  189. * @type {string}
  190. */
  191. this.basePath = basePath;
  192. /**
  193. * If `true` then patterns which don't start with `/` will match the paths to the outside of `basePath`. Defaults to `false`.
  194. *
  195. * It's set `true` for `.eslintignore`, `package.json`, and `--ignore-path` for backward compatibility.
  196. * It's `false` as-is for `ignorePatterns` property in config files.
  197. * @type {boolean}
  198. */
  199. this.loose = false;
  200. }
  201. /**
  202. * Get `patterns` as modified for a given base path. It modifies the
  203. * absolute paths in the patterns as prepending the difference of two base
  204. * paths.
  205. * @param {string} newBasePath The base path.
  206. * @returns {string[]} Modifired patterns.
  207. */
  208. getPatternsRelativeTo(newBasePath) {
  209. assert__default["default"](path__default["default"].isAbsolute(newBasePath), "'newBasePath' should be an absolute path.");
  210. const { basePath, loose, patterns } = this;
  211. if (newBasePath === basePath) {
  212. return patterns;
  213. }
  214. const prefix = `/${relative(newBasePath, basePath)}`;
  215. return patterns.map(pattern => {
  216. const negative = pattern.startsWith("!");
  217. const head = negative ? "!" : "";
  218. const body = negative ? pattern.slice(1) : pattern;
  219. if (body.startsWith("/") || body.startsWith("../")) {
  220. return `${head}${prefix}${body}`;
  221. }
  222. return loose ? pattern : `${head}${prefix}/**/${body}`;
  223. });
  224. }
  225. }
  226. /**
  227. * @fileoverview `ExtractedConfig` class.
  228. *
  229. * `ExtractedConfig` class expresses a final configuration for a specific file.
  230. *
  231. * It provides one method.
  232. *
  233. * - `toCompatibleObjectAsConfigFileContent()`
  234. * Convert this configuration to the compatible object as the content of
  235. * config files. It converts the loaded parser and plugins to strings.
  236. * `CLIEngine#getConfigForFile(filePath)` method uses this method.
  237. *
  238. * `ConfigArray#extractConfig(filePath)` creates a `ExtractedConfig` instance.
  239. *
  240. * @author Toru Nagashima <https://github.com/mysticatea>
  241. */
  242. // For VSCode intellisense
  243. /** @typedef {import("../../shared/types").ConfigData} ConfigData */
  244. /** @typedef {import("../../shared/types").GlobalConf} GlobalConf */
  245. /** @typedef {import("../../shared/types").SeverityConf} SeverityConf */
  246. /** @typedef {import("./config-dependency").DependentParser} DependentParser */
  247. /** @typedef {import("./config-dependency").DependentPlugin} DependentPlugin */
  248. /**
  249. * Check if `xs` starts with `ys`.
  250. * @template T
  251. * @param {T[]} xs The array to check.
  252. * @param {T[]} ys The array that may be the first part of `xs`.
  253. * @returns {boolean} `true` if `xs` starts with `ys`.
  254. */
  255. function startsWith(xs, ys) {
  256. return xs.length >= ys.length && ys.every((y, i) => y === xs[i]);
  257. }
  258. /**
  259. * The class for extracted config data.
  260. */
  261. class ExtractedConfig {
  262. constructor() {
  263. /**
  264. * The config name what `noInlineConfig` setting came from.
  265. * @type {string}
  266. */
  267. this.configNameOfNoInlineConfig = "";
  268. /**
  269. * Environments.
  270. * @type {Record<string, boolean>}
  271. */
  272. this.env = {};
  273. /**
  274. * Global variables.
  275. * @type {Record<string, GlobalConf>}
  276. */
  277. this.globals = {};
  278. /**
  279. * The glob patterns that ignore to lint.
  280. * @type {(((filePath:string, dot?:boolean) => boolean) & { basePath:string; patterns:string[] }) | undefined}
  281. */
  282. this.ignores = void 0;
  283. /**
  284. * The flag that disables directive comments.
  285. * @type {boolean|undefined}
  286. */
  287. this.noInlineConfig = void 0;
  288. /**
  289. * Parser definition.
  290. * @type {DependentParser|null}
  291. */
  292. this.parser = null;
  293. /**
  294. * Options for the parser.
  295. * @type {Object}
  296. */
  297. this.parserOptions = {};
  298. /**
  299. * Plugin definitions.
  300. * @type {Record<string, DependentPlugin>}
  301. */
  302. this.plugins = {};
  303. /**
  304. * Processor ID.
  305. * @type {string|null}
  306. */
  307. this.processor = null;
  308. /**
  309. * The flag that reports unused `eslint-disable` directive comments.
  310. * @type {boolean|undefined}
  311. */
  312. this.reportUnusedDisableDirectives = void 0;
  313. /**
  314. * Rule settings.
  315. * @type {Record<string, [SeverityConf, ...any[]]>}
  316. */
  317. this.rules = {};
  318. /**
  319. * Shared settings.
  320. * @type {Object}
  321. */
  322. this.settings = {};
  323. }
  324. /**
  325. * Convert this config to the compatible object as a config file content.
  326. * @returns {ConfigData} The converted object.
  327. */
  328. toCompatibleObjectAsConfigFileContent() {
  329. const {
  330. /* eslint-disable no-unused-vars */
  331. configNameOfNoInlineConfig: _ignore1,
  332. processor: _ignore2,
  333. /* eslint-enable no-unused-vars */
  334. ignores,
  335. ...config
  336. } = this;
  337. config.parser = config.parser && config.parser.filePath;
  338. config.plugins = Object.keys(config.plugins).filter(Boolean).reverse();
  339. config.ignorePatterns = ignores ? ignores.patterns : [];
  340. // Strip the default patterns from `ignorePatterns`.
  341. if (startsWith(config.ignorePatterns, IgnorePattern.DefaultPatterns)) {
  342. config.ignorePatterns =
  343. config.ignorePatterns.slice(IgnorePattern.DefaultPatterns.length);
  344. }
  345. return config;
  346. }
  347. }
  348. /**
  349. * @fileoverview `ConfigArray` class.
  350. *
  351. * `ConfigArray` class expresses the full of a configuration. It has the entry
  352. * config file, base config files that were extended, loaded parsers, and loaded
  353. * plugins.
  354. *
  355. * `ConfigArray` class provides three properties and two methods.
  356. *
  357. * - `pluginEnvironments`
  358. * - `pluginProcessors`
  359. * - `pluginRules`
  360. * The `Map` objects that contain the members of all plugins that this
  361. * config array contains. Those map objects don't have mutation methods.
  362. * Those keys are the member ID such as `pluginId/memberName`.
  363. * - `isRoot()`
  364. * If `true` then this configuration has `root:true` property.
  365. * - `extractConfig(filePath)`
  366. * Extract the final configuration for a given file. This means merging
  367. * every config array element which that `criteria` property matched. The
  368. * `filePath` argument must be an absolute path.
  369. *
  370. * `ConfigArrayFactory` provides the loading logic of config files.
  371. *
  372. * @author Toru Nagashima <https://github.com/mysticatea>
  373. */
  374. //------------------------------------------------------------------------------
  375. // Helpers
  376. //------------------------------------------------------------------------------
  377. // Define types for VSCode IntelliSense.
  378. /** @typedef {import("../../shared/types").Environment} Environment */
  379. /** @typedef {import("../../shared/types").GlobalConf} GlobalConf */
  380. /** @typedef {import("../../shared/types").RuleConf} RuleConf */
  381. /** @typedef {import("../../shared/types").Rule} Rule */
  382. /** @typedef {import("../../shared/types").Plugin} Plugin */
  383. /** @typedef {import("../../shared/types").Processor} Processor */
  384. /** @typedef {import("./config-dependency").DependentParser} DependentParser */
  385. /** @typedef {import("./config-dependency").DependentPlugin} DependentPlugin */
  386. /** @typedef {import("./override-tester")["OverrideTester"]} OverrideTester */
  387. /**
  388. * @typedef {Object} ConfigArrayElement
  389. * @property {string} name The name of this config element.
  390. * @property {string} filePath The path to the source file of this config element.
  391. * @property {InstanceType<OverrideTester>|null} criteria The tester for the `files` and `excludedFiles` of this config element.
  392. * @property {Record<string, boolean>|undefined} env The environment settings.
  393. * @property {Record<string, GlobalConf>|undefined} globals The global variable settings.
  394. * @property {IgnorePattern|undefined} ignorePattern The ignore patterns.
  395. * @property {boolean|undefined} noInlineConfig The flag that disables directive comments.
  396. * @property {DependentParser|undefined} parser The parser loader.
  397. * @property {Object|undefined} parserOptions The parser options.
  398. * @property {Record<string, DependentPlugin>|undefined} plugins The plugin loaders.
  399. * @property {string|undefined} processor The processor name to refer plugin's processor.
  400. * @property {boolean|undefined} reportUnusedDisableDirectives The flag to report unused `eslint-disable` comments.
  401. * @property {boolean|undefined} root The flag to express root.
  402. * @property {Record<string, RuleConf>|undefined} rules The rule settings
  403. * @property {Object|undefined} settings The shared settings.
  404. * @property {"config" | "ignore" | "implicit-processor"} type The element type.
  405. */
  406. /**
  407. * @typedef {Object} ConfigArrayInternalSlots
  408. * @property {Map<string, ExtractedConfig>} cache The cache to extract configs.
  409. * @property {ReadonlyMap<string, Environment>|null} envMap The map from environment ID to environment definition.
  410. * @property {ReadonlyMap<string, Processor>|null} processorMap The map from processor ID to environment definition.
  411. * @property {ReadonlyMap<string, Rule>|null} ruleMap The map from rule ID to rule definition.
  412. */
  413. /** @type {WeakMap<ConfigArray, ConfigArrayInternalSlots>} */
  414. const internalSlotsMap$2 = new class extends WeakMap {
  415. get(key) {
  416. let value = super.get(key);
  417. if (!value) {
  418. value = {
  419. cache: new Map(),
  420. envMap: null,
  421. processorMap: null,
  422. ruleMap: null
  423. };
  424. super.set(key, value);
  425. }
  426. return value;
  427. }
  428. }();
  429. /**
  430. * Get the indices which are matched to a given file.
  431. * @param {ConfigArrayElement[]} elements The elements.
  432. * @param {string} filePath The path to a target file.
  433. * @returns {number[]} The indices.
  434. */
  435. function getMatchedIndices(elements, filePath) {
  436. const indices = [];
  437. for (let i = elements.length - 1; i >= 0; --i) {
  438. const element = elements[i];
  439. if (!element.criteria || (filePath && element.criteria.test(filePath))) {
  440. indices.push(i);
  441. }
  442. }
  443. return indices;
  444. }
  445. /**
  446. * Check if a value is a non-null object.
  447. * @param {any} x The value to check.
  448. * @returns {boolean} `true` if the value is a non-null object.
  449. */
  450. function isNonNullObject(x) {
  451. return typeof x === "object" && x !== null;
  452. }
  453. /**
  454. * Merge two objects.
  455. *
  456. * Assign every property values of `y` to `x` if `x` doesn't have the property.
  457. * If `x`'s property value is an object, it does recursive.
  458. * @param {Object} target The destination to merge
  459. * @param {Object|undefined} source The source to merge.
  460. * @returns {void}
  461. */
  462. function mergeWithoutOverwrite(target, source) {
  463. if (!isNonNullObject(source)) {
  464. return;
  465. }
  466. for (const key of Object.keys(source)) {
  467. if (key === "__proto__") {
  468. continue;
  469. }
  470. if (isNonNullObject(target[key])) {
  471. mergeWithoutOverwrite(target[key], source[key]);
  472. } else if (target[key] === void 0) {
  473. if (isNonNullObject(source[key])) {
  474. target[key] = Array.isArray(source[key]) ? [] : {};
  475. mergeWithoutOverwrite(target[key], source[key]);
  476. } else if (source[key] !== void 0) {
  477. target[key] = source[key];
  478. }
  479. }
  480. }
  481. }
  482. /**
  483. * The error for plugin conflicts.
  484. */
  485. class PluginConflictError extends Error {
  486. /**
  487. * Initialize this error object.
  488. * @param {string} pluginId The plugin ID.
  489. * @param {{filePath:string, importerName:string}[]} plugins The resolved plugins.
  490. */
  491. constructor(pluginId, plugins) {
  492. super(`Plugin "${pluginId}" was conflicted between ${plugins.map(p => `"${p.importerName}"`).join(" and ")}.`);
  493. this.messageTemplate = "plugin-conflict";
  494. this.messageData = { pluginId, plugins };
  495. }
  496. }
  497. /**
  498. * Merge plugins.
  499. * `target`'s definition is prior to `source`'s.
  500. * @param {Record<string, DependentPlugin>} target The destination to merge
  501. * @param {Record<string, DependentPlugin>|undefined} source The source to merge.
  502. * @returns {void}
  503. */
  504. function mergePlugins(target, source) {
  505. if (!isNonNullObject(source)) {
  506. return;
  507. }
  508. for (const key of Object.keys(source)) {
  509. if (key === "__proto__") {
  510. continue;
  511. }
  512. const targetValue = target[key];
  513. const sourceValue = source[key];
  514. // Adopt the plugin which was found at first.
  515. if (targetValue === void 0) {
  516. if (sourceValue.error) {
  517. throw sourceValue.error;
  518. }
  519. target[key] = sourceValue;
  520. } else if (sourceValue.filePath !== targetValue.filePath) {
  521. throw new PluginConflictError(key, [
  522. {
  523. filePath: targetValue.filePath,
  524. importerName: targetValue.importerName
  525. },
  526. {
  527. filePath: sourceValue.filePath,
  528. importerName: sourceValue.importerName
  529. }
  530. ]);
  531. }
  532. }
  533. }
  534. /**
  535. * Merge rule configs.
  536. * `target`'s definition is prior to `source`'s.
  537. * @param {Record<string, Array>} target The destination to merge
  538. * @param {Record<string, RuleConf>|undefined} source The source to merge.
  539. * @returns {void}
  540. */
  541. function mergeRuleConfigs(target, source) {
  542. if (!isNonNullObject(source)) {
  543. return;
  544. }
  545. for (const key of Object.keys(source)) {
  546. if (key === "__proto__") {
  547. continue;
  548. }
  549. const targetDef = target[key];
  550. const sourceDef = source[key];
  551. // Adopt the rule config which was found at first.
  552. if (targetDef === void 0) {
  553. if (Array.isArray(sourceDef)) {
  554. target[key] = [...sourceDef];
  555. } else {
  556. target[key] = [sourceDef];
  557. }
  558. /*
  559. * If the first found rule config is severity only and the current rule
  560. * config has options, merge the severity and the options.
  561. */
  562. } else if (
  563. targetDef.length === 1 &&
  564. Array.isArray(sourceDef) &&
  565. sourceDef.length >= 2
  566. ) {
  567. targetDef.push(...sourceDef.slice(1));
  568. }
  569. }
  570. }
  571. /**
  572. * Create the extracted config.
  573. * @param {ConfigArray} instance The config elements.
  574. * @param {number[]} indices The indices to use.
  575. * @returns {ExtractedConfig} The extracted config.
  576. */
  577. function createConfig(instance, indices) {
  578. const config = new ExtractedConfig();
  579. const ignorePatterns = [];
  580. // Merge elements.
  581. for (const index of indices) {
  582. const element = instance[index];
  583. // Adopt the parser which was found at first.
  584. if (!config.parser && element.parser) {
  585. if (element.parser.error) {
  586. throw element.parser.error;
  587. }
  588. config.parser = element.parser;
  589. }
  590. // Adopt the processor which was found at first.
  591. if (!config.processor && element.processor) {
  592. config.processor = element.processor;
  593. }
  594. // Adopt the noInlineConfig which was found at first.
  595. if (config.noInlineConfig === void 0 && element.noInlineConfig !== void 0) {
  596. config.noInlineConfig = element.noInlineConfig;
  597. config.configNameOfNoInlineConfig = element.name;
  598. }
  599. // Adopt the reportUnusedDisableDirectives which was found at first.
  600. if (config.reportUnusedDisableDirectives === void 0 && element.reportUnusedDisableDirectives !== void 0) {
  601. config.reportUnusedDisableDirectives = element.reportUnusedDisableDirectives;
  602. }
  603. // Collect ignorePatterns
  604. if (element.ignorePattern) {
  605. ignorePatterns.push(element.ignorePattern);
  606. }
  607. // Merge others.
  608. mergeWithoutOverwrite(config.env, element.env);
  609. mergeWithoutOverwrite(config.globals, element.globals);
  610. mergeWithoutOverwrite(config.parserOptions, element.parserOptions);
  611. mergeWithoutOverwrite(config.settings, element.settings);
  612. mergePlugins(config.plugins, element.plugins);
  613. mergeRuleConfigs(config.rules, element.rules);
  614. }
  615. // Create the predicate function for ignore patterns.
  616. if (ignorePatterns.length > 0) {
  617. config.ignores = IgnorePattern.createIgnore(ignorePatterns.reverse());
  618. }
  619. return config;
  620. }
  621. /**
  622. * Collect definitions.
  623. * @template T, U
  624. * @param {string} pluginId The plugin ID for prefix.
  625. * @param {Record<string,T>} defs The definitions to collect.
  626. * @param {Map<string, U>} map The map to output.
  627. * @returns {void}
  628. */
  629. function collect(pluginId, defs, map) {
  630. if (defs) {
  631. const prefix = pluginId && `${pluginId}/`;
  632. for (const [key, value] of Object.entries(defs)) {
  633. map.set(`${prefix}${key}`, value);
  634. }
  635. }
  636. }
  637. /**
  638. * Delete the mutation methods from a given map.
  639. * @param {Map<any, any>} map The map object to delete.
  640. * @returns {void}
  641. */
  642. function deleteMutationMethods(map) {
  643. Object.defineProperties(map, {
  644. clear: { configurable: true, value: void 0 },
  645. delete: { configurable: true, value: void 0 },
  646. set: { configurable: true, value: void 0 }
  647. });
  648. }
  649. /**
  650. * Create `envMap`, `processorMap`, `ruleMap` with the plugins in the config array.
  651. * @param {ConfigArrayElement[]} elements The config elements.
  652. * @param {ConfigArrayInternalSlots} slots The internal slots.
  653. * @returns {void}
  654. */
  655. function initPluginMemberMaps(elements, slots) {
  656. const processed = new Set();
  657. slots.envMap = new Map();
  658. slots.processorMap = new Map();
  659. slots.ruleMap = new Map();
  660. for (const element of elements) {
  661. if (!element.plugins) {
  662. continue;
  663. }
  664. for (const [pluginId, value] of Object.entries(element.plugins)) {
  665. const plugin = value.definition;
  666. if (!plugin || processed.has(pluginId)) {
  667. continue;
  668. }
  669. processed.add(pluginId);
  670. collect(pluginId, plugin.environments, slots.envMap);
  671. collect(pluginId, plugin.processors, slots.processorMap);
  672. collect(pluginId, plugin.rules, slots.ruleMap);
  673. }
  674. }
  675. deleteMutationMethods(slots.envMap);
  676. deleteMutationMethods(slots.processorMap);
  677. deleteMutationMethods(slots.ruleMap);
  678. }
  679. /**
  680. * Create `envMap`, `processorMap`, `ruleMap` with the plugins in the config array.
  681. * @param {ConfigArray} instance The config elements.
  682. * @returns {ConfigArrayInternalSlots} The extracted config.
  683. */
  684. function ensurePluginMemberMaps(instance) {
  685. const slots = internalSlotsMap$2.get(instance);
  686. if (!slots.ruleMap) {
  687. initPluginMemberMaps(instance, slots);
  688. }
  689. return slots;
  690. }
  691. //------------------------------------------------------------------------------
  692. // Public Interface
  693. //------------------------------------------------------------------------------
  694. /**
  695. * The Config Array.
  696. *
  697. * `ConfigArray` instance contains all settings, parsers, and plugins.
  698. * You need to call `ConfigArray#extractConfig(filePath)` method in order to
  699. * extract, merge and get only the config data which is related to an arbitrary
  700. * file.
  701. * @extends {Array<ConfigArrayElement>}
  702. */
  703. class ConfigArray extends Array {
  704. /**
  705. * Get the plugin environments.
  706. * The returned map cannot be mutated.
  707. * @type {ReadonlyMap<string, Environment>} The plugin environments.
  708. */
  709. get pluginEnvironments() {
  710. return ensurePluginMemberMaps(this).envMap;
  711. }
  712. /**
  713. * Get the plugin processors.
  714. * The returned map cannot be mutated.
  715. * @type {ReadonlyMap<string, Processor>} The plugin processors.
  716. */
  717. get pluginProcessors() {
  718. return ensurePluginMemberMaps(this).processorMap;
  719. }
  720. /**
  721. * Get the plugin rules.
  722. * The returned map cannot be mutated.
  723. * @returns {ReadonlyMap<string, Rule>} The plugin rules.
  724. */
  725. get pluginRules() {
  726. return ensurePluginMemberMaps(this).ruleMap;
  727. }
  728. /**
  729. * Check if this config has `root` flag.
  730. * @returns {boolean} `true` if this config array is root.
  731. */
  732. isRoot() {
  733. for (let i = this.length - 1; i >= 0; --i) {
  734. const root = this[i].root;
  735. if (typeof root === "boolean") {
  736. return root;
  737. }
  738. }
  739. return false;
  740. }
  741. /**
  742. * Extract the config data which is related to a given file.
  743. * @param {string} filePath The absolute path to the target file.
  744. * @returns {ExtractedConfig} The extracted config data.
  745. */
  746. extractConfig(filePath) {
  747. const { cache } = internalSlotsMap$2.get(this);
  748. const indices = getMatchedIndices(this, filePath);
  749. const cacheKey = indices.join(",");
  750. if (!cache.has(cacheKey)) {
  751. cache.set(cacheKey, createConfig(this, indices));
  752. }
  753. return cache.get(cacheKey);
  754. }
  755. /**
  756. * Check if a given path is an additional lint target.
  757. * @param {string} filePath The absolute path to the target file.
  758. * @returns {boolean} `true` if the file is an additional lint target.
  759. */
  760. isAdditionalTargetPath(filePath) {
  761. for (const { criteria, type } of this) {
  762. if (
  763. type === "config" &&
  764. criteria &&
  765. !criteria.endsWithWildcard &&
  766. criteria.test(filePath)
  767. ) {
  768. return true;
  769. }
  770. }
  771. return false;
  772. }
  773. }
  774. /**
  775. * Get the used extracted configs.
  776. * CLIEngine will use this method to collect used deprecated rules.
  777. * @param {ConfigArray} instance The config array object to get.
  778. * @returns {ExtractedConfig[]} The used extracted configs.
  779. * @private
  780. */
  781. function getUsedExtractedConfigs(instance) {
  782. const { cache } = internalSlotsMap$2.get(instance);
  783. return Array.from(cache.values());
  784. }
  785. /**
  786. * @fileoverview `ConfigDependency` class.
  787. *
  788. * `ConfigDependency` class expresses a loaded parser or plugin.
  789. *
  790. * If the parser or plugin was loaded successfully, it has `definition` property
  791. * and `filePath` property. Otherwise, it has `error` property.
  792. *
  793. * When `JSON.stringify()` converted a `ConfigDependency` object to a JSON, it
  794. * omits `definition` property.
  795. *
  796. * `ConfigArrayFactory` creates `ConfigDependency` objects when it loads parsers
  797. * or plugins.
  798. *
  799. * @author Toru Nagashima <https://github.com/mysticatea>
  800. */
  801. /**
  802. * The class is to store parsers or plugins.
  803. * This class hides the loaded object from `JSON.stringify()` and `console.log`.
  804. * @template T
  805. */
  806. class ConfigDependency {
  807. /**
  808. * Initialize this instance.
  809. * @param {Object} data The dependency data.
  810. * @param {T} [data.definition] The dependency if the loading succeeded.
  811. * @param {T} [data.original] The original, non-normalized dependency if the loading succeeded.
  812. * @param {Error} [data.error] The error object if the loading failed.
  813. * @param {string} [data.filePath] The actual path to the dependency if the loading succeeded.
  814. * @param {string} data.id The ID of this dependency.
  815. * @param {string} data.importerName The name of the config file which loads this dependency.
  816. * @param {string} data.importerPath The path to the config file which loads this dependency.
  817. */
  818. constructor({
  819. definition = null,
  820. original = null,
  821. error = null,
  822. filePath = null,
  823. id,
  824. importerName,
  825. importerPath
  826. }) {
  827. /**
  828. * The loaded dependency if the loading succeeded.
  829. * @type {T|null}
  830. */
  831. this.definition = definition;
  832. /**
  833. * The original dependency as loaded directly from disk if the loading succeeded.
  834. * @type {T|null}
  835. */
  836. this.original = original;
  837. /**
  838. * The error object if the loading failed.
  839. * @type {Error|null}
  840. */
  841. this.error = error;
  842. /**
  843. * The loaded dependency if the loading succeeded.
  844. * @type {string|null}
  845. */
  846. this.filePath = filePath;
  847. /**
  848. * The ID of this dependency.
  849. * @type {string}
  850. */
  851. this.id = id;
  852. /**
  853. * The name of the config file which loads this dependency.
  854. * @type {string}
  855. */
  856. this.importerName = importerName;
  857. /**
  858. * The path to the config file which loads this dependency.
  859. * @type {string}
  860. */
  861. this.importerPath = importerPath;
  862. }
  863. // eslint-disable-next-line jsdoc/require-description
  864. /**
  865. * @returns {Object} a JSON compatible object.
  866. */
  867. toJSON() {
  868. const obj = this[util__default["default"].inspect.custom]();
  869. // Display `error.message` (`Error#message` is unenumerable).
  870. if (obj.error instanceof Error) {
  871. obj.error = { ...obj.error, message: obj.error.message };
  872. }
  873. return obj;
  874. }
  875. // eslint-disable-next-line jsdoc/require-description
  876. /**
  877. * @returns {Object} an object to display by `console.log()`.
  878. */
  879. [util__default["default"].inspect.custom]() {
  880. const {
  881. definition: _ignore1, // eslint-disable-line no-unused-vars
  882. original: _ignore2, // eslint-disable-line no-unused-vars
  883. ...obj
  884. } = this;
  885. return obj;
  886. }
  887. }
  888. /**
  889. * @fileoverview `OverrideTester` class.
  890. *
  891. * `OverrideTester` class handles `files` property and `excludedFiles` property
  892. * of `overrides` config.
  893. *
  894. * It provides one method.
  895. *
  896. * - `test(filePath)`
  897. * Test if a file path matches the pair of `files` property and
  898. * `excludedFiles` property. The `filePath` argument must be an absolute
  899. * path.
  900. *
  901. * `ConfigArrayFactory` creates `OverrideTester` objects when it processes
  902. * `overrides` properties.
  903. *
  904. * @author Toru Nagashima <https://github.com/mysticatea>
  905. */
  906. const { Minimatch } = minimatch__default["default"];
  907. const minimatchOpts = { dot: true, matchBase: true };
  908. /**
  909. * @typedef {Object} Pattern
  910. * @property {InstanceType<Minimatch>[] | null} includes The positive matchers.
  911. * @property {InstanceType<Minimatch>[] | null} excludes The negative matchers.
  912. */
  913. /**
  914. * Normalize a given pattern to an array.
  915. * @param {string|string[]|undefined} patterns A glob pattern or an array of glob patterns.
  916. * @returns {string[]|null} Normalized patterns.
  917. * @private
  918. */
  919. function normalizePatterns(patterns) {
  920. if (Array.isArray(patterns)) {
  921. return patterns.filter(Boolean);
  922. }
  923. if (typeof patterns === "string" && patterns) {
  924. return [patterns];
  925. }
  926. return [];
  927. }
  928. /**
  929. * Create the matchers of given patterns.
  930. * @param {string[]} patterns The patterns.
  931. * @returns {InstanceType<Minimatch>[] | null} The matchers.
  932. */
  933. function toMatcher(patterns) {
  934. if (patterns.length === 0) {
  935. return null;
  936. }
  937. return patterns.map(pattern => {
  938. if (/^\.[/\\]/u.test(pattern)) {
  939. return new Minimatch(
  940. pattern.slice(2),
  941. // `./*.js` should not match with `subdir/foo.js`
  942. { ...minimatchOpts, matchBase: false }
  943. );
  944. }
  945. return new Minimatch(pattern, minimatchOpts);
  946. });
  947. }
  948. /**
  949. * Convert a given matcher to string.
  950. * @param {Pattern} matchers The matchers.
  951. * @returns {string} The string expression of the matcher.
  952. */
  953. function patternToJson({ includes, excludes }) {
  954. return {
  955. includes: includes && includes.map(m => m.pattern),
  956. excludes: excludes && excludes.map(m => m.pattern)
  957. };
  958. }
  959. /**
  960. * The class to test given paths are matched by the patterns.
  961. */
  962. class OverrideTester {
  963. /**
  964. * Create a tester with given criteria.
  965. * If there are no criteria, returns `null`.
  966. * @param {string|string[]} files The glob patterns for included files.
  967. * @param {string|string[]} excludedFiles The glob patterns for excluded files.
  968. * @param {string} basePath The path to the base directory to test paths.
  969. * @returns {OverrideTester|null} The created instance or `null`.
  970. */
  971. static create(files, excludedFiles, basePath) {
  972. const includePatterns = normalizePatterns(files);
  973. const excludePatterns = normalizePatterns(excludedFiles);
  974. let endsWithWildcard = false;
  975. if (includePatterns.length === 0) {
  976. return null;
  977. }
  978. // Rejects absolute paths or relative paths to parents.
  979. for (const pattern of includePatterns) {
  980. if (path__default["default"].isAbsolute(pattern) || pattern.includes("..")) {
  981. throw new Error(`Invalid override pattern (expected relative path not containing '..'): ${pattern}`);
  982. }
  983. if (pattern.endsWith("*")) {
  984. endsWithWildcard = true;
  985. }
  986. }
  987. for (const pattern of excludePatterns) {
  988. if (path__default["default"].isAbsolute(pattern) || pattern.includes("..")) {
  989. throw new Error(`Invalid override pattern (expected relative path not containing '..'): ${pattern}`);
  990. }
  991. }
  992. const includes = toMatcher(includePatterns);
  993. const excludes = toMatcher(excludePatterns);
  994. return new OverrideTester(
  995. [{ includes, excludes }],
  996. basePath,
  997. endsWithWildcard
  998. );
  999. }
  1000. /**
  1001. * Combine two testers by logical and.
  1002. * If either of the testers was `null`, returns the other tester.
  1003. * The `basePath` property of the two must be the same value.
  1004. * @param {OverrideTester|null} a A tester.
  1005. * @param {OverrideTester|null} b Another tester.
  1006. * @returns {OverrideTester|null} Combined tester.
  1007. */
  1008. static and(a, b) {
  1009. if (!b) {
  1010. return a && new OverrideTester(
  1011. a.patterns,
  1012. a.basePath,
  1013. a.endsWithWildcard
  1014. );
  1015. }
  1016. if (!a) {
  1017. return new OverrideTester(
  1018. b.patterns,
  1019. b.basePath,
  1020. b.endsWithWildcard
  1021. );
  1022. }
  1023. assert__default["default"].strictEqual(a.basePath, b.basePath);
  1024. return new OverrideTester(
  1025. a.patterns.concat(b.patterns),
  1026. a.basePath,
  1027. a.endsWithWildcard || b.endsWithWildcard
  1028. );
  1029. }
  1030. /**
  1031. * Initialize this instance.
  1032. * @param {Pattern[]} patterns The matchers.
  1033. * @param {string} basePath The base path.
  1034. * @param {boolean} endsWithWildcard If `true` then a pattern ends with `*`.
  1035. */
  1036. constructor(patterns, basePath, endsWithWildcard = false) {
  1037. /** @type {Pattern[]} */
  1038. this.patterns = patterns;
  1039. /** @type {string} */
  1040. this.basePath = basePath;
  1041. /** @type {boolean} */
  1042. this.endsWithWildcard = endsWithWildcard;
  1043. }
  1044. /**
  1045. * Test if a given path is matched or not.
  1046. * @param {string} filePath The absolute path to the target file.
  1047. * @returns {boolean} `true` if the path was matched.
  1048. */
  1049. test(filePath) {
  1050. if (typeof filePath !== "string" || !path__default["default"].isAbsolute(filePath)) {
  1051. throw new Error(`'filePath' should be an absolute path, but got ${filePath}.`);
  1052. }
  1053. const relativePath = path__default["default"].relative(this.basePath, filePath);
  1054. return this.patterns.every(({ includes, excludes }) => (
  1055. (!includes || includes.some(m => m.match(relativePath))) &&
  1056. (!excludes || !excludes.some(m => m.match(relativePath)))
  1057. ));
  1058. }
  1059. // eslint-disable-next-line jsdoc/require-description
  1060. /**
  1061. * @returns {Object} a JSON compatible object.
  1062. */
  1063. toJSON() {
  1064. if (this.patterns.length === 1) {
  1065. return {
  1066. ...patternToJson(this.patterns[0]),
  1067. basePath: this.basePath
  1068. };
  1069. }
  1070. return {
  1071. AND: this.patterns.map(patternToJson),
  1072. basePath: this.basePath
  1073. };
  1074. }
  1075. // eslint-disable-next-line jsdoc/require-description
  1076. /**
  1077. * @returns {Object} an object to display by `console.log()`.
  1078. */
  1079. [util__default["default"].inspect.custom]() {
  1080. return this.toJSON();
  1081. }
  1082. }
  1083. /**
  1084. * @fileoverview `ConfigArray` class.
  1085. * @author Toru Nagashima <https://github.com/mysticatea>
  1086. */
  1087. /**
  1088. * @fileoverview Config file operations. This file must be usable in the browser,
  1089. * so no Node-specific code can be here.
  1090. * @author Nicholas C. Zakas
  1091. */
  1092. //------------------------------------------------------------------------------
  1093. // Private
  1094. //------------------------------------------------------------------------------
  1095. const RULE_SEVERITY_STRINGS = ["off", "warn", "error"],
  1096. RULE_SEVERITY = RULE_SEVERITY_STRINGS.reduce((map, value, index) => {
  1097. map[value] = index;
  1098. return map;
  1099. }, {}),
  1100. VALID_SEVERITIES = [0, 1, 2, "off", "warn", "error"];
  1101. //------------------------------------------------------------------------------
  1102. // Public Interface
  1103. //------------------------------------------------------------------------------
  1104. /**
  1105. * Normalizes the severity value of a rule's configuration to a number
  1106. * @param {(number|string|[number, ...*]|[string, ...*])} ruleConfig A rule's configuration value, generally
  1107. * received from the user. A valid config value is either 0, 1, 2, the string "off" (treated the same as 0),
  1108. * the string "warn" (treated the same as 1), the string "error" (treated the same as 2), or an array
  1109. * whose first element is one of the above values. Strings are matched case-insensitively.
  1110. * @returns {(0|1|2)} The numeric severity value if the config value was valid, otherwise 0.
  1111. */
  1112. function getRuleSeverity(ruleConfig) {
  1113. const severityValue = Array.isArray(ruleConfig) ? ruleConfig[0] : ruleConfig;
  1114. if (severityValue === 0 || severityValue === 1 || severityValue === 2) {
  1115. return severityValue;
  1116. }
  1117. if (typeof severityValue === "string") {
  1118. return RULE_SEVERITY[severityValue.toLowerCase()] || 0;
  1119. }
  1120. return 0;
  1121. }
  1122. /**
  1123. * Converts old-style severity settings (0, 1, 2) into new-style
  1124. * severity settings (off, warn, error) for all rules. Assumption is that severity
  1125. * values have already been validated as correct.
  1126. * @param {Object} config The config object to normalize.
  1127. * @returns {void}
  1128. */
  1129. function normalizeToStrings(config) {
  1130. if (config.rules) {
  1131. Object.keys(config.rules).forEach(ruleId => {
  1132. const ruleConfig = config.rules[ruleId];
  1133. if (typeof ruleConfig === "number") {
  1134. config.rules[ruleId] = RULE_SEVERITY_STRINGS[ruleConfig] || RULE_SEVERITY_STRINGS[0];
  1135. } else if (Array.isArray(ruleConfig) && typeof ruleConfig[0] === "number") {
  1136. ruleConfig[0] = RULE_SEVERITY_STRINGS[ruleConfig[0]] || RULE_SEVERITY_STRINGS[0];
  1137. }
  1138. });
  1139. }
  1140. }
  1141. /**
  1142. * Determines if the severity for the given rule configuration represents an error.
  1143. * @param {int|string|Array} ruleConfig The configuration for an individual rule.
  1144. * @returns {boolean} True if the rule represents an error, false if not.
  1145. */
  1146. function isErrorSeverity(ruleConfig) {
  1147. return getRuleSeverity(ruleConfig) === 2;
  1148. }
  1149. /**
  1150. * Checks whether a given config has valid severity or not.
  1151. * @param {number|string|Array} ruleConfig The configuration for an individual rule.
  1152. * @returns {boolean} `true` if the configuration has valid severity.
  1153. */
  1154. function isValidSeverity(ruleConfig) {
  1155. let severity = Array.isArray(ruleConfig) ? ruleConfig[0] : ruleConfig;
  1156. if (typeof severity === "string") {
  1157. severity = severity.toLowerCase();
  1158. }
  1159. return VALID_SEVERITIES.indexOf(severity) !== -1;
  1160. }
  1161. /**
  1162. * Checks whether every rule of a given config has valid severity or not.
  1163. * @param {Object} config The configuration for rules.
  1164. * @returns {boolean} `true` if the configuration has valid severity.
  1165. */
  1166. function isEverySeverityValid(config) {
  1167. return Object.keys(config).every(ruleId => isValidSeverity(config[ruleId]));
  1168. }
  1169. /**
  1170. * Normalizes a value for a global in a config
  1171. * @param {(boolean|string|null)} configuredValue The value given for a global in configuration or in
  1172. * a global directive comment
  1173. * @returns {("readable"|"writeable"|"off")} The value normalized as a string
  1174. * @throws Error if global value is invalid
  1175. */
  1176. function normalizeConfigGlobal(configuredValue) {
  1177. switch (configuredValue) {
  1178. case "off":
  1179. return "off";
  1180. case true:
  1181. case "true":
  1182. case "writeable":
  1183. case "writable":
  1184. return "writable";
  1185. case null:
  1186. case false:
  1187. case "false":
  1188. case "readable":
  1189. case "readonly":
  1190. return "readonly";
  1191. default:
  1192. throw new Error(`'${configuredValue}' is not a valid configuration for a global (use 'readonly', 'writable', or 'off')`);
  1193. }
  1194. }
  1195. var ConfigOps = {
  1196. __proto__: null,
  1197. getRuleSeverity: getRuleSeverity,
  1198. normalizeToStrings: normalizeToStrings,
  1199. isErrorSeverity: isErrorSeverity,
  1200. isValidSeverity: isValidSeverity,
  1201. isEverySeverityValid: isEverySeverityValid,
  1202. normalizeConfigGlobal: normalizeConfigGlobal
  1203. };
  1204. /**
  1205. * @fileoverview Provide the function that emits deprecation warnings.
  1206. * @author Toru Nagashima <http://github.com/mysticatea>
  1207. */
  1208. //------------------------------------------------------------------------------
  1209. // Private
  1210. //------------------------------------------------------------------------------
  1211. // Defitions for deprecation warnings.
  1212. const deprecationWarningMessages = {
  1213. ESLINT_LEGACY_ECMAFEATURES:
  1214. "The 'ecmaFeatures' config file property is deprecated and has no effect.",
  1215. ESLINT_PERSONAL_CONFIG_LOAD:
  1216. "'~/.eslintrc.*' config files have been deprecated. " +
  1217. "Please use a config file per project or the '--config' option.",
  1218. ESLINT_PERSONAL_CONFIG_SUPPRESS:
  1219. "'~/.eslintrc.*' config files have been deprecated. " +
  1220. "Please remove it or add 'root:true' to the config files in your " +
  1221. "projects in order to avoid loading '~/.eslintrc.*' accidentally."
  1222. };
  1223. const sourceFileErrorCache = new Set();
  1224. /**
  1225. * Emits a deprecation warning containing a given filepath. A new deprecation warning is emitted
  1226. * for each unique file path, but repeated invocations with the same file path have no effect.
  1227. * No warnings are emitted if the `--no-deprecation` or `--no-warnings` Node runtime flags are active.
  1228. * @param {string} source The name of the configuration source to report the warning for.
  1229. * @param {string} errorCode The warning message to show.
  1230. * @returns {void}
  1231. */
  1232. function emitDeprecationWarning(source, errorCode) {
  1233. const cacheKey = JSON.stringify({ source, errorCode });
  1234. if (sourceFileErrorCache.has(cacheKey)) {
  1235. return;
  1236. }
  1237. sourceFileErrorCache.add(cacheKey);
  1238. const rel = path__default["default"].relative(process.cwd(), source);
  1239. const message = deprecationWarningMessages[errorCode];
  1240. process.emitWarning(
  1241. `${message} (found in "${rel}")`,
  1242. "DeprecationWarning",
  1243. errorCode
  1244. );
  1245. }
  1246. /**
  1247. * @fileoverview The instance of Ajv validator.
  1248. * @author Evgeny Poberezkin
  1249. */
  1250. //-----------------------------------------------------------------------------
  1251. // Helpers
  1252. //-----------------------------------------------------------------------------
  1253. /*
  1254. * Copied from ajv/lib/refs/json-schema-draft-04.json
  1255. * The MIT License (MIT)
  1256. * Copyright (c) 2015-2017 Evgeny Poberezkin
  1257. */
  1258. const metaSchema = {
  1259. id: "http://json-schema.org/draft-04/schema#",
  1260. $schema: "http://json-schema.org/draft-04/schema#",
  1261. description: "Core schema meta-schema",
  1262. definitions: {
  1263. schemaArray: {
  1264. type: "array",
  1265. minItems: 1,
  1266. items: { $ref: "#" }
  1267. },
  1268. positiveInteger: {
  1269. type: "integer",
  1270. minimum: 0
  1271. },
  1272. positiveIntegerDefault0: {
  1273. allOf: [{ $ref: "#/definitions/positiveInteger" }, { default: 0 }]
  1274. },
  1275. simpleTypes: {
  1276. enum: ["array", "boolean", "integer", "null", "number", "object", "string"]
  1277. },
  1278. stringArray: {
  1279. type: "array",
  1280. items: { type: "string" },
  1281. minItems: 1,
  1282. uniqueItems: true
  1283. }
  1284. },
  1285. type: "object",
  1286. properties: {
  1287. id: {
  1288. type: "string"
  1289. },
  1290. $schema: {
  1291. type: "string"
  1292. },
  1293. title: {
  1294. type: "string"
  1295. },
  1296. description: {
  1297. type: "string"
  1298. },
  1299. default: { },
  1300. multipleOf: {
  1301. type: "number",
  1302. minimum: 0,
  1303. exclusiveMinimum: true
  1304. },
  1305. maximum: {
  1306. type: "number"
  1307. },
  1308. exclusiveMaximum: {
  1309. type: "boolean",
  1310. default: false
  1311. },
  1312. minimum: {
  1313. type: "number"
  1314. },
  1315. exclusiveMinimum: {
  1316. type: "boolean",
  1317. default: false
  1318. },
  1319. maxLength: { $ref: "#/definitions/positiveInteger" },
  1320. minLength: { $ref: "#/definitions/positiveIntegerDefault0" },
  1321. pattern: {
  1322. type: "string",
  1323. format: "regex"
  1324. },
  1325. additionalItems: {
  1326. anyOf: [
  1327. { type: "boolean" },
  1328. { $ref: "#" }
  1329. ],
  1330. default: { }
  1331. },
  1332. items: {
  1333. anyOf: [
  1334. { $ref: "#" },
  1335. { $ref: "#/definitions/schemaArray" }
  1336. ],
  1337. default: { }
  1338. },
  1339. maxItems: { $ref: "#/definitions/positiveInteger" },
  1340. minItems: { $ref: "#/definitions/positiveIntegerDefault0" },
  1341. uniqueItems: {
  1342. type: "boolean",
  1343. default: false
  1344. },
  1345. maxProperties: { $ref: "#/definitions/positiveInteger" },
  1346. minProperties: { $ref: "#/definitions/positiveIntegerDefault0" },
  1347. required: { $ref: "#/definitions/stringArray" },
  1348. additionalProperties: {
  1349. anyOf: [
  1350. { type: "boolean" },
  1351. { $ref: "#" }
  1352. ],
  1353. default: { }
  1354. },
  1355. definitions: {
  1356. type: "object",
  1357. additionalProperties: { $ref: "#" },
  1358. default: { }
  1359. },
  1360. properties: {
  1361. type: "object",
  1362. additionalProperties: { $ref: "#" },
  1363. default: { }
  1364. },
  1365. patternProperties: {
  1366. type: "object",
  1367. additionalProperties: { $ref: "#" },
  1368. default: { }
  1369. },
  1370. dependencies: {
  1371. type: "object",
  1372. additionalProperties: {
  1373. anyOf: [
  1374. { $ref: "#" },
  1375. { $ref: "#/definitions/stringArray" }
  1376. ]
  1377. }
  1378. },
  1379. enum: {
  1380. type: "array",
  1381. minItems: 1,
  1382. uniqueItems: true
  1383. },
  1384. type: {
  1385. anyOf: [
  1386. { $ref: "#/definitions/simpleTypes" },
  1387. {
  1388. type: "array",
  1389. items: { $ref: "#/definitions/simpleTypes" },
  1390. minItems: 1,
  1391. uniqueItems: true
  1392. }
  1393. ]
  1394. },
  1395. format: { type: "string" },
  1396. allOf: { $ref: "#/definitions/schemaArray" },
  1397. anyOf: { $ref: "#/definitions/schemaArray" },
  1398. oneOf: { $ref: "#/definitions/schemaArray" },
  1399. not: { $ref: "#" }
  1400. },
  1401. dependencies: {
  1402. exclusiveMaximum: ["maximum"],
  1403. exclusiveMinimum: ["minimum"]
  1404. },
  1405. default: { }
  1406. };
  1407. //------------------------------------------------------------------------------
  1408. // Public Interface
  1409. //------------------------------------------------------------------------------
  1410. var ajvOrig = (additionalOptions = {}) => {
  1411. const ajv = new Ajv__default["default"]({
  1412. meta: false,
  1413. useDefaults: true,
  1414. validateSchema: false,
  1415. missingRefs: "ignore",
  1416. verbose: true,
  1417. schemaId: "auto",
  1418. ...additionalOptions
  1419. });
  1420. ajv.addMetaSchema(metaSchema);
  1421. // eslint-disable-next-line no-underscore-dangle
  1422. ajv._opts.defaultMeta = metaSchema.id;
  1423. return ajv;
  1424. };
  1425. /**
  1426. * @fileoverview Applies default rule options
  1427. * @author JoshuaKGoldberg
  1428. */
  1429. /**
  1430. * Check if the variable contains an object strictly rejecting arrays
  1431. * @param {unknown} value an object
  1432. * @returns {boolean} Whether value is an object
  1433. */
  1434. function isObjectNotArray(value) {
  1435. return typeof value === "object" && value !== null && !Array.isArray(value);
  1436. }
  1437. /**
  1438. * Deeply merges second on top of first, creating a new {} object if needed.
  1439. * @param {T} first Base, default value.
  1440. * @param {U} second User-specified value.
  1441. * @returns {T | U | (T & U)} Merged equivalent of second on top of first.
  1442. */
  1443. function deepMergeObjects(first, second) {
  1444. if (second === void 0) {
  1445. return first;
  1446. }
  1447. if (!isObjectNotArray(first) || !isObjectNotArray(second)) {
  1448. return second;
  1449. }
  1450. const result = { ...first, ...second };
  1451. for (const key of Object.keys(second)) {
  1452. if (Object.prototype.propertyIsEnumerable.call(first, key)) {
  1453. result[key] = deepMergeObjects(first[key], second[key]);
  1454. }
  1455. }
  1456. return result;
  1457. }
  1458. /**
  1459. * Deeply merges second on top of first, creating a new [] array if needed.
  1460. * @param {T[] | undefined} first Base, default values.
  1461. * @param {U[] | undefined} second User-specified values.
  1462. * @returns {(T | U | (T & U))[]} Merged equivalent of second on top of first.
  1463. */
  1464. function deepMergeArrays(first, second) {
  1465. if (!first || !second) {
  1466. return second || first || [];
  1467. }
  1468. return [
  1469. ...first.map((value, i) => deepMergeObjects(value, second[i])),
  1470. ...second.slice(first.length)
  1471. ];
  1472. }
  1473. /**
  1474. * @fileoverview Defines a schema for configs.
  1475. * @author Sylvan Mably
  1476. */
  1477. const baseConfigProperties = {
  1478. $schema: { type: "string" },
  1479. env: { type: "object" },
  1480. extends: { $ref: "#/definitions/stringOrStrings" },
  1481. globals: { type: "object" },
  1482. overrides: {
  1483. type: "array",
  1484. items: { $ref: "#/definitions/overrideConfig" },
  1485. additionalItems: false
  1486. },
  1487. parser: { type: ["string", "null"] },
  1488. parserOptions: { type: "object" },
  1489. plugins: { type: "array" },
  1490. processor: { type: "string" },
  1491. rules: { type: "object" },
  1492. settings: { type: "object" },
  1493. noInlineConfig: { type: "boolean" },
  1494. reportUnusedDisableDirectives: { type: "boolean" },
  1495. ecmaFeatures: { type: "object" } // deprecated; logs a warning when used
  1496. };
  1497. const configSchema = {
  1498. definitions: {
  1499. stringOrStrings: {
  1500. oneOf: [
  1501. { type: "string" },
  1502. {
  1503. type: "array",
  1504. items: { type: "string" },
  1505. additionalItems: false
  1506. }
  1507. ]
  1508. },
  1509. stringOrStringsRequired: {
  1510. oneOf: [
  1511. { type: "string" },
  1512. {
  1513. type: "array",
  1514. items: { type: "string" },
  1515. additionalItems: false,
  1516. minItems: 1
  1517. }
  1518. ]
  1519. },
  1520. // Config at top-level.
  1521. objectConfig: {
  1522. type: "object",
  1523. properties: {
  1524. root: { type: "boolean" },
  1525. ignorePatterns: { $ref: "#/definitions/stringOrStrings" },
  1526. ...baseConfigProperties
  1527. },
  1528. additionalProperties: false
  1529. },
  1530. // Config in `overrides`.
  1531. overrideConfig: {
  1532. type: "object",
  1533. properties: {
  1534. excludedFiles: { $ref: "#/definitions/stringOrStrings" },
  1535. files: { $ref: "#/definitions/stringOrStringsRequired" },
  1536. ...baseConfigProperties
  1537. },
  1538. required: ["files"],
  1539. additionalProperties: false
  1540. }
  1541. },
  1542. $ref: "#/definitions/objectConfig"
  1543. };
  1544. /**
  1545. * @fileoverview Defines environment settings and globals.
  1546. * @author Elan Shanker
  1547. */
  1548. //------------------------------------------------------------------------------
  1549. // Helpers
  1550. //------------------------------------------------------------------------------
  1551. /**
  1552. * Get the object that has difference.
  1553. * @param {Record<string,boolean>} current The newer object.
  1554. * @param {Record<string,boolean>} prev The older object.
  1555. * @returns {Record<string,boolean>} The difference object.
  1556. */
  1557. function getDiff(current, prev) {
  1558. const retv = {};
  1559. for (const [key, value] of Object.entries(current)) {
  1560. if (!Object.hasOwnProperty.call(prev, key)) {
  1561. retv[key] = value;
  1562. }
  1563. }
  1564. return retv;
  1565. }
  1566. const newGlobals2015 = getDiff(globals__default["default"].es2015, globals__default["default"].es5); // 19 variables such as Promise, Map, ...
  1567. const newGlobals2017 = {
  1568. Atomics: false,
  1569. SharedArrayBuffer: false
  1570. };
  1571. const newGlobals2020 = {
  1572. BigInt: false,
  1573. BigInt64Array: false,
  1574. BigUint64Array: false,
  1575. globalThis: false
  1576. };
  1577. const newGlobals2021 = {
  1578. AggregateError: false,
  1579. FinalizationRegistry: false,
  1580. WeakRef: false
  1581. };
  1582. //------------------------------------------------------------------------------
  1583. // Public Interface
  1584. //------------------------------------------------------------------------------
  1585. /** @type {Map<string, import("../lib/shared/types").Environment>} */
  1586. var environments = new Map(Object.entries({
  1587. // Language
  1588. builtin: {
  1589. globals: globals__default["default"].es5
  1590. },
  1591. es6: {
  1592. globals: newGlobals2015,
  1593. parserOptions: {
  1594. ecmaVersion: 6
  1595. }
  1596. },
  1597. es2015: {
  1598. globals: newGlobals2015,
  1599. parserOptions: {
  1600. ecmaVersion: 6
  1601. }
  1602. },
  1603. es2016: {
  1604. globals: newGlobals2015,
  1605. parserOptions: {
  1606. ecmaVersion: 7
  1607. }
  1608. },
  1609. es2017: {
  1610. globals: { ...newGlobals2015, ...newGlobals2017 },
  1611. parserOptions: {
  1612. ecmaVersion: 8
  1613. }
  1614. },
  1615. es2018: {
  1616. globals: { ...newGlobals2015, ...newGlobals2017 },
  1617. parserOptions: {
  1618. ecmaVersion: 9
  1619. }
  1620. },
  1621. es2019: {
  1622. globals: { ...newGlobals2015, ...newGlobals2017 },
  1623. parserOptions: {
  1624. ecmaVersion: 10
  1625. }
  1626. },
  1627. es2020: {
  1628. globals: { ...newGlobals2015, ...newGlobals2017, ...newGlobals2020 },
  1629. parserOptions: {
  1630. ecmaVersion: 11
  1631. }
  1632. },
  1633. es2021: {
  1634. globals: { ...newGlobals2015, ...newGlobals2017, ...newGlobals2020, ...newGlobals2021 },
  1635. parserOptions: {
  1636. ecmaVersion: 12
  1637. }
  1638. },
  1639. es2022: {
  1640. globals: { ...newGlobals2015, ...newGlobals2017, ...newGlobals2020, ...newGlobals2021 },
  1641. parserOptions: {
  1642. ecmaVersion: 13
  1643. }
  1644. },
  1645. es2023: {
  1646. globals: { ...newGlobals2015, ...newGlobals2017, ...newGlobals2020, ...newGlobals2021 },
  1647. parserOptions: {
  1648. ecmaVersion: 14
  1649. }
  1650. },
  1651. es2024: {
  1652. globals: { ...newGlobals2015, ...newGlobals2017, ...newGlobals2020, ...newGlobals2021 },
  1653. parserOptions: {
  1654. ecmaVersion: 15
  1655. }
  1656. },
  1657. // Platforms
  1658. browser: {
  1659. globals: globals__default["default"].browser
  1660. },
  1661. node: {
  1662. globals: globals__default["default"].node,
  1663. parserOptions: {
  1664. ecmaFeatures: {
  1665. globalReturn: true
  1666. }
  1667. }
  1668. },
  1669. "shared-node-browser": {
  1670. globals: globals__default["default"]["shared-node-browser"]
  1671. },
  1672. worker: {
  1673. globals: globals__default["default"].worker
  1674. },
  1675. serviceworker: {
  1676. globals: globals__default["default"].serviceworker
  1677. },
  1678. // Frameworks
  1679. commonjs: {
  1680. globals: globals__default["default"].commonjs,
  1681. parserOptions: {
  1682. ecmaFeatures: {
  1683. globalReturn: true
  1684. }
  1685. }
  1686. },
  1687. amd: {
  1688. globals: globals__default["default"].amd
  1689. },
  1690. mocha: {
  1691. globals: globals__default["default"].mocha
  1692. },
  1693. jasmine: {
  1694. globals: globals__default["default"].jasmine
  1695. },
  1696. jest: {
  1697. globals: globals__default["default"].jest
  1698. },
  1699. phantomjs: {
  1700. globals: globals__default["default"].phantomjs
  1701. },
  1702. jquery: {
  1703. globals: globals__default["default"].jquery
  1704. },
  1705. qunit: {
  1706. globals: globals__default["default"].qunit
  1707. },
  1708. prototypejs: {
  1709. globals: globals__default["default"].prototypejs
  1710. },
  1711. shelljs: {
  1712. globals: globals__default["default"].shelljs
  1713. },
  1714. meteor: {
  1715. globals: globals__default["default"].meteor
  1716. },
  1717. mongo: {
  1718. globals: globals__default["default"].mongo
  1719. },
  1720. protractor: {
  1721. globals: globals__default["default"].protractor
  1722. },
  1723. applescript: {
  1724. globals: globals__default["default"].applescript
  1725. },
  1726. nashorn: {
  1727. globals: globals__default["default"].nashorn
  1728. },
  1729. atomtest: {
  1730. globals: globals__default["default"].atomtest
  1731. },
  1732. embertest: {
  1733. globals: globals__default["default"].embertest
  1734. },
  1735. webextensions: {
  1736. globals: globals__default["default"].webextensions
  1737. },
  1738. greasemonkey: {
  1739. globals: globals__default["default"].greasemonkey
  1740. }
  1741. }));
  1742. /**
  1743. * @fileoverview Validates configs.
  1744. * @author Brandon Mills
  1745. */
  1746. const ajv = ajvOrig();
  1747. const ruleValidators = new WeakMap();
  1748. const noop = Function.prototype;
  1749. //------------------------------------------------------------------------------
  1750. // Private
  1751. //------------------------------------------------------------------------------
  1752. let validateSchema;
  1753. const severityMap = {
  1754. error: 2,
  1755. warn: 1,
  1756. off: 0
  1757. };
  1758. const validated = new WeakSet();
  1759. // JSON schema that disallows passing any options
  1760. const noOptionsSchema = Object.freeze({
  1761. type: "array",
  1762. minItems: 0,
  1763. maxItems: 0
  1764. });
  1765. //-----------------------------------------------------------------------------
  1766. // Exports
  1767. //-----------------------------------------------------------------------------
  1768. class ConfigValidator {
  1769. constructor({ builtInRules = new Map() } = {}) {
  1770. this.builtInRules = builtInRules;
  1771. }
  1772. /**
  1773. * Gets a complete options schema for a rule.
  1774. * @param {Rule} rule A rule object
  1775. * @throws {TypeError} If `meta.schema` is specified but is not an array, object or `false`.
  1776. * @returns {Object|null} JSON Schema for the rule's options.
  1777. * `null` if rule wasn't passed or its `meta.schema` is `false`.
  1778. */
  1779. getRuleOptionsSchema(rule) {
  1780. if (!rule) {
  1781. return null;
  1782. }
  1783. if (!rule.meta) {
  1784. return { ...noOptionsSchema }; // default if `meta.schema` is not specified
  1785. }
  1786. const schema = rule.meta.schema;
  1787. if (typeof schema === "undefined") {
  1788. return { ...noOptionsSchema }; // default if `meta.schema` is not specified
  1789. }
  1790. // `schema:false` is an allowed explicit opt-out of options validation for the rule
  1791. if (schema === false) {
  1792. return null;
  1793. }
  1794. if (typeof schema !== "object" || schema === null) {
  1795. throw new TypeError("Rule's `meta.schema` must be an array or object");
  1796. }
  1797. // ESLint-specific array form needs to be converted into a valid JSON Schema definition
  1798. if (Array.isArray(schema)) {
  1799. if (schema.length) {
  1800. return {
  1801. type: "array",
  1802. items: schema,
  1803. minItems: 0,
  1804. maxItems: schema.length
  1805. };
  1806. }
  1807. // `schema:[]` is an explicit way to specify that the rule does not accept any options
  1808. return { ...noOptionsSchema };
  1809. }
  1810. // `schema:<object>` is assumed to be a valid JSON Schema definition
  1811. return schema;
  1812. }
  1813. /**
  1814. * Validates a rule's severity and returns the severity value. Throws an error if the severity is invalid.
  1815. * @param {options} options The given options for the rule.
  1816. * @returns {number|string} The rule's severity value
  1817. */
  1818. validateRuleSeverity(options) {
  1819. const severity = Array.isArray(options) ? options[0] : options;
  1820. const normSeverity = typeof severity === "string" ? severityMap[severity.toLowerCase()] : severity;
  1821. if (normSeverity === 0 || normSeverity === 1 || normSeverity === 2) {
  1822. return normSeverity;
  1823. }
  1824. throw new Error(`\tSeverity should be one of the following: 0 = off, 1 = warn, 2 = error (you passed '${util__default["default"].inspect(severity).replace(/'/gu, "\"").replace(/\n/gu, "")}').\n`);
  1825. }
  1826. /**
  1827. * Validates the non-severity options passed to a rule, based on its schema.
  1828. * @param {{create: Function}} rule The rule to validate
  1829. * @param {Array} localOptions The options for the rule, excluding severity
  1830. * @returns {void}
  1831. */
  1832. validateRuleSchema(rule, localOptions) {
  1833. if (!ruleValidators.has(rule)) {
  1834. try {
  1835. const schema = this.getRuleOptionsSchema(rule);
  1836. if (schema) {
  1837. ruleValidators.set(rule, ajv.compile(schema));
  1838. }
  1839. } catch (err) {
  1840. const errorWithCode = new Error(err.message, { cause: err });
  1841. errorWithCode.code = "ESLINT_INVALID_RULE_OPTIONS_SCHEMA";
  1842. throw errorWithCode;
  1843. }
  1844. }
  1845. const validateRule = ruleValidators.get(rule);
  1846. if (validateRule) {
  1847. const mergedOptions = deepMergeArrays(rule.meta?.defaultOptions, localOptions);
  1848. validateRule(mergedOptions);
  1849. if (validateRule.errors) {
  1850. throw new Error(validateRule.errors.map(
  1851. error => `\tValue ${JSON.stringify(error.data)} ${error.message}.\n`
  1852. ).join(""));
  1853. }
  1854. }
  1855. }
  1856. /**
  1857. * Validates a rule's options against its schema.
  1858. * @param {{create: Function}|null} rule The rule that the config is being validated for
  1859. * @param {string} ruleId The rule's unique name.
  1860. * @param {Array|number} options The given options for the rule.
  1861. * @param {string|null} source The name of the configuration source to report in any errors. If null or undefined,
  1862. * no source is prepended to the message.
  1863. * @returns {void}
  1864. */
  1865. validateRuleOptions(rule, ruleId, options, source = null) {
  1866. try {
  1867. const severity = this.validateRuleSeverity(options);
  1868. if (severity !== 0) {
  1869. this.validateRuleSchema(rule, Array.isArray(options) ? options.slice(1) : []);
  1870. }
  1871. } catch (err) {
  1872. let enhancedMessage = err.code === "ESLINT_INVALID_RULE_OPTIONS_SCHEMA"
  1873. ? `Error while processing options validation schema of rule '${ruleId}': ${err.message}`
  1874. : `Configuration for rule "${ruleId}" is invalid:\n${err.message}`;
  1875. if (typeof source === "string") {
  1876. enhancedMessage = `${source}:\n\t${enhancedMessage}`;
  1877. }
  1878. const enhancedError = new Error(enhancedMessage, { cause: err });
  1879. if (err.code) {
  1880. enhancedError.code = err.code;
  1881. }
  1882. throw enhancedError;
  1883. }
  1884. }
  1885. /**
  1886. * Validates an environment object
  1887. * @param {Object} environment The environment config object to validate.
  1888. * @param {string} source The name of the configuration source to report in any errors.
  1889. * @param {function(envId:string): Object} [getAdditionalEnv] A map from strings to loaded environments.
  1890. * @returns {void}
  1891. */
  1892. validateEnvironment(
  1893. environment,
  1894. source,
  1895. getAdditionalEnv = noop
  1896. ) {
  1897. // not having an environment is ok
  1898. if (!environment) {
  1899. return;
  1900. }
  1901. Object.keys(environment).forEach(id => {
  1902. const env = getAdditionalEnv(id) || environments.get(id) || null;
  1903. if (!env) {
  1904. const message = `${source}:\n\tEnvironment key "${id}" is unknown\n`;
  1905. throw new Error(message);
  1906. }
  1907. });
  1908. }
  1909. /**
  1910. * Validates a rules config object
  1911. * @param {Object} rulesConfig The rules config object to validate.
  1912. * @param {string} source The name of the configuration source to report in any errors.
  1913. * @param {function(ruleId:string): Object} getAdditionalRule A map from strings to loaded rules
  1914. * @returns {void}
  1915. */
  1916. validateRules(
  1917. rulesConfig,
  1918. source,
  1919. getAdditionalRule = noop
  1920. ) {
  1921. if (!rulesConfig) {
  1922. return;
  1923. }
  1924. Object.keys(rulesConfig).forEach(id => {
  1925. const rule = getAdditionalRule(id) || this.builtInRules.get(id) || null;
  1926. this.validateRuleOptions(rule, id, rulesConfig[id], source);
  1927. });
  1928. }
  1929. /**
  1930. * Validates a `globals` section of a config file
  1931. * @param {Object} globalsConfig The `globals` section
  1932. * @param {string|null} source The name of the configuration source to report in the event of an error.
  1933. * @returns {void}
  1934. */
  1935. validateGlobals(globalsConfig, source = null) {
  1936. if (!globalsConfig) {
  1937. return;
  1938. }
  1939. Object.entries(globalsConfig)
  1940. .forEach(([configuredGlobal, configuredValue]) => {
  1941. try {
  1942. normalizeConfigGlobal(configuredValue);
  1943. } catch (err) {
  1944. throw new Error(`ESLint configuration of global '${configuredGlobal}' in ${source} is invalid:\n${err.message}`);
  1945. }
  1946. });
  1947. }
  1948. /**
  1949. * Validate `processor` configuration.
  1950. * @param {string|undefined} processorName The processor name.
  1951. * @param {string} source The name of config file.
  1952. * @param {function(id:string): Processor} getProcessor The getter of defined processors.
  1953. * @returns {void}
  1954. */
  1955. validateProcessor(processorName, source, getProcessor) {
  1956. if (processorName && !getProcessor(processorName)) {
  1957. throw new Error(`ESLint configuration of processor in '${source}' is invalid: '${processorName}' was not found.`);
  1958. }
  1959. }
  1960. /**
  1961. * Formats an array of schema validation errors.
  1962. * @param {Array} errors An array of error messages to format.
  1963. * @returns {string} Formatted error message
  1964. */
  1965. formatErrors(errors) {
  1966. return errors.map(error => {
  1967. if (error.keyword === "additionalProperties") {
  1968. const formattedPropertyPath = error.dataPath.length ? `${error.dataPath.slice(1)}.${error.params.additionalProperty}` : error.params.additionalProperty;
  1969. return `Unexpected top-level property "${formattedPropertyPath}"`;
  1970. }
  1971. if (error.keyword === "type") {
  1972. const formattedField = error.dataPath.slice(1);
  1973. const formattedExpectedType = Array.isArray(error.schema) ? error.schema.join("/") : error.schema;
  1974. const formattedValue = JSON.stringify(error.data);
  1975. return `Property "${formattedField}" is the wrong type (expected ${formattedExpectedType} but got \`${formattedValue}\`)`;
  1976. }
  1977. const field = error.dataPath[0] === "." ? error.dataPath.slice(1) : error.dataPath;
  1978. return `"${field}" ${error.message}. Value: ${JSON.stringify(error.data)}`;
  1979. }).map(message => `\t- ${message}.\n`).join("");
  1980. }
  1981. /**
  1982. * Validates the top level properties of the config object.
  1983. * @param {Object} config The config object to validate.
  1984. * @param {string} source The name of the configuration source to report in any errors.
  1985. * @returns {void}
  1986. */
  1987. validateConfigSchema(config, source = null) {
  1988. validateSchema = validateSchema || ajv.compile(configSchema);
  1989. if (!validateSchema(config)) {
  1990. throw new Error(`ESLint configuration in ${source} is invalid:\n${this.formatErrors(validateSchema.errors)}`);
  1991. }
  1992. if (Object.hasOwnProperty.call(config, "ecmaFeatures")) {
  1993. emitDeprecationWarning(source, "ESLINT_LEGACY_ECMAFEATURES");
  1994. }
  1995. }
  1996. /**
  1997. * Validates an entire config object.
  1998. * @param {Object} config The config object to validate.
  1999. * @param {string} source The name of the configuration source to report in any errors.
  2000. * @param {function(ruleId:string): Object} [getAdditionalRule] A map from strings to loaded rules.
  2001. * @param {function(envId:string): Object} [getAdditionalEnv] A map from strings to loaded envs.
  2002. * @returns {void}
  2003. */
  2004. validate(config, source, getAdditionalRule, getAdditionalEnv) {
  2005. this.validateConfigSchema(config, source);
  2006. this.validateRules(config.rules, source, getAdditionalRule);
  2007. this.validateEnvironment(config.env, source, getAdditionalEnv);
  2008. this.validateGlobals(config.globals, source);
  2009. for (const override of config.overrides || []) {
  2010. this.validateRules(override.rules, source, getAdditionalRule);
  2011. this.validateEnvironment(override.env, source, getAdditionalEnv);
  2012. this.validateGlobals(config.globals, source);
  2013. }
  2014. }
  2015. /**
  2016. * Validate config array object.
  2017. * @param {ConfigArray} configArray The config array to validate.
  2018. * @returns {void}
  2019. */
  2020. validateConfigArray(configArray) {
  2021. const getPluginEnv = Map.prototype.get.bind(configArray.pluginEnvironments);
  2022. const getPluginProcessor = Map.prototype.get.bind(configArray.pluginProcessors);
  2023. const getPluginRule = Map.prototype.get.bind(configArray.pluginRules);
  2024. // Validate.
  2025. for (const element of configArray) {
  2026. if (validated.has(element)) {
  2027. continue;
  2028. }
  2029. validated.add(element);
  2030. this.validateEnvironment(element.env, element.name, getPluginEnv);
  2031. this.validateGlobals(element.globals, element.name);
  2032. this.validateProcessor(element.processor, element.name, getPluginProcessor);
  2033. this.validateRules(element.rules, element.name, getPluginRule);
  2034. }
  2035. }
  2036. }
  2037. /**
  2038. * @fileoverview Common helpers for naming of plugins, formatters and configs
  2039. */
  2040. const NAMESPACE_REGEX = /^@.*\//iu;
  2041. /**
  2042. * Brings package name to correct format based on prefix
  2043. * @param {string} name The name of the package.
  2044. * @param {string} prefix Can be either "eslint-plugin", "eslint-config" or "eslint-formatter"
  2045. * @returns {string} Normalized name of the package
  2046. * @private
  2047. */
  2048. function normalizePackageName(name, prefix) {
  2049. let normalizedName = name;
  2050. /**
  2051. * On Windows, name can come in with Windows slashes instead of Unix slashes.
  2052. * Normalize to Unix first to avoid errors later on.
  2053. * https://github.com/eslint/eslint/issues/5644
  2054. */
  2055. if (normalizedName.includes("\\")) {
  2056. normalizedName = normalizedName.replace(/\\/gu, "/");
  2057. }
  2058. if (normalizedName.charAt(0) === "@") {
  2059. /**
  2060. * it's a scoped package
  2061. * package name is the prefix, or just a username
  2062. */
  2063. const scopedPackageShortcutRegex = new RegExp(`^(@[^/]+)(?:/(?:${prefix})?)?$`, "u"),
  2064. scopedPackageNameRegex = new RegExp(`^${prefix}(-|$)`, "u");
  2065. if (scopedPackageShortcutRegex.test(normalizedName)) {
  2066. normalizedName = normalizedName.replace(scopedPackageShortcutRegex, `$1/${prefix}`);
  2067. } else if (!scopedPackageNameRegex.test(normalizedName.split("/")[1])) {
  2068. /**
  2069. * for scoped packages, insert the prefix after the first / unless
  2070. * the path is already @scope/eslint or @scope/eslint-xxx-yyy
  2071. */
  2072. normalizedName = normalizedName.replace(/^@([^/]+)\/(.*)$/u, `@$1/${prefix}-$2`);
  2073. }
  2074. } else if (!normalizedName.startsWith(`${prefix}-`)) {
  2075. normalizedName = `${prefix}-${normalizedName}`;
  2076. }
  2077. return normalizedName;
  2078. }
  2079. /**
  2080. * Removes the prefix from a fullname.
  2081. * @param {string} fullname The term which may have the prefix.
  2082. * @param {string} prefix The prefix to remove.
  2083. * @returns {string} The term without prefix.
  2084. */
  2085. function getShorthandName(fullname, prefix) {
  2086. if (fullname[0] === "@") {
  2087. let matchResult = new RegExp(`^(@[^/]+)/${prefix}$`, "u").exec(fullname);
  2088. if (matchResult) {
  2089. return matchResult[1];
  2090. }
  2091. matchResult = new RegExp(`^(@[^/]+)/${prefix}-(.+)$`, "u").exec(fullname);
  2092. if (matchResult) {
  2093. return `${matchResult[1]}/${matchResult[2]}`;
  2094. }
  2095. } else if (fullname.startsWith(`${prefix}-`)) {
  2096. return fullname.slice(prefix.length + 1);
  2097. }
  2098. return fullname;
  2099. }
  2100. /**
  2101. * Gets the scope (namespace) of a term.
  2102. * @param {string} term The term which may have the namespace.
  2103. * @returns {string} The namespace of the term if it has one.
  2104. */
  2105. function getNamespaceFromTerm(term) {
  2106. const match = term.match(NAMESPACE_REGEX);
  2107. return match ? match[0] : "";
  2108. }
  2109. var naming = {
  2110. __proto__: null,
  2111. normalizePackageName: normalizePackageName,
  2112. getShorthandName: getShorthandName,
  2113. getNamespaceFromTerm: getNamespaceFromTerm
  2114. };
  2115. /**
  2116. * Utility for resolving a module relative to another module
  2117. * @author Teddy Katz
  2118. */
  2119. /*
  2120. * `Module.createRequire` is added in v12.2.0. It supports URL as well.
  2121. * We only support the case where the argument is a filepath, not a URL.
  2122. */
  2123. const createRequire = Module__default["default"].createRequire;
  2124. /**
  2125. * Resolves a Node module relative to another module
  2126. * @param {string} moduleName The name of a Node module, or a path to a Node module.
  2127. * @param {string} relativeToPath An absolute path indicating the module that `moduleName` should be resolved relative to. This must be
  2128. * a file rather than a directory, but the file need not actually exist.
  2129. * @returns {string} The absolute path that would result from calling `require.resolve(moduleName)` in a file located at `relativeToPath`
  2130. */
  2131. function resolve(moduleName, relativeToPath) {
  2132. try {
  2133. return createRequire(relativeToPath).resolve(moduleName);
  2134. } catch (error) {
  2135. // This `if` block is for older Node.js than 12.0.0. We can remove this block in the future.
  2136. if (
  2137. typeof error === "object" &&
  2138. error !== null &&
  2139. error.code === "MODULE_NOT_FOUND" &&
  2140. !error.requireStack &&
  2141. error.message.includes(moduleName)
  2142. ) {
  2143. error.message += `\nRequire stack:\n- ${relativeToPath}`;
  2144. }
  2145. throw error;
  2146. }
  2147. }
  2148. var ModuleResolver = {
  2149. __proto__: null,
  2150. resolve: resolve
  2151. };
  2152. /**
  2153. * @fileoverview The factory of `ConfigArray` objects.
  2154. *
  2155. * This class provides methods to create `ConfigArray` instance.
  2156. *
  2157. * - `create(configData, options)`
  2158. * Create a `ConfigArray` instance from a config data. This is to handle CLI
  2159. * options except `--config`.
  2160. * - `loadFile(filePath, options)`
  2161. * Create a `ConfigArray` instance from a config file. This is to handle
  2162. * `--config` option. If the file was not found, throws the following error:
  2163. * - If the filename was `*.js`, a `MODULE_NOT_FOUND` error.
  2164. * - If the filename was `package.json`, an IO error or an
  2165. * `ESLINT_CONFIG_FIELD_NOT_FOUND` error.
  2166. * - Otherwise, an IO error such as `ENOENT`.
  2167. * - `loadInDirectory(directoryPath, options)`
  2168. * Create a `ConfigArray` instance from a config file which is on a given
  2169. * directory. This tries to load `.eslintrc.*` or `package.json`. If not
  2170. * found, returns an empty `ConfigArray`.
  2171. * - `loadESLintIgnore(filePath)`
  2172. * Create a `ConfigArray` instance from a config file that is `.eslintignore`
  2173. * format. This is to handle `--ignore-path` option.
  2174. * - `loadDefaultESLintIgnore()`
  2175. * Create a `ConfigArray` instance from `.eslintignore` or `package.json` in
  2176. * the current working directory.
  2177. *
  2178. * `ConfigArrayFactory` class has the responsibility that loads configuration
  2179. * files, including loading `extends`, `parser`, and `plugins`. The created
  2180. * `ConfigArray` instance has the loaded `extends`, `parser`, and `plugins`.
  2181. *
  2182. * But this class doesn't handle cascading. `CascadingConfigArrayFactory` class
  2183. * handles cascading and hierarchy.
  2184. *
  2185. * @author Toru Nagashima <https://github.com/mysticatea>
  2186. */
  2187. const require$1 = Module.createRequire(require('url').pathToFileURL(__filename).toString());
  2188. const debug$2 = debugOrig__default["default"]("eslintrc:config-array-factory");
  2189. //------------------------------------------------------------------------------
  2190. // Helpers
  2191. //------------------------------------------------------------------------------
  2192. const configFilenames = [
  2193. ".eslintrc.js",
  2194. ".eslintrc.cjs",
  2195. ".eslintrc.yaml",
  2196. ".eslintrc.yml",
  2197. ".eslintrc.json",
  2198. ".eslintrc",
  2199. "package.json"
  2200. ];
  2201. // Define types for VSCode IntelliSense.
  2202. /** @typedef {import("./shared/types").ConfigData} ConfigData */
  2203. /** @typedef {import("./shared/types").OverrideConfigData} OverrideConfigData */
  2204. /** @typedef {import("./shared/types").Parser} Parser */
  2205. /** @typedef {import("./shared/types").Plugin} Plugin */
  2206. /** @typedef {import("./shared/types").Rule} Rule */
  2207. /** @typedef {import("./config-array/config-dependency").DependentParser} DependentParser */
  2208. /** @typedef {import("./config-array/config-dependency").DependentPlugin} DependentPlugin */
  2209. /** @typedef {ConfigArray[0]} ConfigArrayElement */
  2210. /**
  2211. * @typedef {Object} ConfigArrayFactoryOptions
  2212. * @property {Map<string,Plugin>} [additionalPluginPool] The map for additional plugins.
  2213. * @property {string} [cwd] The path to the current working directory.
  2214. * @property {string} [resolvePluginsRelativeTo] A path to the directory that plugins should be resolved from. Defaults to `cwd`.
  2215. * @property {Map<string,Rule>} builtInRules The rules that are built in to ESLint.
  2216. * @property {Object} [resolver=ModuleResolver] The module resolver object.
  2217. * @property {string} eslintAllPath The path to the definitions for eslint:all.
  2218. * @property {Function} getEslintAllConfig Returns the config data for eslint:all.
  2219. * @property {string} eslintRecommendedPath The path to the definitions for eslint:recommended.
  2220. * @property {Function} getEslintRecommendedConfig Returns the config data for eslint:recommended.
  2221. */
  2222. /**
  2223. * @typedef {Object} ConfigArrayFactoryInternalSlots
  2224. * @property {Map<string,Plugin>} additionalPluginPool The map for additional plugins.
  2225. * @property {string} cwd The path to the current working directory.
  2226. * @property {string | undefined} resolvePluginsRelativeTo An absolute path the the directory that plugins should be resolved from.
  2227. * @property {Map<string,Rule>} builtInRules The rules that are built in to ESLint.
  2228. * @property {Object} [resolver=ModuleResolver] The module resolver object.
  2229. * @property {string} eslintAllPath The path to the definitions for eslint:all.
  2230. * @property {Function} getEslintAllConfig Returns the config data for eslint:all.
  2231. * @property {string} eslintRecommendedPath The path to the definitions for eslint:recommended.
  2232. * @property {Function} getEslintRecommendedConfig Returns the config data for eslint:recommended.
  2233. */
  2234. /**
  2235. * @typedef {Object} ConfigArrayFactoryLoadingContext
  2236. * @property {string} filePath The path to the current configuration.
  2237. * @property {string} matchBasePath The base path to resolve relative paths in `overrides[].files`, `overrides[].excludedFiles`, and `ignorePatterns`.
  2238. * @property {string} name The name of the current configuration.
  2239. * @property {string} pluginBasePath The base path to resolve plugins.
  2240. * @property {"config" | "ignore" | "implicit-processor"} type The type of the current configuration. This is `"config"` in normal. This is `"ignore"` if it came from `.eslintignore`. This is `"implicit-processor"` if it came from legacy file-extension processors.
  2241. */
  2242. /**
  2243. * @typedef {Object} ConfigArrayFactoryLoadingContext
  2244. * @property {string} filePath The path to the current configuration.
  2245. * @property {string} matchBasePath The base path to resolve relative paths in `overrides[].files`, `overrides[].excludedFiles`, and `ignorePatterns`.
  2246. * @property {string} name The name of the current configuration.
  2247. * @property {"config" | "ignore" | "implicit-processor"} type The type of the current configuration. This is `"config"` in normal. This is `"ignore"` if it came from `.eslintignore`. This is `"implicit-processor"` if it came from legacy file-extension processors.
  2248. */
  2249. /** @type {WeakMap<ConfigArrayFactory, ConfigArrayFactoryInternalSlots>} */
  2250. const internalSlotsMap$1 = new WeakMap();
  2251. /** @type {WeakMap<object, Plugin>} */
  2252. const normalizedPlugins = new WeakMap();
  2253. /**
  2254. * Check if a given string is a file path.
  2255. * @param {string} nameOrPath A module name or file path.
  2256. * @returns {boolean} `true` if the `nameOrPath` is a file path.
  2257. */
  2258. function isFilePath(nameOrPath) {
  2259. return (
  2260. /^\.{1,2}[/\\]/u.test(nameOrPath) ||
  2261. path__default["default"].isAbsolute(nameOrPath)
  2262. );
  2263. }
  2264. /**
  2265. * Convenience wrapper for synchronously reading file contents.
  2266. * @param {string} filePath The filename to read.
  2267. * @returns {string} The file contents, with the BOM removed.
  2268. * @private
  2269. */
  2270. function readFile(filePath) {
  2271. return fs__default["default"].readFileSync(filePath, "utf8").replace(/^\ufeff/u, "");
  2272. }
  2273. /**
  2274. * Loads a YAML configuration from a file.
  2275. * @param {string} filePath The filename to load.
  2276. * @returns {ConfigData} The configuration object from the file.
  2277. * @throws {Error} If the file cannot be read.
  2278. * @private
  2279. */
  2280. function loadYAMLConfigFile(filePath) {
  2281. debug$2(`Loading YAML config file: ${filePath}`);
  2282. // lazy load YAML to improve performance when not used
  2283. const yaml = require$1("js-yaml");
  2284. try {
  2285. // empty YAML file can be null, so always use
  2286. return yaml.load(readFile(filePath)) || {};
  2287. } catch (e) {
  2288. debug$2(`Error reading YAML file: ${filePath}`);
  2289. e.message = `Cannot read config file: ${filePath}\nError: ${e.message}`;
  2290. throw e;
  2291. }
  2292. }
  2293. /**
  2294. * Loads a JSON configuration from a file.
  2295. * @param {string} filePath The filename to load.
  2296. * @returns {ConfigData} The configuration object from the file.
  2297. * @throws {Error} If the file cannot be read.
  2298. * @private
  2299. */
  2300. function loadJSONConfigFile(filePath) {
  2301. debug$2(`Loading JSON config file: ${filePath}`);
  2302. try {
  2303. return JSON.parse(stripComments__default["default"](readFile(filePath)));
  2304. } catch (e) {
  2305. debug$2(`Error reading JSON file: ${filePath}`);
  2306. e.message = `Cannot read config file: ${filePath}\nError: ${e.message}`;
  2307. e.messageTemplate = "failed-to-read-json";
  2308. e.messageData = {
  2309. path: filePath,
  2310. message: e.message
  2311. };
  2312. throw e;
  2313. }
  2314. }
  2315. /**
  2316. * Loads a legacy (.eslintrc) configuration from a file.
  2317. * @param {string} filePath The filename to load.
  2318. * @returns {ConfigData} The configuration object from the file.
  2319. * @throws {Error} If the file cannot be read.
  2320. * @private
  2321. */
  2322. function loadLegacyConfigFile(filePath) {
  2323. debug$2(`Loading legacy config file: ${filePath}`);
  2324. // lazy load YAML to improve performance when not used
  2325. const yaml = require$1("js-yaml");
  2326. try {
  2327. return yaml.load(stripComments__default["default"](readFile(filePath))) || /* istanbul ignore next */ {};
  2328. } catch (e) {
  2329. debug$2("Error reading YAML file: %s\n%o", filePath, e);
  2330. e.message = `Cannot read config file: ${filePath}\nError: ${e.message}`;
  2331. throw e;
  2332. }
  2333. }
  2334. /**
  2335. * Loads a JavaScript configuration from a file.
  2336. * @param {string} filePath The filename to load.
  2337. * @returns {ConfigData} The configuration object from the file.
  2338. * @throws {Error} If the file cannot be read.
  2339. * @private
  2340. */
  2341. function loadJSConfigFile(filePath) {
  2342. debug$2(`Loading JS config file: ${filePath}`);
  2343. try {
  2344. return importFresh__default["default"](filePath);
  2345. } catch (e) {
  2346. debug$2(`Error reading JavaScript file: ${filePath}`);
  2347. e.message = `Cannot read config file: ${filePath}\nError: ${e.message}`;
  2348. throw e;
  2349. }
  2350. }
  2351. /**
  2352. * Loads a configuration from a package.json file.
  2353. * @param {string} filePath The filename to load.
  2354. * @returns {ConfigData} The configuration object from the file.
  2355. * @throws {Error} If the file cannot be read.
  2356. * @private
  2357. */
  2358. function loadPackageJSONConfigFile(filePath) {
  2359. debug$2(`Loading package.json config file: ${filePath}`);
  2360. try {
  2361. const packageData = loadJSONConfigFile(filePath);
  2362. if (!Object.hasOwnProperty.call(packageData, "eslintConfig")) {
  2363. throw Object.assign(
  2364. new Error("package.json file doesn't have 'eslintConfig' field."),
  2365. { code: "ESLINT_CONFIG_FIELD_NOT_FOUND" }
  2366. );
  2367. }
  2368. return packageData.eslintConfig;
  2369. } catch (e) {
  2370. debug$2(`Error reading package.json file: ${filePath}`);
  2371. e.message = `Cannot read config file: ${filePath}\nError: ${e.message}`;
  2372. throw e;
  2373. }
  2374. }
  2375. /**
  2376. * Loads a `.eslintignore` from a file.
  2377. * @param {string} filePath The filename to load.
  2378. * @returns {string[]} The ignore patterns from the file.
  2379. * @private
  2380. */
  2381. function loadESLintIgnoreFile(filePath) {
  2382. debug$2(`Loading .eslintignore file: ${filePath}`);
  2383. try {
  2384. return readFile(filePath)
  2385. .split(/\r?\n/gu)
  2386. .filter(line => line.trim() !== "" && !line.startsWith("#"));
  2387. } catch (e) {
  2388. debug$2(`Error reading .eslintignore file: ${filePath}`);
  2389. e.message = `Cannot read .eslintignore file: ${filePath}\nError: ${e.message}`;
  2390. throw e;
  2391. }
  2392. }
  2393. /**
  2394. * Creates an error to notify about a missing config to extend from.
  2395. * @param {string} configName The name of the missing config.
  2396. * @param {string} importerName The name of the config that imported the missing config
  2397. * @param {string} messageTemplate The text template to source error strings from.
  2398. * @returns {Error} The error object to throw
  2399. * @private
  2400. */
  2401. function configInvalidError(configName, importerName, messageTemplate) {
  2402. return Object.assign(
  2403. new Error(`Failed to load config "${configName}" to extend from.`),
  2404. {
  2405. messageTemplate,
  2406. messageData: { configName, importerName }
  2407. }
  2408. );
  2409. }
  2410. /**
  2411. * Loads a configuration file regardless of the source. Inspects the file path
  2412. * to determine the correctly way to load the config file.
  2413. * @param {string} filePath The path to the configuration.
  2414. * @returns {ConfigData|null} The configuration information.
  2415. * @private
  2416. */
  2417. function loadConfigFile(filePath) {
  2418. switch (path__default["default"].extname(filePath)) {
  2419. case ".js":
  2420. case ".cjs":
  2421. return loadJSConfigFile(filePath);
  2422. case ".json":
  2423. if (path__default["default"].basename(filePath) === "package.json") {
  2424. return loadPackageJSONConfigFile(filePath);
  2425. }
  2426. return loadJSONConfigFile(filePath);
  2427. case ".yaml":
  2428. case ".yml":
  2429. return loadYAMLConfigFile(filePath);
  2430. default:
  2431. return loadLegacyConfigFile(filePath);
  2432. }
  2433. }
  2434. /**
  2435. * Write debug log.
  2436. * @param {string} request The requested module name.
  2437. * @param {string} relativeTo The file path to resolve the request relative to.
  2438. * @param {string} filePath The resolved file path.
  2439. * @returns {void}
  2440. */
  2441. function writeDebugLogForLoading(request, relativeTo, filePath) {
  2442. /* istanbul ignore next */
  2443. if (debug$2.enabled) {
  2444. let nameAndVersion = null;
  2445. try {
  2446. const packageJsonPath = resolve(
  2447. `${request}/package.json`,
  2448. relativeTo
  2449. );
  2450. const { version = "unknown" } = require$1(packageJsonPath);
  2451. nameAndVersion = `${request}@${version}`;
  2452. } catch (error) {
  2453. debug$2("package.json was not found:", error.message);
  2454. nameAndVersion = request;
  2455. }
  2456. debug$2("Loaded: %s (%s)", nameAndVersion, filePath);
  2457. }
  2458. }
  2459. /**
  2460. * Create a new context with default values.
  2461. * @param {ConfigArrayFactoryInternalSlots} slots The internal slots.
  2462. * @param {"config" | "ignore" | "implicit-processor" | undefined} providedType The type of the current configuration. Default is `"config"`.
  2463. * @param {string | undefined} providedName The name of the current configuration. Default is the relative path from `cwd` to `filePath`.
  2464. * @param {string | undefined} providedFilePath The path to the current configuration. Default is empty string.
  2465. * @param {string | undefined} providedMatchBasePath The type of the current configuration. Default is the directory of `filePath` or `cwd`.
  2466. * @returns {ConfigArrayFactoryLoadingContext} The created context.
  2467. */
  2468. function createContext(
  2469. { cwd, resolvePluginsRelativeTo },
  2470. providedType,
  2471. providedName,
  2472. providedFilePath,
  2473. providedMatchBasePath
  2474. ) {
  2475. const filePath = providedFilePath
  2476. ? path__default["default"].resolve(cwd, providedFilePath)
  2477. : "";
  2478. const matchBasePath =
  2479. (providedMatchBasePath && path__default["default"].resolve(cwd, providedMatchBasePath)) ||
  2480. (filePath && path__default["default"].dirname(filePath)) ||
  2481. cwd;
  2482. const name =
  2483. providedName ||
  2484. (filePath && path__default["default"].relative(cwd, filePath)) ||
  2485. "";
  2486. const pluginBasePath =
  2487. resolvePluginsRelativeTo ||
  2488. (filePath && path__default["default"].dirname(filePath)) ||
  2489. cwd;
  2490. const type = providedType || "config";
  2491. return { filePath, matchBasePath, name, pluginBasePath, type };
  2492. }
  2493. /**
  2494. * Normalize a given plugin.
  2495. * - Ensure the object to have four properties: configs, environments, processors, and rules.
  2496. * - Ensure the object to not have other properties.
  2497. * @param {Plugin} plugin The plugin to normalize.
  2498. * @returns {Plugin} The normalized plugin.
  2499. */
  2500. function normalizePlugin(plugin) {
  2501. // first check the cache
  2502. let normalizedPlugin = normalizedPlugins.get(plugin);
  2503. if (normalizedPlugin) {
  2504. return normalizedPlugin;
  2505. }
  2506. normalizedPlugin = {
  2507. configs: plugin.configs || {},
  2508. environments: plugin.environments || {},
  2509. processors: plugin.processors || {},
  2510. rules: plugin.rules || {}
  2511. };
  2512. // save the reference for later
  2513. normalizedPlugins.set(plugin, normalizedPlugin);
  2514. return normalizedPlugin;
  2515. }
  2516. //------------------------------------------------------------------------------
  2517. // Public Interface
  2518. //------------------------------------------------------------------------------
  2519. /**
  2520. * The factory of `ConfigArray` objects.
  2521. */
  2522. class ConfigArrayFactory {
  2523. /**
  2524. * Initialize this instance.
  2525. * @param {ConfigArrayFactoryOptions} [options] The map for additional plugins.
  2526. */
  2527. constructor({
  2528. additionalPluginPool = new Map(),
  2529. cwd = process.cwd(),
  2530. resolvePluginsRelativeTo,
  2531. builtInRules,
  2532. resolver = ModuleResolver,
  2533. eslintAllPath,
  2534. getEslintAllConfig,
  2535. eslintRecommendedPath,
  2536. getEslintRecommendedConfig
  2537. } = {}) {
  2538. internalSlotsMap$1.set(this, {
  2539. additionalPluginPool,
  2540. cwd,
  2541. resolvePluginsRelativeTo:
  2542. resolvePluginsRelativeTo &&
  2543. path__default["default"].resolve(cwd, resolvePluginsRelativeTo),
  2544. builtInRules,
  2545. resolver,
  2546. eslintAllPath,
  2547. getEslintAllConfig,
  2548. eslintRecommendedPath,
  2549. getEslintRecommendedConfig
  2550. });
  2551. }
  2552. /**
  2553. * Create `ConfigArray` instance from a config data.
  2554. * @param {ConfigData|null} configData The config data to create.
  2555. * @param {Object} [options] The options.
  2556. * @param {string} [options.basePath] The base path to resolve relative paths in `overrides[].files`, `overrides[].excludedFiles`, and `ignorePatterns`.
  2557. * @param {string} [options.filePath] The path to this config data.
  2558. * @param {string} [options.name] The config name.
  2559. * @returns {ConfigArray} Loaded config.
  2560. */
  2561. create(configData, { basePath, filePath, name } = {}) {
  2562. if (!configData) {
  2563. return new ConfigArray();
  2564. }
  2565. const slots = internalSlotsMap$1.get(this);
  2566. const ctx = createContext(slots, "config", name, filePath, basePath);
  2567. const elements = this._normalizeConfigData(configData, ctx);
  2568. return new ConfigArray(...elements);
  2569. }
  2570. /**
  2571. * Load a config file.
  2572. * @param {string} filePath The path to a config file.
  2573. * @param {Object} [options] The options.
  2574. * @param {string} [options.basePath] The base path to resolve relative paths in `overrides[].files`, `overrides[].excludedFiles`, and `ignorePatterns`.
  2575. * @param {string} [options.name] The config name.
  2576. * @returns {ConfigArray} Loaded config.
  2577. */
  2578. loadFile(filePath, { basePath, name } = {}) {
  2579. const slots = internalSlotsMap$1.get(this);
  2580. const ctx = createContext(slots, "config", name, filePath, basePath);
  2581. return new ConfigArray(...this._loadConfigData(ctx));
  2582. }
  2583. /**
  2584. * Load the config file on a given directory if exists.
  2585. * @param {string} directoryPath The path to a directory.
  2586. * @param {Object} [options] The options.
  2587. * @param {string} [options.basePath] The base path to resolve relative paths in `overrides[].files`, `overrides[].excludedFiles`, and `ignorePatterns`.
  2588. * @param {string} [options.name] The config name.
  2589. * @returns {ConfigArray} Loaded config. An empty `ConfigArray` if any config doesn't exist.
  2590. */
  2591. loadInDirectory(directoryPath, { basePath, name } = {}) {
  2592. const slots = internalSlotsMap$1.get(this);
  2593. for (const filename of configFilenames) {
  2594. const ctx = createContext(
  2595. slots,
  2596. "config",
  2597. name,
  2598. path__default["default"].join(directoryPath, filename),
  2599. basePath
  2600. );
  2601. if (fs__default["default"].existsSync(ctx.filePath) && fs__default["default"].statSync(ctx.filePath).isFile()) {
  2602. let configData;
  2603. try {
  2604. configData = loadConfigFile(ctx.filePath);
  2605. } catch (error) {
  2606. if (!error || error.code !== "ESLINT_CONFIG_FIELD_NOT_FOUND") {
  2607. throw error;
  2608. }
  2609. }
  2610. if (configData) {
  2611. debug$2(`Config file found: ${ctx.filePath}`);
  2612. return new ConfigArray(
  2613. ...this._normalizeConfigData(configData, ctx)
  2614. );
  2615. }
  2616. }
  2617. }
  2618. debug$2(`Config file not found on ${directoryPath}`);
  2619. return new ConfigArray();
  2620. }
  2621. /**
  2622. * Check if a config file on a given directory exists or not.
  2623. * @param {string} directoryPath The path to a directory.
  2624. * @returns {string | null} The path to the found config file. If not found then null.
  2625. */
  2626. static getPathToConfigFileInDirectory(directoryPath) {
  2627. for (const filename of configFilenames) {
  2628. const filePath = path__default["default"].join(directoryPath, filename);
  2629. if (fs__default["default"].existsSync(filePath)) {
  2630. if (filename === "package.json") {
  2631. try {
  2632. loadPackageJSONConfigFile(filePath);
  2633. return filePath;
  2634. } catch { /* ignore */ }
  2635. } else {
  2636. return filePath;
  2637. }
  2638. }
  2639. }
  2640. return null;
  2641. }
  2642. /**
  2643. * Load `.eslintignore` file.
  2644. * @param {string} filePath The path to a `.eslintignore` file to load.
  2645. * @returns {ConfigArray} Loaded config. An empty `ConfigArray` if any config doesn't exist.
  2646. */
  2647. loadESLintIgnore(filePath) {
  2648. const slots = internalSlotsMap$1.get(this);
  2649. const ctx = createContext(
  2650. slots,
  2651. "ignore",
  2652. void 0,
  2653. filePath,
  2654. slots.cwd
  2655. );
  2656. const ignorePatterns = loadESLintIgnoreFile(ctx.filePath);
  2657. return new ConfigArray(
  2658. ...this._normalizeESLintIgnoreData(ignorePatterns, ctx)
  2659. );
  2660. }
  2661. /**
  2662. * Load `.eslintignore` file in the current working directory.
  2663. * @returns {ConfigArray} Loaded config. An empty `ConfigArray` if any config doesn't exist.
  2664. */
  2665. loadDefaultESLintIgnore() {
  2666. const slots = internalSlotsMap$1.get(this);
  2667. const eslintIgnorePath = path__default["default"].resolve(slots.cwd, ".eslintignore");
  2668. const packageJsonPath = path__default["default"].resolve(slots.cwd, "package.json");
  2669. if (fs__default["default"].existsSync(eslintIgnorePath)) {
  2670. return this.loadESLintIgnore(eslintIgnorePath);
  2671. }
  2672. if (fs__default["default"].existsSync(packageJsonPath)) {
  2673. const data = loadJSONConfigFile(packageJsonPath);
  2674. if (Object.hasOwnProperty.call(data, "eslintIgnore")) {
  2675. if (!Array.isArray(data.eslintIgnore)) {
  2676. throw new Error("Package.json eslintIgnore property requires an array of paths");
  2677. }
  2678. const ctx = createContext(
  2679. slots,
  2680. "ignore",
  2681. "eslintIgnore in package.json",
  2682. packageJsonPath,
  2683. slots.cwd
  2684. );
  2685. return new ConfigArray(
  2686. ...this._normalizeESLintIgnoreData(data.eslintIgnore, ctx)
  2687. );
  2688. }
  2689. }
  2690. return new ConfigArray();
  2691. }
  2692. /**
  2693. * Load a given config file.
  2694. * @param {ConfigArrayFactoryLoadingContext} ctx The loading context.
  2695. * @returns {IterableIterator<ConfigArrayElement>} Loaded config.
  2696. * @private
  2697. */
  2698. _loadConfigData(ctx) {
  2699. return this._normalizeConfigData(loadConfigFile(ctx.filePath), ctx);
  2700. }
  2701. /**
  2702. * Normalize a given `.eslintignore` data to config array elements.
  2703. * @param {string[]} ignorePatterns The patterns to ignore files.
  2704. * @param {ConfigArrayFactoryLoadingContext} ctx The loading context.
  2705. * @returns {IterableIterator<ConfigArrayElement>} The normalized config.
  2706. * @private
  2707. */
  2708. *_normalizeESLintIgnoreData(ignorePatterns, ctx) {
  2709. const elements = this._normalizeObjectConfigData(
  2710. { ignorePatterns },
  2711. ctx
  2712. );
  2713. // Set `ignorePattern.loose` flag for backward compatibility.
  2714. for (const element of elements) {
  2715. if (element.ignorePattern) {
  2716. element.ignorePattern.loose = true;
  2717. }
  2718. yield element;
  2719. }
  2720. }
  2721. /**
  2722. * Normalize a given config to an array.
  2723. * @param {ConfigData} configData The config data to normalize.
  2724. * @param {ConfigArrayFactoryLoadingContext} ctx The loading context.
  2725. * @returns {IterableIterator<ConfigArrayElement>} The normalized config.
  2726. * @private
  2727. */
  2728. _normalizeConfigData(configData, ctx) {
  2729. const validator = new ConfigValidator();
  2730. validator.validateConfigSchema(configData, ctx.name || ctx.filePath);
  2731. return this._normalizeObjectConfigData(configData, ctx);
  2732. }
  2733. /**
  2734. * Normalize a given config to an array.
  2735. * @param {ConfigData|OverrideConfigData} configData The config data to normalize.
  2736. * @param {ConfigArrayFactoryLoadingContext} ctx The loading context.
  2737. * @returns {IterableIterator<ConfigArrayElement>} The normalized config.
  2738. * @private
  2739. */
  2740. *_normalizeObjectConfigData(configData, ctx) {
  2741. const { files, excludedFiles, ...configBody } = configData;
  2742. const criteria = OverrideTester.create(
  2743. files,
  2744. excludedFiles,
  2745. ctx.matchBasePath
  2746. );
  2747. const elements = this._normalizeObjectConfigDataBody(configBody, ctx);
  2748. // Apply the criteria to every element.
  2749. for (const element of elements) {
  2750. /*
  2751. * Merge the criteria.
  2752. * This is for the `overrides` entries that came from the
  2753. * configurations of `overrides[].extends`.
  2754. */
  2755. element.criteria = OverrideTester.and(criteria, element.criteria);
  2756. /*
  2757. * Remove `root` property to ignore `root` settings which came from
  2758. * `extends` in `overrides`.
  2759. */
  2760. if (element.criteria) {
  2761. element.root = void 0;
  2762. }
  2763. yield element;
  2764. }
  2765. }
  2766. /**
  2767. * Normalize a given config to an array.
  2768. * @param {ConfigData} configData The config data to normalize.
  2769. * @param {ConfigArrayFactoryLoadingContext} ctx The loading context.
  2770. * @returns {IterableIterator<ConfigArrayElement>} The normalized config.
  2771. * @private
  2772. */
  2773. *_normalizeObjectConfigDataBody(
  2774. {
  2775. env,
  2776. extends: extend,
  2777. globals,
  2778. ignorePatterns,
  2779. noInlineConfig,
  2780. parser: parserName,
  2781. parserOptions,
  2782. plugins: pluginList,
  2783. processor,
  2784. reportUnusedDisableDirectives,
  2785. root,
  2786. rules,
  2787. settings,
  2788. overrides: overrideList = []
  2789. },
  2790. ctx
  2791. ) {
  2792. const extendList = Array.isArray(extend) ? extend : [extend];
  2793. const ignorePattern = ignorePatterns && new IgnorePattern(
  2794. Array.isArray(ignorePatterns) ? ignorePatterns : [ignorePatterns],
  2795. ctx.matchBasePath
  2796. );
  2797. // Flatten `extends`.
  2798. for (const extendName of extendList.filter(Boolean)) {
  2799. yield* this._loadExtends(extendName, ctx);
  2800. }
  2801. // Load parser & plugins.
  2802. const parser = parserName && this._loadParser(parserName, ctx);
  2803. const plugins = pluginList && this._loadPlugins(pluginList, ctx);
  2804. // Yield pseudo config data for file extension processors.
  2805. if (plugins) {
  2806. yield* this._takeFileExtensionProcessors(plugins, ctx);
  2807. }
  2808. // Yield the config data except `extends` and `overrides`.
  2809. yield {
  2810. // Debug information.
  2811. type: ctx.type,
  2812. name: ctx.name,
  2813. filePath: ctx.filePath,
  2814. // Config data.
  2815. criteria: null,
  2816. env,
  2817. globals,
  2818. ignorePattern,
  2819. noInlineConfig,
  2820. parser,
  2821. parserOptions,
  2822. plugins,
  2823. processor,
  2824. reportUnusedDisableDirectives,
  2825. root,
  2826. rules,
  2827. settings
  2828. };
  2829. // Flatten `overries`.
  2830. for (let i = 0; i < overrideList.length; ++i) {
  2831. yield* this._normalizeObjectConfigData(
  2832. overrideList[i],
  2833. { ...ctx, name: `${ctx.name}#overrides[${i}]` }
  2834. );
  2835. }
  2836. }
  2837. /**
  2838. * Load configs of an element in `extends`.
  2839. * @param {string} extendName The name of a base config.
  2840. * @param {ConfigArrayFactoryLoadingContext} ctx The loading context.
  2841. * @returns {IterableIterator<ConfigArrayElement>} The normalized config.
  2842. * @private
  2843. */
  2844. _loadExtends(extendName, ctx) {
  2845. debug$2("Loading {extends:%j} relative to %s", extendName, ctx.filePath);
  2846. try {
  2847. if (extendName.startsWith("eslint:")) {
  2848. return this._loadExtendedBuiltInConfig(extendName, ctx);
  2849. }
  2850. if (extendName.startsWith("plugin:")) {
  2851. return this._loadExtendedPluginConfig(extendName, ctx);
  2852. }
  2853. return this._loadExtendedShareableConfig(extendName, ctx);
  2854. } catch (error) {
  2855. error.message += `\nReferenced from: ${ctx.filePath || ctx.name}`;
  2856. throw error;
  2857. }
  2858. }
  2859. /**
  2860. * Load configs of an element in `extends`.
  2861. * @param {string} extendName The name of a base config.
  2862. * @param {ConfigArrayFactoryLoadingContext} ctx The loading context.
  2863. * @returns {IterableIterator<ConfigArrayElement>} The normalized config.
  2864. * @private
  2865. */
  2866. _loadExtendedBuiltInConfig(extendName, ctx) {
  2867. const {
  2868. eslintAllPath,
  2869. getEslintAllConfig,
  2870. eslintRecommendedPath,
  2871. getEslintRecommendedConfig
  2872. } = internalSlotsMap$1.get(this);
  2873. if (extendName === "eslint:recommended") {
  2874. const name = `${ctx.name} » ${extendName}`;
  2875. if (getEslintRecommendedConfig) {
  2876. if (typeof getEslintRecommendedConfig !== "function") {
  2877. throw new Error(`getEslintRecommendedConfig must be a function instead of '${getEslintRecommendedConfig}'`);
  2878. }
  2879. return this._normalizeConfigData(getEslintRecommendedConfig(), { ...ctx, name, filePath: "" });
  2880. }
  2881. return this._loadConfigData({
  2882. ...ctx,
  2883. name,
  2884. filePath: eslintRecommendedPath
  2885. });
  2886. }
  2887. if (extendName === "eslint:all") {
  2888. const name = `${ctx.name} » ${extendName}`;
  2889. if (getEslintAllConfig) {
  2890. if (typeof getEslintAllConfig !== "function") {
  2891. throw new Error(`getEslintAllConfig must be a function instead of '${getEslintAllConfig}'`);
  2892. }
  2893. return this._normalizeConfigData(getEslintAllConfig(), { ...ctx, name, filePath: "" });
  2894. }
  2895. return this._loadConfigData({
  2896. ...ctx,
  2897. name,
  2898. filePath: eslintAllPath
  2899. });
  2900. }
  2901. throw configInvalidError(extendName, ctx.name, "extend-config-missing");
  2902. }
  2903. /**
  2904. * Load configs of an element in `extends`.
  2905. * @param {string} extendName The name of a base config.
  2906. * @param {ConfigArrayFactoryLoadingContext} ctx The loading context.
  2907. * @returns {IterableIterator<ConfigArrayElement>} The normalized config.
  2908. * @private
  2909. */
  2910. _loadExtendedPluginConfig(extendName, ctx) {
  2911. const slashIndex = extendName.lastIndexOf("/");
  2912. if (slashIndex === -1) {
  2913. throw configInvalidError(extendName, ctx.filePath, "plugin-invalid");
  2914. }
  2915. const pluginName = extendName.slice("plugin:".length, slashIndex);
  2916. const configName = extendName.slice(slashIndex + 1);
  2917. if (isFilePath(pluginName)) {
  2918. throw new Error("'extends' cannot use a file path for plugins.");
  2919. }
  2920. const plugin = this._loadPlugin(pluginName, ctx);
  2921. const configData =
  2922. plugin.definition &&
  2923. plugin.definition.configs[configName];
  2924. if (configData) {
  2925. return this._normalizeConfigData(configData, {
  2926. ...ctx,
  2927. filePath: plugin.filePath || ctx.filePath,
  2928. name: `${ctx.name} » plugin:${plugin.id}/${configName}`
  2929. });
  2930. }
  2931. throw plugin.error || configInvalidError(extendName, ctx.filePath, "extend-config-missing");
  2932. }
  2933. /**
  2934. * Load configs of an element in `extends`.
  2935. * @param {string} extendName The name of a base config.
  2936. * @param {ConfigArrayFactoryLoadingContext} ctx The loading context.
  2937. * @returns {IterableIterator<ConfigArrayElement>} The normalized config.
  2938. * @private
  2939. */
  2940. _loadExtendedShareableConfig(extendName, ctx) {
  2941. const { cwd, resolver } = internalSlotsMap$1.get(this);
  2942. const relativeTo = ctx.filePath || path__default["default"].join(cwd, "__placeholder__.js");
  2943. let request;
  2944. if (isFilePath(extendName)) {
  2945. request = extendName;
  2946. } else if (extendName.startsWith(".")) {
  2947. request = `./${extendName}`; // For backward compatibility. A ton of tests depended on this behavior.
  2948. } else {
  2949. request = normalizePackageName(
  2950. extendName,
  2951. "eslint-config"
  2952. );
  2953. }
  2954. let filePath;
  2955. try {
  2956. filePath = resolver.resolve(request, relativeTo);
  2957. } catch (error) {
  2958. /* istanbul ignore else */
  2959. if (error && error.code === "MODULE_NOT_FOUND") {
  2960. throw configInvalidError(extendName, ctx.filePath, "extend-config-missing");
  2961. }
  2962. throw error;
  2963. }
  2964. writeDebugLogForLoading(request, relativeTo, filePath);
  2965. return this._loadConfigData({
  2966. ...ctx,
  2967. filePath,
  2968. name: `${ctx.name} » ${request}`
  2969. });
  2970. }
  2971. /**
  2972. * Load given plugins.
  2973. * @param {string[]} names The plugin names to load.
  2974. * @param {ConfigArrayFactoryLoadingContext} ctx The loading context.
  2975. * @returns {Record<string,DependentPlugin>} The loaded parser.
  2976. * @private
  2977. */
  2978. _loadPlugins(names, ctx) {
  2979. return names.reduce((map, name) => {
  2980. if (isFilePath(name)) {
  2981. throw new Error("Plugins array cannot includes file paths.");
  2982. }
  2983. const plugin = this._loadPlugin(name, ctx);
  2984. map[plugin.id] = plugin;
  2985. return map;
  2986. }, {});
  2987. }
  2988. /**
  2989. * Load a given parser.
  2990. * @param {string} nameOrPath The package name or the path to a parser file.
  2991. * @param {ConfigArrayFactoryLoadingContext} ctx The loading context.
  2992. * @returns {DependentParser} The loaded parser.
  2993. */
  2994. _loadParser(nameOrPath, ctx) {
  2995. debug$2("Loading parser %j from %s", nameOrPath, ctx.filePath);
  2996. const { cwd, resolver } = internalSlotsMap$1.get(this);
  2997. const relativeTo = ctx.filePath || path__default["default"].join(cwd, "__placeholder__.js");
  2998. try {
  2999. const filePath = resolver.resolve(nameOrPath, relativeTo);
  3000. writeDebugLogForLoading(nameOrPath, relativeTo, filePath);
  3001. return new ConfigDependency({
  3002. definition: require$1(filePath),
  3003. filePath,
  3004. id: nameOrPath,
  3005. importerName: ctx.name,
  3006. importerPath: ctx.filePath
  3007. });
  3008. } catch (error) {
  3009. // If the parser name is "espree", load the espree of ESLint.
  3010. if (nameOrPath === "espree") {
  3011. debug$2("Fallback espree.");
  3012. return new ConfigDependency({
  3013. definition: require$1("espree"),
  3014. filePath: require$1.resolve("espree"),
  3015. id: nameOrPath,
  3016. importerName: ctx.name,
  3017. importerPath: ctx.filePath
  3018. });
  3019. }
  3020. debug$2("Failed to load parser '%s' declared in '%s'.", nameOrPath, ctx.name);
  3021. error.message = `Failed to load parser '${nameOrPath}' declared in '${ctx.name}': ${error.message}`;
  3022. return new ConfigDependency({
  3023. error,
  3024. id: nameOrPath,
  3025. importerName: ctx.name,
  3026. importerPath: ctx.filePath
  3027. });
  3028. }
  3029. }
  3030. /**
  3031. * Load a given plugin.
  3032. * @param {string} name The plugin name to load.
  3033. * @param {ConfigArrayFactoryLoadingContext} ctx The loading context.
  3034. * @returns {DependentPlugin} The loaded plugin.
  3035. * @private
  3036. */
  3037. _loadPlugin(name, ctx) {
  3038. debug$2("Loading plugin %j from %s", name, ctx.filePath);
  3039. const { additionalPluginPool, resolver } = internalSlotsMap$1.get(this);
  3040. const request = normalizePackageName(name, "eslint-plugin");
  3041. const id = getShorthandName(request, "eslint-plugin");
  3042. const relativeTo = path__default["default"].join(ctx.pluginBasePath, "__placeholder__.js");
  3043. if (name.match(/\s+/u)) {
  3044. const error = Object.assign(
  3045. new Error(`Whitespace found in plugin name '${name}'`),
  3046. {
  3047. messageTemplate: "whitespace-found",
  3048. messageData: { pluginName: request }
  3049. }
  3050. );
  3051. return new ConfigDependency({
  3052. error,
  3053. id,
  3054. importerName: ctx.name,
  3055. importerPath: ctx.filePath
  3056. });
  3057. }
  3058. // Check for additional pool.
  3059. const plugin =
  3060. additionalPluginPool.get(request) ||
  3061. additionalPluginPool.get(id);
  3062. if (plugin) {
  3063. return new ConfigDependency({
  3064. definition: normalizePlugin(plugin),
  3065. original: plugin,
  3066. filePath: "", // It's unknown where the plugin came from.
  3067. id,
  3068. importerName: ctx.name,
  3069. importerPath: ctx.filePath
  3070. });
  3071. }
  3072. let filePath;
  3073. let error;
  3074. try {
  3075. filePath = resolver.resolve(request, relativeTo);
  3076. } catch (resolveError) {
  3077. error = resolveError;
  3078. /* istanbul ignore else */
  3079. if (error && error.code === "MODULE_NOT_FOUND") {
  3080. error.messageTemplate = "plugin-missing";
  3081. error.messageData = {
  3082. pluginName: request,
  3083. resolvePluginsRelativeTo: ctx.pluginBasePath,
  3084. importerName: ctx.name
  3085. };
  3086. }
  3087. }
  3088. if (filePath) {
  3089. try {
  3090. writeDebugLogForLoading(request, relativeTo, filePath);
  3091. const startTime = Date.now();
  3092. const pluginDefinition = require$1(filePath);
  3093. debug$2(`Plugin ${filePath} loaded in: ${Date.now() - startTime}ms`);
  3094. return new ConfigDependency({
  3095. definition: normalizePlugin(pluginDefinition),
  3096. original: pluginDefinition,
  3097. filePath,
  3098. id,
  3099. importerName: ctx.name,
  3100. importerPath: ctx.filePath
  3101. });
  3102. } catch (loadError) {
  3103. error = loadError;
  3104. }
  3105. }
  3106. debug$2("Failed to load plugin '%s' declared in '%s'.", name, ctx.name);
  3107. error.message = `Failed to load plugin '${name}' declared in '${ctx.name}': ${error.message}`;
  3108. return new ConfigDependency({
  3109. error,
  3110. id,
  3111. importerName: ctx.name,
  3112. importerPath: ctx.filePath
  3113. });
  3114. }
  3115. /**
  3116. * Take file expression processors as config array elements.
  3117. * @param {Record<string,DependentPlugin>} plugins The plugin definitions.
  3118. * @param {ConfigArrayFactoryLoadingContext} ctx The loading context.
  3119. * @returns {IterableIterator<ConfigArrayElement>} The config array elements of file expression processors.
  3120. * @private
  3121. */
  3122. *_takeFileExtensionProcessors(plugins, ctx) {
  3123. for (const pluginId of Object.keys(plugins)) {
  3124. const processors =
  3125. plugins[pluginId] &&
  3126. plugins[pluginId].definition &&
  3127. plugins[pluginId].definition.processors;
  3128. if (!processors) {
  3129. continue;
  3130. }
  3131. for (const processorId of Object.keys(processors)) {
  3132. if (processorId.startsWith(".")) {
  3133. yield* this._normalizeObjectConfigData(
  3134. {
  3135. files: [`*${processorId}`],
  3136. processor: `${pluginId}/${processorId}`
  3137. },
  3138. {
  3139. ...ctx,
  3140. type: "implicit-processor",
  3141. name: `${ctx.name}#processors["${pluginId}/${processorId}"]`
  3142. }
  3143. );
  3144. }
  3145. }
  3146. }
  3147. }
  3148. }
  3149. /**
  3150. * @fileoverview `CascadingConfigArrayFactory` class.
  3151. *
  3152. * `CascadingConfigArrayFactory` class has a responsibility:
  3153. *
  3154. * 1. Handles cascading of config files.
  3155. *
  3156. * It provides two methods:
  3157. *
  3158. * - `getConfigArrayForFile(filePath)`
  3159. * Get the corresponded configuration of a given file. This method doesn't
  3160. * throw even if the given file didn't exist.
  3161. * - `clearCache()`
  3162. * Clear the internal cache. You have to call this method when
  3163. * `additionalPluginPool` was updated if `baseConfig` or `cliConfig` depends
  3164. * on the additional plugins. (`CLIEngine#addPlugin()` method calls this.)
  3165. *
  3166. * @author Toru Nagashima <https://github.com/mysticatea>
  3167. */
  3168. const debug$1 = debugOrig__default["default"]("eslintrc:cascading-config-array-factory");
  3169. //------------------------------------------------------------------------------
  3170. // Helpers
  3171. //------------------------------------------------------------------------------
  3172. // Define types for VSCode IntelliSense.
  3173. /** @typedef {import("./shared/types").ConfigData} ConfigData */
  3174. /** @typedef {import("./shared/types").Parser} Parser */
  3175. /** @typedef {import("./shared/types").Plugin} Plugin */
  3176. /** @typedef {import("./shared/types").Rule} Rule */
  3177. /** @typedef {ReturnType<ConfigArrayFactory["create"]>} ConfigArray */
  3178. /**
  3179. * @typedef {Object} CascadingConfigArrayFactoryOptions
  3180. * @property {Map<string,Plugin>} [additionalPluginPool] The map for additional plugins.
  3181. * @property {ConfigData} [baseConfig] The config by `baseConfig` option.
  3182. * @property {ConfigData} [cliConfig] The config by CLI options (`--env`, `--global`, `--ignore-pattern`, `--parser`, `--parser-options`, `--plugin`, and `--rule`). CLI options overwrite the setting in config files.
  3183. * @property {string} [cwd] The base directory to start lookup.
  3184. * @property {string} [ignorePath] The path to the alternative file of `.eslintignore`.
  3185. * @property {string[]} [rulePaths] The value of `--rulesdir` option.
  3186. * @property {string} [specificConfigPath] The value of `--config` option.
  3187. * @property {boolean} [useEslintrc] if `false` then it doesn't load config files.
  3188. * @property {Function} loadRules The function to use to load rules.
  3189. * @property {Map<string,Rule>} builtInRules The rules that are built in to ESLint.
  3190. * @property {Object} [resolver=ModuleResolver] The module resolver object.
  3191. * @property {string} eslintAllPath The path to the definitions for eslint:all.
  3192. * @property {Function} getEslintAllConfig Returns the config data for eslint:all.
  3193. * @property {string} eslintRecommendedPath The path to the definitions for eslint:recommended.
  3194. * @property {Function} getEslintRecommendedConfig Returns the config data for eslint:recommended.
  3195. */
  3196. /**
  3197. * @typedef {Object} CascadingConfigArrayFactoryInternalSlots
  3198. * @property {ConfigArray} baseConfigArray The config array of `baseConfig` option.
  3199. * @property {ConfigData} baseConfigData The config data of `baseConfig` option. This is used to reset `baseConfigArray`.
  3200. * @property {ConfigArray} cliConfigArray The config array of CLI options.
  3201. * @property {ConfigData} cliConfigData The config data of CLI options. This is used to reset `cliConfigArray`.
  3202. * @property {ConfigArrayFactory} configArrayFactory The factory for config arrays.
  3203. * @property {Map<string, ConfigArray>} configCache The cache from directory paths to config arrays.
  3204. * @property {string} cwd The base directory to start lookup.
  3205. * @property {WeakMap<ConfigArray, ConfigArray>} finalizeCache The cache from config arrays to finalized config arrays.
  3206. * @property {string} [ignorePath] The path to the alternative file of `.eslintignore`.
  3207. * @property {string[]|null} rulePaths The value of `--rulesdir` option. This is used to reset `baseConfigArray`.
  3208. * @property {string|null} specificConfigPath The value of `--config` option. This is used to reset `cliConfigArray`.
  3209. * @property {boolean} useEslintrc if `false` then it doesn't load config files.
  3210. * @property {Function} loadRules The function to use to load rules.
  3211. * @property {Map<string,Rule>} builtInRules The rules that are built in to ESLint.
  3212. * @property {Object} [resolver=ModuleResolver] The module resolver object.
  3213. * @property {string} eslintAllPath The path to the definitions for eslint:all.
  3214. * @property {Function} getEslintAllConfig Returns the config data for eslint:all.
  3215. * @property {string} eslintRecommendedPath The path to the definitions for eslint:recommended.
  3216. * @property {Function} getEslintRecommendedConfig Returns the config data for eslint:recommended.
  3217. */
  3218. /** @type {WeakMap<CascadingConfigArrayFactory, CascadingConfigArrayFactoryInternalSlots>} */
  3219. const internalSlotsMap = new WeakMap();
  3220. /**
  3221. * Create the config array from `baseConfig` and `rulePaths`.
  3222. * @param {CascadingConfigArrayFactoryInternalSlots} slots The slots.
  3223. * @returns {ConfigArray} The config array of the base configs.
  3224. */
  3225. function createBaseConfigArray({
  3226. configArrayFactory,
  3227. baseConfigData,
  3228. rulePaths,
  3229. cwd,
  3230. loadRules
  3231. }) {
  3232. const baseConfigArray = configArrayFactory.create(
  3233. baseConfigData,
  3234. { name: "BaseConfig" }
  3235. );
  3236. /*
  3237. * Create the config array element for the default ignore patterns.
  3238. * This element has `ignorePattern` property that ignores the default
  3239. * patterns in the current working directory.
  3240. */
  3241. baseConfigArray.unshift(configArrayFactory.create(
  3242. { ignorePatterns: IgnorePattern.DefaultPatterns },
  3243. { name: "DefaultIgnorePattern" }
  3244. )[0]);
  3245. /*
  3246. * Load rules `--rulesdir` option as a pseudo plugin.
  3247. * Use a pseudo plugin to define rules of `--rulesdir`, so we can validate
  3248. * the rule's options with only information in the config array.
  3249. */
  3250. if (rulePaths && rulePaths.length > 0) {
  3251. baseConfigArray.push({
  3252. type: "config",
  3253. name: "--rulesdir",
  3254. filePath: "",
  3255. plugins: {
  3256. "": new ConfigDependency({
  3257. definition: {
  3258. rules: rulePaths.reduce(
  3259. (map, rulesPath) => Object.assign(
  3260. map,
  3261. loadRules(rulesPath, cwd)
  3262. ),
  3263. {}
  3264. )
  3265. },
  3266. filePath: "",
  3267. id: "",
  3268. importerName: "--rulesdir",
  3269. importerPath: ""
  3270. })
  3271. }
  3272. });
  3273. }
  3274. return baseConfigArray;
  3275. }
  3276. /**
  3277. * Create the config array from CLI options.
  3278. * @param {CascadingConfigArrayFactoryInternalSlots} slots The slots.
  3279. * @returns {ConfigArray} The config array of the base configs.
  3280. */
  3281. function createCLIConfigArray({
  3282. cliConfigData,
  3283. configArrayFactory,
  3284. cwd,
  3285. ignorePath,
  3286. specificConfigPath
  3287. }) {
  3288. const cliConfigArray = configArrayFactory.create(
  3289. cliConfigData,
  3290. { name: "CLIOptions" }
  3291. );
  3292. cliConfigArray.unshift(
  3293. ...(ignorePath
  3294. ? configArrayFactory.loadESLintIgnore(ignorePath)
  3295. : configArrayFactory.loadDefaultESLintIgnore())
  3296. );
  3297. if (specificConfigPath) {
  3298. cliConfigArray.unshift(
  3299. ...configArrayFactory.loadFile(
  3300. specificConfigPath,
  3301. { name: "--config", basePath: cwd }
  3302. )
  3303. );
  3304. }
  3305. return cliConfigArray;
  3306. }
  3307. /**
  3308. * The error type when there are files matched by a glob, but all of them have been ignored.
  3309. */
  3310. class ConfigurationNotFoundError extends Error {
  3311. // eslint-disable-next-line jsdoc/require-description
  3312. /**
  3313. * @param {string} directoryPath The directory path.
  3314. */
  3315. constructor(directoryPath) {
  3316. super(`No ESLint configuration found in ${directoryPath}.`);
  3317. this.messageTemplate = "no-config-found";
  3318. this.messageData = { directoryPath };
  3319. }
  3320. }
  3321. /**
  3322. * This class provides the functionality that enumerates every file which is
  3323. * matched by given glob patterns and that configuration.
  3324. */
  3325. class CascadingConfigArrayFactory {
  3326. /**
  3327. * Initialize this enumerator.
  3328. * @param {CascadingConfigArrayFactoryOptions} options The options.
  3329. */
  3330. constructor({
  3331. additionalPluginPool = new Map(),
  3332. baseConfig: baseConfigData = null,
  3333. cliConfig: cliConfigData = null,
  3334. cwd = process.cwd(),
  3335. ignorePath,
  3336. resolvePluginsRelativeTo,
  3337. rulePaths = [],
  3338. specificConfigPath = null,
  3339. useEslintrc = true,
  3340. builtInRules = new Map(),
  3341. loadRules,
  3342. resolver,
  3343. eslintRecommendedPath,
  3344. getEslintRecommendedConfig,
  3345. eslintAllPath,
  3346. getEslintAllConfig
  3347. } = {}) {
  3348. const configArrayFactory = new ConfigArrayFactory({
  3349. additionalPluginPool,
  3350. cwd,
  3351. resolvePluginsRelativeTo,
  3352. builtInRules,
  3353. resolver,
  3354. eslintRecommendedPath,
  3355. getEslintRecommendedConfig,
  3356. eslintAllPath,
  3357. getEslintAllConfig
  3358. });
  3359. internalSlotsMap.set(this, {
  3360. baseConfigArray: createBaseConfigArray({
  3361. baseConfigData,
  3362. configArrayFactory,
  3363. cwd,
  3364. rulePaths,
  3365. loadRules
  3366. }),
  3367. baseConfigData,
  3368. cliConfigArray: createCLIConfigArray({
  3369. cliConfigData,
  3370. configArrayFactory,
  3371. cwd,
  3372. ignorePath,
  3373. specificConfigPath
  3374. }),
  3375. cliConfigData,
  3376. configArrayFactory,
  3377. configCache: new Map(),
  3378. cwd,
  3379. finalizeCache: new WeakMap(),
  3380. ignorePath,
  3381. rulePaths,
  3382. specificConfigPath,
  3383. useEslintrc,
  3384. builtInRules,
  3385. loadRules
  3386. });
  3387. }
  3388. /**
  3389. * The path to the current working directory.
  3390. * This is used by tests.
  3391. * @type {string}
  3392. */
  3393. get cwd() {
  3394. const { cwd } = internalSlotsMap.get(this);
  3395. return cwd;
  3396. }
  3397. /**
  3398. * Get the config array of a given file.
  3399. * If `filePath` was not given, it returns the config which contains only
  3400. * `baseConfigData` and `cliConfigData`.
  3401. * @param {string} [filePath] The file path to a file.
  3402. * @param {Object} [options] The options.
  3403. * @param {boolean} [options.ignoreNotFoundError] If `true` then it doesn't throw `ConfigurationNotFoundError`.
  3404. * @returns {ConfigArray} The config array of the file.
  3405. */
  3406. getConfigArrayForFile(filePath, { ignoreNotFoundError = false } = {}) {
  3407. const {
  3408. baseConfigArray,
  3409. cliConfigArray,
  3410. cwd
  3411. } = internalSlotsMap.get(this);
  3412. if (!filePath) {
  3413. return new ConfigArray(...baseConfigArray, ...cliConfigArray);
  3414. }
  3415. const directoryPath = path__default["default"].dirname(path__default["default"].resolve(cwd, filePath));
  3416. debug$1(`Load config files for ${directoryPath}.`);
  3417. return this._finalizeConfigArray(
  3418. this._loadConfigInAncestors(directoryPath),
  3419. directoryPath,
  3420. ignoreNotFoundError
  3421. );
  3422. }
  3423. /**
  3424. * Set the config data to override all configs.
  3425. * Require to call `clearCache()` method after this method is called.
  3426. * @param {ConfigData} configData The config data to override all configs.
  3427. * @returns {void}
  3428. */
  3429. setOverrideConfig(configData) {
  3430. const slots = internalSlotsMap.get(this);
  3431. slots.cliConfigData = configData;
  3432. }
  3433. /**
  3434. * Clear config cache.
  3435. * @returns {void}
  3436. */
  3437. clearCache() {
  3438. const slots = internalSlotsMap.get(this);
  3439. slots.baseConfigArray = createBaseConfigArray(slots);
  3440. slots.cliConfigArray = createCLIConfigArray(slots);
  3441. slots.configCache.clear();
  3442. }
  3443. /**
  3444. * Load and normalize config files from the ancestor directories.
  3445. * @param {string} directoryPath The path to a leaf directory.
  3446. * @param {boolean} configsExistInSubdirs `true` if configurations exist in subdirectories.
  3447. * @returns {ConfigArray} The loaded config.
  3448. * @private
  3449. */
  3450. _loadConfigInAncestors(directoryPath, configsExistInSubdirs = false) {
  3451. const {
  3452. baseConfigArray,
  3453. configArrayFactory,
  3454. configCache,
  3455. cwd,
  3456. useEslintrc
  3457. } = internalSlotsMap.get(this);
  3458. if (!useEslintrc) {
  3459. return baseConfigArray;
  3460. }
  3461. let configArray = configCache.get(directoryPath);
  3462. // Hit cache.
  3463. if (configArray) {
  3464. debug$1(`Cache hit: ${directoryPath}.`);
  3465. return configArray;
  3466. }
  3467. debug$1(`No cache found: ${directoryPath}.`);
  3468. const homePath = os__default["default"].homedir();
  3469. // Consider this is root.
  3470. if (directoryPath === homePath && cwd !== homePath) {
  3471. debug$1("Stop traversing because of considered root.");
  3472. if (configsExistInSubdirs) {
  3473. const filePath = ConfigArrayFactory.getPathToConfigFileInDirectory(directoryPath);
  3474. if (filePath) {
  3475. emitDeprecationWarning(
  3476. filePath,
  3477. "ESLINT_PERSONAL_CONFIG_SUPPRESS"
  3478. );
  3479. }
  3480. }
  3481. return this._cacheConfig(directoryPath, baseConfigArray);
  3482. }
  3483. // Load the config on this directory.
  3484. try {
  3485. configArray = configArrayFactory.loadInDirectory(directoryPath);
  3486. } catch (error) {
  3487. /* istanbul ignore next */
  3488. if (error.code === "EACCES") {
  3489. debug$1("Stop traversing because of 'EACCES' error.");
  3490. return this._cacheConfig(directoryPath, baseConfigArray);
  3491. }
  3492. throw error;
  3493. }
  3494. if (configArray.length > 0 && configArray.isRoot()) {
  3495. debug$1("Stop traversing because of 'root:true'.");
  3496. configArray.unshift(...baseConfigArray);
  3497. return this._cacheConfig(directoryPath, configArray);
  3498. }
  3499. // Load from the ancestors and merge it.
  3500. const parentPath = path__default["default"].dirname(directoryPath);
  3501. const parentConfigArray = parentPath && parentPath !== directoryPath
  3502. ? this._loadConfigInAncestors(
  3503. parentPath,
  3504. configsExistInSubdirs || configArray.length > 0
  3505. )
  3506. : baseConfigArray;
  3507. if (configArray.length > 0) {
  3508. configArray.unshift(...parentConfigArray);
  3509. } else {
  3510. configArray = parentConfigArray;
  3511. }
  3512. // Cache and return.
  3513. return this._cacheConfig(directoryPath, configArray);
  3514. }
  3515. /**
  3516. * Freeze and cache a given config.
  3517. * @param {string} directoryPath The path to a directory as a cache key.
  3518. * @param {ConfigArray} configArray The config array as a cache value.
  3519. * @returns {ConfigArray} The `configArray` (frozen).
  3520. */
  3521. _cacheConfig(directoryPath, configArray) {
  3522. const { configCache } = internalSlotsMap.get(this);
  3523. Object.freeze(configArray);
  3524. configCache.set(directoryPath, configArray);
  3525. return configArray;
  3526. }
  3527. /**
  3528. * Finalize a given config array.
  3529. * Concatenate `--config` and other CLI options.
  3530. * @param {ConfigArray} configArray The parent config array.
  3531. * @param {string} directoryPath The path to the leaf directory to find config files.
  3532. * @param {boolean} ignoreNotFoundError If `true` then it doesn't throw `ConfigurationNotFoundError`.
  3533. * @returns {ConfigArray} The loaded config.
  3534. * @private
  3535. */
  3536. _finalizeConfigArray(configArray, directoryPath, ignoreNotFoundError) {
  3537. const {
  3538. cliConfigArray,
  3539. configArrayFactory,
  3540. finalizeCache,
  3541. useEslintrc,
  3542. builtInRules
  3543. } = internalSlotsMap.get(this);
  3544. let finalConfigArray = finalizeCache.get(configArray);
  3545. if (!finalConfigArray) {
  3546. finalConfigArray = configArray;
  3547. // Load the personal config if there are no regular config files.
  3548. if (
  3549. useEslintrc &&
  3550. configArray.every(c => !c.filePath) &&
  3551. cliConfigArray.every(c => !c.filePath) // `--config` option can be a file.
  3552. ) {
  3553. const homePath = os__default["default"].homedir();
  3554. debug$1("Loading the config file of the home directory:", homePath);
  3555. const personalConfigArray = configArrayFactory.loadInDirectory(
  3556. homePath,
  3557. { name: "PersonalConfig" }
  3558. );
  3559. if (
  3560. personalConfigArray.length > 0 &&
  3561. !directoryPath.startsWith(homePath)
  3562. ) {
  3563. const lastElement =
  3564. personalConfigArray[personalConfigArray.length - 1];
  3565. emitDeprecationWarning(
  3566. lastElement.filePath,
  3567. "ESLINT_PERSONAL_CONFIG_LOAD"
  3568. );
  3569. }
  3570. finalConfigArray = finalConfigArray.concat(personalConfigArray);
  3571. }
  3572. // Apply CLI options.
  3573. if (cliConfigArray.length > 0) {
  3574. finalConfigArray = finalConfigArray.concat(cliConfigArray);
  3575. }
  3576. // Validate rule settings and environments.
  3577. const validator = new ConfigValidator({
  3578. builtInRules
  3579. });
  3580. validator.validateConfigArray(finalConfigArray);
  3581. // Cache it.
  3582. Object.freeze(finalConfigArray);
  3583. finalizeCache.set(configArray, finalConfigArray);
  3584. debug$1(
  3585. "Configuration was determined: %o on %s",
  3586. finalConfigArray,
  3587. directoryPath
  3588. );
  3589. }
  3590. // At least one element (the default ignore patterns) exists.
  3591. if (!ignoreNotFoundError && useEslintrc && finalConfigArray.length <= 1) {
  3592. throw new ConfigurationNotFoundError(directoryPath);
  3593. }
  3594. return finalConfigArray;
  3595. }
  3596. }
  3597. /**
  3598. * @fileoverview Compatibility class for flat config.
  3599. * @author Nicholas C. Zakas
  3600. */
  3601. //-----------------------------------------------------------------------------
  3602. // Helpers
  3603. //-----------------------------------------------------------------------------
  3604. /** @typedef {import("../../shared/types").Environment} Environment */
  3605. /** @typedef {import("../../shared/types").Processor} Processor */
  3606. const debug = debugOrig__default["default"]("eslintrc:flat-compat");
  3607. const cafactory = Symbol("cafactory");
  3608. /**
  3609. * Translates an ESLintRC-style config object into a flag-config-style config
  3610. * object.
  3611. * @param {Object} eslintrcConfig An ESLintRC-style config object.
  3612. * @param {Object} options Options to help translate the config.
  3613. * @param {string} options.resolveConfigRelativeTo To the directory to resolve
  3614. * configs from.
  3615. * @param {string} options.resolvePluginsRelativeTo The directory to resolve
  3616. * plugins from.
  3617. * @param {ReadOnlyMap<string,Environment>} options.pluginEnvironments A map of plugin environment
  3618. * names to objects.
  3619. * @param {ReadOnlyMap<string,Processor>} options.pluginProcessors A map of plugin processor
  3620. * names to objects.
  3621. * @returns {Object} A flag-config-style config object.
  3622. */
  3623. function translateESLintRC(eslintrcConfig, {
  3624. resolveConfigRelativeTo,
  3625. resolvePluginsRelativeTo,
  3626. pluginEnvironments,
  3627. pluginProcessors
  3628. }) {
  3629. const flatConfig = {};
  3630. const configs = [];
  3631. const languageOptions = {};
  3632. const linterOptions = {};
  3633. const keysToCopy = ["settings", "rules", "processor"];
  3634. const languageOptionsKeysToCopy = ["globals", "parser", "parserOptions"];
  3635. const linterOptionsKeysToCopy = ["noInlineConfig", "reportUnusedDisableDirectives"];
  3636. // copy over simple translations
  3637. for (const key of keysToCopy) {
  3638. if (key in eslintrcConfig && typeof eslintrcConfig[key] !== "undefined") {
  3639. flatConfig[key] = eslintrcConfig[key];
  3640. }
  3641. }
  3642. // copy over languageOptions
  3643. for (const key of languageOptionsKeysToCopy) {
  3644. if (key in eslintrcConfig && typeof eslintrcConfig[key] !== "undefined") {
  3645. // create the languageOptions key in the flat config
  3646. flatConfig.languageOptions = languageOptions;
  3647. if (key === "parser") {
  3648. debug(`Resolving parser '${languageOptions[key]}' relative to ${resolveConfigRelativeTo}`);
  3649. if (eslintrcConfig[key].error) {
  3650. throw eslintrcConfig[key].error;
  3651. }
  3652. languageOptions[key] = eslintrcConfig[key].definition;
  3653. continue;
  3654. }
  3655. // clone any object values that are in the eslintrc config
  3656. if (eslintrcConfig[key] && typeof eslintrcConfig[key] === "object") {
  3657. languageOptions[key] = {
  3658. ...eslintrcConfig[key]
  3659. };
  3660. } else {
  3661. languageOptions[key] = eslintrcConfig[key];
  3662. }
  3663. }
  3664. }
  3665. // copy over linterOptions
  3666. for (const key of linterOptionsKeysToCopy) {
  3667. if (key in eslintrcConfig && typeof eslintrcConfig[key] !== "undefined") {
  3668. flatConfig.linterOptions = linterOptions;
  3669. linterOptions[key] = eslintrcConfig[key];
  3670. }
  3671. }
  3672. // move ecmaVersion a level up
  3673. if (languageOptions.parserOptions) {
  3674. if ("ecmaVersion" in languageOptions.parserOptions) {
  3675. languageOptions.ecmaVersion = languageOptions.parserOptions.ecmaVersion;
  3676. delete languageOptions.parserOptions.ecmaVersion;
  3677. }
  3678. if ("sourceType" in languageOptions.parserOptions) {
  3679. languageOptions.sourceType = languageOptions.parserOptions.sourceType;
  3680. delete languageOptions.parserOptions.sourceType;
  3681. }
  3682. // check to see if we even need parserOptions anymore and remove it if not
  3683. if (Object.keys(languageOptions.parserOptions).length === 0) {
  3684. delete languageOptions.parserOptions;
  3685. }
  3686. }
  3687. // overrides
  3688. if (eslintrcConfig.criteria) {
  3689. flatConfig.files = [absoluteFilePath => eslintrcConfig.criteria.test(absoluteFilePath)];
  3690. }
  3691. // translate plugins
  3692. if (eslintrcConfig.plugins && typeof eslintrcConfig.plugins === "object") {
  3693. debug(`Translating plugins: ${eslintrcConfig.plugins}`);
  3694. flatConfig.plugins = {};
  3695. for (const pluginName of Object.keys(eslintrcConfig.plugins)) {
  3696. debug(`Translating plugin: ${pluginName}`);
  3697. debug(`Resolving plugin '${pluginName} relative to ${resolvePluginsRelativeTo}`);
  3698. const { original: plugin, error } = eslintrcConfig.plugins[pluginName];
  3699. if (error) {
  3700. throw error;
  3701. }
  3702. flatConfig.plugins[pluginName] = plugin;
  3703. // create a config for any processors
  3704. if (plugin.processors) {
  3705. for (const processorName of Object.keys(plugin.processors)) {
  3706. if (processorName.startsWith(".")) {
  3707. debug(`Assigning processor: ${pluginName}/${processorName}`);
  3708. configs.unshift({
  3709. files: [`**/*${processorName}`],
  3710. processor: pluginProcessors.get(`${pluginName}/${processorName}`)
  3711. });
  3712. }
  3713. }
  3714. }
  3715. }
  3716. }
  3717. // translate env - must come after plugins
  3718. if (eslintrcConfig.env && typeof eslintrcConfig.env === "object") {
  3719. for (const envName of Object.keys(eslintrcConfig.env)) {
  3720. // only add environments that are true
  3721. if (eslintrcConfig.env[envName]) {
  3722. debug(`Translating environment: ${envName}`);
  3723. if (environments.has(envName)) {
  3724. // built-in environments should be defined first
  3725. configs.unshift(...translateESLintRC({
  3726. criteria: eslintrcConfig.criteria,
  3727. ...environments.get(envName)
  3728. }, {
  3729. resolveConfigRelativeTo,
  3730. resolvePluginsRelativeTo
  3731. }));
  3732. } else if (pluginEnvironments.has(envName)) {
  3733. // if the environment comes from a plugin, it should come after the plugin config
  3734. configs.push(...translateESLintRC({
  3735. criteria: eslintrcConfig.criteria,
  3736. ...pluginEnvironments.get(envName)
  3737. }, {
  3738. resolveConfigRelativeTo,
  3739. resolvePluginsRelativeTo
  3740. }));
  3741. }
  3742. }
  3743. }
  3744. }
  3745. // only add if there are actually keys in the config
  3746. if (Object.keys(flatConfig).length > 0) {
  3747. configs.push(flatConfig);
  3748. }
  3749. return configs;
  3750. }
  3751. //-----------------------------------------------------------------------------
  3752. // Exports
  3753. //-----------------------------------------------------------------------------
  3754. /**
  3755. * A compatibility class for working with configs.
  3756. */
  3757. class FlatCompat {
  3758. constructor({
  3759. baseDirectory = process.cwd(),
  3760. resolvePluginsRelativeTo = baseDirectory,
  3761. recommendedConfig,
  3762. allConfig
  3763. } = {}) {
  3764. this.baseDirectory = baseDirectory;
  3765. this.resolvePluginsRelativeTo = resolvePluginsRelativeTo;
  3766. this[cafactory] = new ConfigArrayFactory({
  3767. cwd: baseDirectory,
  3768. resolvePluginsRelativeTo,
  3769. getEslintAllConfig: () => {
  3770. if (!allConfig) {
  3771. throw new TypeError("Missing parameter 'allConfig' in FlatCompat constructor.");
  3772. }
  3773. return allConfig;
  3774. },
  3775. getEslintRecommendedConfig: () => {
  3776. if (!recommendedConfig) {
  3777. throw new TypeError("Missing parameter 'recommendedConfig' in FlatCompat constructor.");
  3778. }
  3779. return recommendedConfig;
  3780. }
  3781. });
  3782. }
  3783. /**
  3784. * Translates an ESLintRC-style config into a flag-config-style config.
  3785. * @param {Object} eslintrcConfig The ESLintRC-style config object.
  3786. * @returns {Object} A flag-config-style config object.
  3787. */
  3788. config(eslintrcConfig) {
  3789. const eslintrcArray = this[cafactory].create(eslintrcConfig, {
  3790. basePath: this.baseDirectory
  3791. });
  3792. const flatArray = [];
  3793. let hasIgnorePatterns = false;
  3794. eslintrcArray.forEach(configData => {
  3795. if (configData.type === "config") {
  3796. hasIgnorePatterns = hasIgnorePatterns || configData.ignorePattern;
  3797. flatArray.push(...translateESLintRC(configData, {
  3798. resolveConfigRelativeTo: path__default["default"].join(this.baseDirectory, "__placeholder.js"),
  3799. resolvePluginsRelativeTo: path__default["default"].join(this.resolvePluginsRelativeTo, "__placeholder.js"),
  3800. pluginEnvironments: eslintrcArray.pluginEnvironments,
  3801. pluginProcessors: eslintrcArray.pluginProcessors
  3802. }));
  3803. }
  3804. });
  3805. // combine ignorePatterns to emulate ESLintRC behavior better
  3806. if (hasIgnorePatterns) {
  3807. flatArray.unshift({
  3808. ignores: [filePath => {
  3809. // Compute the final config for this file.
  3810. // This filters config array elements by `files`/`excludedFiles` then merges the elements.
  3811. const finalConfig = eslintrcArray.extractConfig(filePath);
  3812. // Test the `ignorePattern` properties of the final config.
  3813. return Boolean(finalConfig.ignores) && finalConfig.ignores(filePath);
  3814. }]
  3815. });
  3816. }
  3817. return flatArray;
  3818. }
  3819. /**
  3820. * Translates the `env` section of an ESLintRC-style config.
  3821. * @param {Object} envConfig The `env` section of an ESLintRC config.
  3822. * @returns {Object[]} An array of flag-config objects representing the environments.
  3823. */
  3824. env(envConfig) {
  3825. return this.config({
  3826. env: envConfig
  3827. });
  3828. }
  3829. /**
  3830. * Translates the `extends` section of an ESLintRC-style config.
  3831. * @param {...string} configsToExtend The names of the configs to load.
  3832. * @returns {Object[]} An array of flag-config objects representing the config.
  3833. */
  3834. extends(...configsToExtend) {
  3835. return this.config({
  3836. extends: configsToExtend
  3837. });
  3838. }
  3839. /**
  3840. * Translates the `plugins` section of an ESLintRC-style config.
  3841. * @param {...string} plugins The names of the plugins to load.
  3842. * @returns {Object[]} An array of flag-config objects representing the plugins.
  3843. */
  3844. plugins(...plugins) {
  3845. return this.config({
  3846. plugins
  3847. });
  3848. }
  3849. }
  3850. /**
  3851. * @fileoverview Package exports for @eslint/eslintrc
  3852. * @author Nicholas C. Zakas
  3853. */
  3854. //-----------------------------------------------------------------------------
  3855. // Exports
  3856. //-----------------------------------------------------------------------------
  3857. const Legacy = {
  3858. ConfigArray,
  3859. createConfigArrayFactoryContext: createContext,
  3860. CascadingConfigArrayFactory,
  3861. ConfigArrayFactory,
  3862. ConfigDependency,
  3863. ExtractedConfig,
  3864. IgnorePattern,
  3865. OverrideTester,
  3866. getUsedExtractedConfigs,
  3867. environments,
  3868. loadConfigFile,
  3869. // shared
  3870. ConfigOps,
  3871. ConfigValidator,
  3872. ModuleResolver,
  3873. naming
  3874. };
  3875. exports.FlatCompat = FlatCompat;
  3876. exports.Legacy = Legacy;
  3877. //# sourceMappingURL=eslintrc.cjs.map