eslintrc.cjs 145 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371
  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 Defines a schema for configs.
  1427. * @author Sylvan Mably
  1428. */
  1429. const baseConfigProperties = {
  1430. $schema: { type: "string" },
  1431. env: { type: "object" },
  1432. extends: { $ref: "#/definitions/stringOrStrings" },
  1433. globals: { type: "object" },
  1434. overrides: {
  1435. type: "array",
  1436. items: { $ref: "#/definitions/overrideConfig" },
  1437. additionalItems: false
  1438. },
  1439. parser: { type: ["string", "null"] },
  1440. parserOptions: { type: "object" },
  1441. plugins: { type: "array" },
  1442. processor: { type: "string" },
  1443. rules: { type: "object" },
  1444. settings: { type: "object" },
  1445. noInlineConfig: { type: "boolean" },
  1446. reportUnusedDisableDirectives: { type: "boolean" },
  1447. ecmaFeatures: { type: "object" } // deprecated; logs a warning when used
  1448. };
  1449. const configSchema = {
  1450. definitions: {
  1451. stringOrStrings: {
  1452. oneOf: [
  1453. { type: "string" },
  1454. {
  1455. type: "array",
  1456. items: { type: "string" },
  1457. additionalItems: false
  1458. }
  1459. ]
  1460. },
  1461. stringOrStringsRequired: {
  1462. oneOf: [
  1463. { type: "string" },
  1464. {
  1465. type: "array",
  1466. items: { type: "string" },
  1467. additionalItems: false,
  1468. minItems: 1
  1469. }
  1470. ]
  1471. },
  1472. // Config at top-level.
  1473. objectConfig: {
  1474. type: "object",
  1475. properties: {
  1476. root: { type: "boolean" },
  1477. ignorePatterns: { $ref: "#/definitions/stringOrStrings" },
  1478. ...baseConfigProperties
  1479. },
  1480. additionalProperties: false
  1481. },
  1482. // Config in `overrides`.
  1483. overrideConfig: {
  1484. type: "object",
  1485. properties: {
  1486. excludedFiles: { $ref: "#/definitions/stringOrStrings" },
  1487. files: { $ref: "#/definitions/stringOrStringsRequired" },
  1488. ...baseConfigProperties
  1489. },
  1490. required: ["files"],
  1491. additionalProperties: false
  1492. }
  1493. },
  1494. $ref: "#/definitions/objectConfig"
  1495. };
  1496. /**
  1497. * @fileoverview Defines environment settings and globals.
  1498. * @author Elan Shanker
  1499. */
  1500. //------------------------------------------------------------------------------
  1501. // Helpers
  1502. //------------------------------------------------------------------------------
  1503. /**
  1504. * Get the object that has difference.
  1505. * @param {Record<string,boolean>} current The newer object.
  1506. * @param {Record<string,boolean>} prev The older object.
  1507. * @returns {Record<string,boolean>} The difference object.
  1508. */
  1509. function getDiff(current, prev) {
  1510. const retv = {};
  1511. for (const [key, value] of Object.entries(current)) {
  1512. if (!Object.hasOwnProperty.call(prev, key)) {
  1513. retv[key] = value;
  1514. }
  1515. }
  1516. return retv;
  1517. }
  1518. const newGlobals2015 = getDiff(globals__default["default"].es2015, globals__default["default"].es5); // 19 variables such as Promise, Map, ...
  1519. const newGlobals2017 = {
  1520. Atomics: false,
  1521. SharedArrayBuffer: false
  1522. };
  1523. const newGlobals2020 = {
  1524. BigInt: false,
  1525. BigInt64Array: false,
  1526. BigUint64Array: false,
  1527. globalThis: false
  1528. };
  1529. const newGlobals2021 = {
  1530. AggregateError: false,
  1531. FinalizationRegistry: false,
  1532. WeakRef: false
  1533. };
  1534. //------------------------------------------------------------------------------
  1535. // Public Interface
  1536. //------------------------------------------------------------------------------
  1537. /** @type {Map<string, import("../lib/shared/types").Environment>} */
  1538. var environments = new Map(Object.entries({
  1539. // Language
  1540. builtin: {
  1541. globals: globals__default["default"].es5
  1542. },
  1543. es6: {
  1544. globals: newGlobals2015,
  1545. parserOptions: {
  1546. ecmaVersion: 6
  1547. }
  1548. },
  1549. es2015: {
  1550. globals: newGlobals2015,
  1551. parserOptions: {
  1552. ecmaVersion: 6
  1553. }
  1554. },
  1555. es2016: {
  1556. globals: newGlobals2015,
  1557. parserOptions: {
  1558. ecmaVersion: 7
  1559. }
  1560. },
  1561. es2017: {
  1562. globals: { ...newGlobals2015, ...newGlobals2017 },
  1563. parserOptions: {
  1564. ecmaVersion: 8
  1565. }
  1566. },
  1567. es2018: {
  1568. globals: { ...newGlobals2015, ...newGlobals2017 },
  1569. parserOptions: {
  1570. ecmaVersion: 9
  1571. }
  1572. },
  1573. es2019: {
  1574. globals: { ...newGlobals2015, ...newGlobals2017 },
  1575. parserOptions: {
  1576. ecmaVersion: 10
  1577. }
  1578. },
  1579. es2020: {
  1580. globals: { ...newGlobals2015, ...newGlobals2017, ...newGlobals2020 },
  1581. parserOptions: {
  1582. ecmaVersion: 11
  1583. }
  1584. },
  1585. es2021: {
  1586. globals: { ...newGlobals2015, ...newGlobals2017, ...newGlobals2020, ...newGlobals2021 },
  1587. parserOptions: {
  1588. ecmaVersion: 12
  1589. }
  1590. },
  1591. es2022: {
  1592. globals: { ...newGlobals2015, ...newGlobals2017, ...newGlobals2020, ...newGlobals2021 },
  1593. parserOptions: {
  1594. ecmaVersion: 13
  1595. }
  1596. },
  1597. es2023: {
  1598. globals: { ...newGlobals2015, ...newGlobals2017, ...newGlobals2020, ...newGlobals2021 },
  1599. parserOptions: {
  1600. ecmaVersion: 14
  1601. }
  1602. },
  1603. es2024: {
  1604. globals: { ...newGlobals2015, ...newGlobals2017, ...newGlobals2020, ...newGlobals2021 },
  1605. parserOptions: {
  1606. ecmaVersion: 15
  1607. }
  1608. },
  1609. // Platforms
  1610. browser: {
  1611. globals: globals__default["default"].browser
  1612. },
  1613. node: {
  1614. globals: globals__default["default"].node,
  1615. parserOptions: {
  1616. ecmaFeatures: {
  1617. globalReturn: true
  1618. }
  1619. }
  1620. },
  1621. "shared-node-browser": {
  1622. globals: globals__default["default"]["shared-node-browser"]
  1623. },
  1624. worker: {
  1625. globals: globals__default["default"].worker
  1626. },
  1627. serviceworker: {
  1628. globals: globals__default["default"].serviceworker
  1629. },
  1630. // Frameworks
  1631. commonjs: {
  1632. globals: globals__default["default"].commonjs,
  1633. parserOptions: {
  1634. ecmaFeatures: {
  1635. globalReturn: true
  1636. }
  1637. }
  1638. },
  1639. amd: {
  1640. globals: globals__default["default"].amd
  1641. },
  1642. mocha: {
  1643. globals: globals__default["default"].mocha
  1644. },
  1645. jasmine: {
  1646. globals: globals__default["default"].jasmine
  1647. },
  1648. jest: {
  1649. globals: globals__default["default"].jest
  1650. },
  1651. phantomjs: {
  1652. globals: globals__default["default"].phantomjs
  1653. },
  1654. jquery: {
  1655. globals: globals__default["default"].jquery
  1656. },
  1657. qunit: {
  1658. globals: globals__default["default"].qunit
  1659. },
  1660. prototypejs: {
  1661. globals: globals__default["default"].prototypejs
  1662. },
  1663. shelljs: {
  1664. globals: globals__default["default"].shelljs
  1665. },
  1666. meteor: {
  1667. globals: globals__default["default"].meteor
  1668. },
  1669. mongo: {
  1670. globals: globals__default["default"].mongo
  1671. },
  1672. protractor: {
  1673. globals: globals__default["default"].protractor
  1674. },
  1675. applescript: {
  1676. globals: globals__default["default"].applescript
  1677. },
  1678. nashorn: {
  1679. globals: globals__default["default"].nashorn
  1680. },
  1681. atomtest: {
  1682. globals: globals__default["default"].atomtest
  1683. },
  1684. embertest: {
  1685. globals: globals__default["default"].embertest
  1686. },
  1687. webextensions: {
  1688. globals: globals__default["default"].webextensions
  1689. },
  1690. greasemonkey: {
  1691. globals: globals__default["default"].greasemonkey
  1692. }
  1693. }));
  1694. /**
  1695. * @fileoverview Validates configs.
  1696. * @author Brandon Mills
  1697. */
  1698. const ajv = ajvOrig();
  1699. const ruleValidators = new WeakMap();
  1700. const noop = Function.prototype;
  1701. //------------------------------------------------------------------------------
  1702. // Private
  1703. //------------------------------------------------------------------------------
  1704. let validateSchema;
  1705. const severityMap = {
  1706. error: 2,
  1707. warn: 1,
  1708. off: 0
  1709. };
  1710. const validated = new WeakSet();
  1711. // JSON schema that disallows passing any options
  1712. const noOptionsSchema = Object.freeze({
  1713. type: "array",
  1714. minItems: 0,
  1715. maxItems: 0
  1716. });
  1717. //-----------------------------------------------------------------------------
  1718. // Exports
  1719. //-----------------------------------------------------------------------------
  1720. class ConfigValidator {
  1721. constructor({ builtInRules = new Map() } = {}) {
  1722. this.builtInRules = builtInRules;
  1723. }
  1724. /**
  1725. * Gets a complete options schema for a rule.
  1726. * @param {Rule} rule A rule object
  1727. * @throws {TypeError} If `meta.schema` is specified but is not an array, object or `false`.
  1728. * @returns {Object|null} JSON Schema for the rule's options.
  1729. * `null` if rule wasn't passed or its `meta.schema` is `false`.
  1730. */
  1731. getRuleOptionsSchema(rule) {
  1732. if (!rule) {
  1733. return null;
  1734. }
  1735. if (!rule.meta) {
  1736. return { ...noOptionsSchema }; // default if `meta.schema` is not specified
  1737. }
  1738. const schema = rule.meta.schema;
  1739. if (typeof schema === "undefined") {
  1740. return { ...noOptionsSchema }; // default if `meta.schema` is not specified
  1741. }
  1742. // `schema:false` is an allowed explicit opt-out of options validation for the rule
  1743. if (schema === false) {
  1744. return null;
  1745. }
  1746. if (typeof schema !== "object" || schema === null) {
  1747. throw new TypeError("Rule's `meta.schema` must be an array or object");
  1748. }
  1749. // ESLint-specific array form needs to be converted into a valid JSON Schema definition
  1750. if (Array.isArray(schema)) {
  1751. if (schema.length) {
  1752. return {
  1753. type: "array",
  1754. items: schema,
  1755. minItems: 0,
  1756. maxItems: schema.length
  1757. };
  1758. }
  1759. // `schema:[]` is an explicit way to specify that the rule does not accept any options
  1760. return { ...noOptionsSchema };
  1761. }
  1762. // `schema:<object>` is assumed to be a valid JSON Schema definition
  1763. return schema;
  1764. }
  1765. /**
  1766. * Validates a rule's severity and returns the severity value. Throws an error if the severity is invalid.
  1767. * @param {options} options The given options for the rule.
  1768. * @returns {number|string} The rule's severity value
  1769. */
  1770. validateRuleSeverity(options) {
  1771. const severity = Array.isArray(options) ? options[0] : options;
  1772. const normSeverity = typeof severity === "string" ? severityMap[severity.toLowerCase()] : severity;
  1773. if (normSeverity === 0 || normSeverity === 1 || normSeverity === 2) {
  1774. return normSeverity;
  1775. }
  1776. 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`);
  1777. }
  1778. /**
  1779. * Validates the non-severity options passed to a rule, based on its schema.
  1780. * @param {{create: Function}} rule The rule to validate
  1781. * @param {Array} localOptions The options for the rule, excluding severity
  1782. * @returns {void}
  1783. */
  1784. validateRuleSchema(rule, localOptions) {
  1785. if (!ruleValidators.has(rule)) {
  1786. try {
  1787. const schema = this.getRuleOptionsSchema(rule);
  1788. if (schema) {
  1789. ruleValidators.set(rule, ajv.compile(schema));
  1790. }
  1791. } catch (err) {
  1792. const errorWithCode = new Error(err.message, { cause: err });
  1793. errorWithCode.code = "ESLINT_INVALID_RULE_OPTIONS_SCHEMA";
  1794. throw errorWithCode;
  1795. }
  1796. }
  1797. const validateRule = ruleValidators.get(rule);
  1798. if (validateRule) {
  1799. validateRule(localOptions);
  1800. if (validateRule.errors) {
  1801. throw new Error(validateRule.errors.map(
  1802. error => `\tValue ${JSON.stringify(error.data)} ${error.message}.\n`
  1803. ).join(""));
  1804. }
  1805. }
  1806. }
  1807. /**
  1808. * Validates a rule's options against its schema.
  1809. * @param {{create: Function}|null} rule The rule that the config is being validated for
  1810. * @param {string} ruleId The rule's unique name.
  1811. * @param {Array|number} options The given options for the rule.
  1812. * @param {string|null} source The name of the configuration source to report in any errors. If null or undefined,
  1813. * no source is prepended to the message.
  1814. * @returns {void}
  1815. */
  1816. validateRuleOptions(rule, ruleId, options, source = null) {
  1817. try {
  1818. const severity = this.validateRuleSeverity(options);
  1819. if (severity !== 0) {
  1820. this.validateRuleSchema(rule, Array.isArray(options) ? options.slice(1) : []);
  1821. }
  1822. } catch (err) {
  1823. let enhancedMessage = err.code === "ESLINT_INVALID_RULE_OPTIONS_SCHEMA"
  1824. ? `Error while processing options validation schema of rule '${ruleId}': ${err.message}`
  1825. : `Configuration for rule "${ruleId}" is invalid:\n${err.message}`;
  1826. if (typeof source === "string") {
  1827. enhancedMessage = `${source}:\n\t${enhancedMessage}`;
  1828. }
  1829. const enhancedError = new Error(enhancedMessage, { cause: err });
  1830. if (err.code) {
  1831. enhancedError.code = err.code;
  1832. }
  1833. throw enhancedError;
  1834. }
  1835. }
  1836. /**
  1837. * Validates an environment object
  1838. * @param {Object} environment The environment config object to validate.
  1839. * @param {string} source The name of the configuration source to report in any errors.
  1840. * @param {function(envId:string): Object} [getAdditionalEnv] A map from strings to loaded environments.
  1841. * @returns {void}
  1842. */
  1843. validateEnvironment(
  1844. environment,
  1845. source,
  1846. getAdditionalEnv = noop
  1847. ) {
  1848. // not having an environment is ok
  1849. if (!environment) {
  1850. return;
  1851. }
  1852. Object.keys(environment).forEach(id => {
  1853. const env = getAdditionalEnv(id) || environments.get(id) || null;
  1854. if (!env) {
  1855. const message = `${source}:\n\tEnvironment key "${id}" is unknown\n`;
  1856. throw new Error(message);
  1857. }
  1858. });
  1859. }
  1860. /**
  1861. * Validates a rules config object
  1862. * @param {Object} rulesConfig The rules config object to validate.
  1863. * @param {string} source The name of the configuration source to report in any errors.
  1864. * @param {function(ruleId:string): Object} getAdditionalRule A map from strings to loaded rules
  1865. * @returns {void}
  1866. */
  1867. validateRules(
  1868. rulesConfig,
  1869. source,
  1870. getAdditionalRule = noop
  1871. ) {
  1872. if (!rulesConfig) {
  1873. return;
  1874. }
  1875. Object.keys(rulesConfig).forEach(id => {
  1876. const rule = getAdditionalRule(id) || this.builtInRules.get(id) || null;
  1877. this.validateRuleOptions(rule, id, rulesConfig[id], source);
  1878. });
  1879. }
  1880. /**
  1881. * Validates a `globals` section of a config file
  1882. * @param {Object} globalsConfig The `globals` section
  1883. * @param {string|null} source The name of the configuration source to report in the event of an error.
  1884. * @returns {void}
  1885. */
  1886. validateGlobals(globalsConfig, source = null) {
  1887. if (!globalsConfig) {
  1888. return;
  1889. }
  1890. Object.entries(globalsConfig)
  1891. .forEach(([configuredGlobal, configuredValue]) => {
  1892. try {
  1893. normalizeConfigGlobal(configuredValue);
  1894. } catch (err) {
  1895. throw new Error(`ESLint configuration of global '${configuredGlobal}' in ${source} is invalid:\n${err.message}`);
  1896. }
  1897. });
  1898. }
  1899. /**
  1900. * Validate `processor` configuration.
  1901. * @param {string|undefined} processorName The processor name.
  1902. * @param {string} source The name of config file.
  1903. * @param {function(id:string): Processor} getProcessor The getter of defined processors.
  1904. * @returns {void}
  1905. */
  1906. validateProcessor(processorName, source, getProcessor) {
  1907. if (processorName && !getProcessor(processorName)) {
  1908. throw new Error(`ESLint configuration of processor in '${source}' is invalid: '${processorName}' was not found.`);
  1909. }
  1910. }
  1911. /**
  1912. * Formats an array of schema validation errors.
  1913. * @param {Array} errors An array of error messages to format.
  1914. * @returns {string} Formatted error message
  1915. */
  1916. formatErrors(errors) {
  1917. return errors.map(error => {
  1918. if (error.keyword === "additionalProperties") {
  1919. const formattedPropertyPath = error.dataPath.length ? `${error.dataPath.slice(1)}.${error.params.additionalProperty}` : error.params.additionalProperty;
  1920. return `Unexpected top-level property "${formattedPropertyPath}"`;
  1921. }
  1922. if (error.keyword === "type") {
  1923. const formattedField = error.dataPath.slice(1);
  1924. const formattedExpectedType = Array.isArray(error.schema) ? error.schema.join("/") : error.schema;
  1925. const formattedValue = JSON.stringify(error.data);
  1926. return `Property "${formattedField}" is the wrong type (expected ${formattedExpectedType} but got \`${formattedValue}\`)`;
  1927. }
  1928. const field = error.dataPath[0] === "." ? error.dataPath.slice(1) : error.dataPath;
  1929. return `"${field}" ${error.message}. Value: ${JSON.stringify(error.data)}`;
  1930. }).map(message => `\t- ${message}.\n`).join("");
  1931. }
  1932. /**
  1933. * Validates the top level properties of the config object.
  1934. * @param {Object} config The config object to validate.
  1935. * @param {string} source The name of the configuration source to report in any errors.
  1936. * @returns {void}
  1937. */
  1938. validateConfigSchema(config, source = null) {
  1939. validateSchema = validateSchema || ajv.compile(configSchema);
  1940. if (!validateSchema(config)) {
  1941. throw new Error(`ESLint configuration in ${source} is invalid:\n${this.formatErrors(validateSchema.errors)}`);
  1942. }
  1943. if (Object.hasOwnProperty.call(config, "ecmaFeatures")) {
  1944. emitDeprecationWarning(source, "ESLINT_LEGACY_ECMAFEATURES");
  1945. }
  1946. }
  1947. /**
  1948. * Validates an entire config object.
  1949. * @param {Object} config The config object to validate.
  1950. * @param {string} source The name of the configuration source to report in any errors.
  1951. * @param {function(ruleId:string): Object} [getAdditionalRule] A map from strings to loaded rules.
  1952. * @param {function(envId:string): Object} [getAdditionalEnv] A map from strings to loaded envs.
  1953. * @returns {void}
  1954. */
  1955. validate(config, source, getAdditionalRule, getAdditionalEnv) {
  1956. this.validateConfigSchema(config, source);
  1957. this.validateRules(config.rules, source, getAdditionalRule);
  1958. this.validateEnvironment(config.env, source, getAdditionalEnv);
  1959. this.validateGlobals(config.globals, source);
  1960. for (const override of config.overrides || []) {
  1961. this.validateRules(override.rules, source, getAdditionalRule);
  1962. this.validateEnvironment(override.env, source, getAdditionalEnv);
  1963. this.validateGlobals(config.globals, source);
  1964. }
  1965. }
  1966. /**
  1967. * Validate config array object.
  1968. * @param {ConfigArray} configArray The config array to validate.
  1969. * @returns {void}
  1970. */
  1971. validateConfigArray(configArray) {
  1972. const getPluginEnv = Map.prototype.get.bind(configArray.pluginEnvironments);
  1973. const getPluginProcessor = Map.prototype.get.bind(configArray.pluginProcessors);
  1974. const getPluginRule = Map.prototype.get.bind(configArray.pluginRules);
  1975. // Validate.
  1976. for (const element of configArray) {
  1977. if (validated.has(element)) {
  1978. continue;
  1979. }
  1980. validated.add(element);
  1981. this.validateEnvironment(element.env, element.name, getPluginEnv);
  1982. this.validateGlobals(element.globals, element.name);
  1983. this.validateProcessor(element.processor, element.name, getPluginProcessor);
  1984. this.validateRules(element.rules, element.name, getPluginRule);
  1985. }
  1986. }
  1987. }
  1988. /**
  1989. * @fileoverview Common helpers for naming of plugins, formatters and configs
  1990. */
  1991. const NAMESPACE_REGEX = /^@.*\//iu;
  1992. /**
  1993. * Brings package name to correct format based on prefix
  1994. * @param {string} name The name of the package.
  1995. * @param {string} prefix Can be either "eslint-plugin", "eslint-config" or "eslint-formatter"
  1996. * @returns {string} Normalized name of the package
  1997. * @private
  1998. */
  1999. function normalizePackageName(name, prefix) {
  2000. let normalizedName = name;
  2001. /**
  2002. * On Windows, name can come in with Windows slashes instead of Unix slashes.
  2003. * Normalize to Unix first to avoid errors later on.
  2004. * https://github.com/eslint/eslint/issues/5644
  2005. */
  2006. if (normalizedName.includes("\\")) {
  2007. normalizedName = normalizedName.replace(/\\/gu, "/");
  2008. }
  2009. if (normalizedName.charAt(0) === "@") {
  2010. /**
  2011. * it's a scoped package
  2012. * package name is the prefix, or just a username
  2013. */
  2014. const scopedPackageShortcutRegex = new RegExp(`^(@[^/]+)(?:/(?:${prefix})?)?$`, "u"),
  2015. scopedPackageNameRegex = new RegExp(`^${prefix}(-|$)`, "u");
  2016. if (scopedPackageShortcutRegex.test(normalizedName)) {
  2017. normalizedName = normalizedName.replace(scopedPackageShortcutRegex, `$1/${prefix}`);
  2018. } else if (!scopedPackageNameRegex.test(normalizedName.split("/")[1])) {
  2019. /**
  2020. * for scoped packages, insert the prefix after the first / unless
  2021. * the path is already @scope/eslint or @scope/eslint-xxx-yyy
  2022. */
  2023. normalizedName = normalizedName.replace(/^@([^/]+)\/(.*)$/u, `@$1/${prefix}-$2`);
  2024. }
  2025. } else if (!normalizedName.startsWith(`${prefix}-`)) {
  2026. normalizedName = `${prefix}-${normalizedName}`;
  2027. }
  2028. return normalizedName;
  2029. }
  2030. /**
  2031. * Removes the prefix from a fullname.
  2032. * @param {string} fullname The term which may have the prefix.
  2033. * @param {string} prefix The prefix to remove.
  2034. * @returns {string} The term without prefix.
  2035. */
  2036. function getShorthandName(fullname, prefix) {
  2037. if (fullname[0] === "@") {
  2038. let matchResult = new RegExp(`^(@[^/]+)/${prefix}$`, "u").exec(fullname);
  2039. if (matchResult) {
  2040. return matchResult[1];
  2041. }
  2042. matchResult = new RegExp(`^(@[^/]+)/${prefix}-(.+)$`, "u").exec(fullname);
  2043. if (matchResult) {
  2044. return `${matchResult[1]}/${matchResult[2]}`;
  2045. }
  2046. } else if (fullname.startsWith(`${prefix}-`)) {
  2047. return fullname.slice(prefix.length + 1);
  2048. }
  2049. return fullname;
  2050. }
  2051. /**
  2052. * Gets the scope (namespace) of a term.
  2053. * @param {string} term The term which may have the namespace.
  2054. * @returns {string} The namespace of the term if it has one.
  2055. */
  2056. function getNamespaceFromTerm(term) {
  2057. const match = term.match(NAMESPACE_REGEX);
  2058. return match ? match[0] : "";
  2059. }
  2060. var naming = {
  2061. __proto__: null,
  2062. normalizePackageName: normalizePackageName,
  2063. getShorthandName: getShorthandName,
  2064. getNamespaceFromTerm: getNamespaceFromTerm
  2065. };
  2066. /**
  2067. * Utility for resolving a module relative to another module
  2068. * @author Teddy Katz
  2069. */
  2070. /*
  2071. * `Module.createRequire` is added in v12.2.0. It supports URL as well.
  2072. * We only support the case where the argument is a filepath, not a URL.
  2073. */
  2074. const createRequire = Module__default["default"].createRequire;
  2075. /**
  2076. * Resolves a Node module relative to another module
  2077. * @param {string} moduleName The name of a Node module, or a path to a Node module.
  2078. * @param {string} relativeToPath An absolute path indicating the module that `moduleName` should be resolved relative to. This must be
  2079. * a file rather than a directory, but the file need not actually exist.
  2080. * @returns {string} The absolute path that would result from calling `require.resolve(moduleName)` in a file located at `relativeToPath`
  2081. */
  2082. function resolve(moduleName, relativeToPath) {
  2083. try {
  2084. return createRequire(relativeToPath).resolve(moduleName);
  2085. } catch (error) {
  2086. // This `if` block is for older Node.js than 12.0.0. We can remove this block in the future.
  2087. if (
  2088. typeof error === "object" &&
  2089. error !== null &&
  2090. error.code === "MODULE_NOT_FOUND" &&
  2091. !error.requireStack &&
  2092. error.message.includes(moduleName)
  2093. ) {
  2094. error.message += `\nRequire stack:\n- ${relativeToPath}`;
  2095. }
  2096. throw error;
  2097. }
  2098. }
  2099. var ModuleResolver = {
  2100. __proto__: null,
  2101. resolve: resolve
  2102. };
  2103. /**
  2104. * @fileoverview The factory of `ConfigArray` objects.
  2105. *
  2106. * This class provides methods to create `ConfigArray` instance.
  2107. *
  2108. * - `create(configData, options)`
  2109. * Create a `ConfigArray` instance from a config data. This is to handle CLI
  2110. * options except `--config`.
  2111. * - `loadFile(filePath, options)`
  2112. * Create a `ConfigArray` instance from a config file. This is to handle
  2113. * `--config` option. If the file was not found, throws the following error:
  2114. * - If the filename was `*.js`, a `MODULE_NOT_FOUND` error.
  2115. * - If the filename was `package.json`, an IO error or an
  2116. * `ESLINT_CONFIG_FIELD_NOT_FOUND` error.
  2117. * - Otherwise, an IO error such as `ENOENT`.
  2118. * - `loadInDirectory(directoryPath, options)`
  2119. * Create a `ConfigArray` instance from a config file which is on a given
  2120. * directory. This tries to load `.eslintrc.*` or `package.json`. If not
  2121. * found, returns an empty `ConfigArray`.
  2122. * - `loadESLintIgnore(filePath)`
  2123. * Create a `ConfigArray` instance from a config file that is `.eslintignore`
  2124. * format. This is to handle `--ignore-path` option.
  2125. * - `loadDefaultESLintIgnore()`
  2126. * Create a `ConfigArray` instance from `.eslintignore` or `package.json` in
  2127. * the current working directory.
  2128. *
  2129. * `ConfigArrayFactory` class has the responsibility that loads configuration
  2130. * files, including loading `extends`, `parser`, and `plugins`. The created
  2131. * `ConfigArray` instance has the loaded `extends`, `parser`, and `plugins`.
  2132. *
  2133. * But this class doesn't handle cascading. `CascadingConfigArrayFactory` class
  2134. * handles cascading and hierarchy.
  2135. *
  2136. * @author Toru Nagashima <https://github.com/mysticatea>
  2137. */
  2138. const require$1 = Module.createRequire(require('url').pathToFileURL(__filename).toString());
  2139. const debug$2 = debugOrig__default["default"]("eslintrc:config-array-factory");
  2140. //------------------------------------------------------------------------------
  2141. // Helpers
  2142. //------------------------------------------------------------------------------
  2143. const configFilenames = [
  2144. ".eslintrc.js",
  2145. ".eslintrc.cjs",
  2146. ".eslintrc.yaml",
  2147. ".eslintrc.yml",
  2148. ".eslintrc.json",
  2149. ".eslintrc",
  2150. "package.json"
  2151. ];
  2152. // Define types for VSCode IntelliSense.
  2153. /** @typedef {import("./shared/types").ConfigData} ConfigData */
  2154. /** @typedef {import("./shared/types").OverrideConfigData} OverrideConfigData */
  2155. /** @typedef {import("./shared/types").Parser} Parser */
  2156. /** @typedef {import("./shared/types").Plugin} Plugin */
  2157. /** @typedef {import("./shared/types").Rule} Rule */
  2158. /** @typedef {import("./config-array/config-dependency").DependentParser} DependentParser */
  2159. /** @typedef {import("./config-array/config-dependency").DependentPlugin} DependentPlugin */
  2160. /** @typedef {ConfigArray[0]} ConfigArrayElement */
  2161. /**
  2162. * @typedef {Object} ConfigArrayFactoryOptions
  2163. * @property {Map<string,Plugin>} [additionalPluginPool] The map for additional plugins.
  2164. * @property {string} [cwd] The path to the current working directory.
  2165. * @property {string} [resolvePluginsRelativeTo] A path to the directory that plugins should be resolved from. Defaults to `cwd`.
  2166. * @property {Map<string,Rule>} builtInRules The rules that are built in to ESLint.
  2167. * @property {Object} [resolver=ModuleResolver] The module resolver object.
  2168. * @property {string} eslintAllPath The path to the definitions for eslint:all.
  2169. * @property {Function} getEslintAllConfig Returns the config data for eslint:all.
  2170. * @property {string} eslintRecommendedPath The path to the definitions for eslint:recommended.
  2171. * @property {Function} getEslintRecommendedConfig Returns the config data for eslint:recommended.
  2172. */
  2173. /**
  2174. * @typedef {Object} ConfigArrayFactoryInternalSlots
  2175. * @property {Map<string,Plugin>} additionalPluginPool The map for additional plugins.
  2176. * @property {string} cwd The path to the current working directory.
  2177. * @property {string | undefined} resolvePluginsRelativeTo An absolute path the the directory that plugins should be resolved from.
  2178. * @property {Map<string,Rule>} builtInRules The rules that are built in to ESLint.
  2179. * @property {Object} [resolver=ModuleResolver] The module resolver object.
  2180. * @property {string} eslintAllPath The path to the definitions for eslint:all.
  2181. * @property {Function} getEslintAllConfig Returns the config data for eslint:all.
  2182. * @property {string} eslintRecommendedPath The path to the definitions for eslint:recommended.
  2183. * @property {Function} getEslintRecommendedConfig Returns the config data for eslint:recommended.
  2184. */
  2185. /**
  2186. * @typedef {Object} ConfigArrayFactoryLoadingContext
  2187. * @property {string} filePath The path to the current configuration.
  2188. * @property {string} matchBasePath The base path to resolve relative paths in `overrides[].files`, `overrides[].excludedFiles`, and `ignorePatterns`.
  2189. * @property {string} name The name of the current configuration.
  2190. * @property {string} pluginBasePath The base path to resolve plugins.
  2191. * @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.
  2192. */
  2193. /**
  2194. * @typedef {Object} ConfigArrayFactoryLoadingContext
  2195. * @property {string} filePath The path to the current configuration.
  2196. * @property {string} matchBasePath The base path to resolve relative paths in `overrides[].files`, `overrides[].excludedFiles`, and `ignorePatterns`.
  2197. * @property {string} name The name of the current configuration.
  2198. * @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.
  2199. */
  2200. /** @type {WeakMap<ConfigArrayFactory, ConfigArrayFactoryInternalSlots>} */
  2201. const internalSlotsMap$1 = new WeakMap();
  2202. /** @type {WeakMap<object, Plugin>} */
  2203. const normalizedPlugins = new WeakMap();
  2204. /**
  2205. * Check if a given string is a file path.
  2206. * @param {string} nameOrPath A module name or file path.
  2207. * @returns {boolean} `true` if the `nameOrPath` is a file path.
  2208. */
  2209. function isFilePath(nameOrPath) {
  2210. return (
  2211. /^\.{1,2}[/\\]/u.test(nameOrPath) ||
  2212. path__default["default"].isAbsolute(nameOrPath)
  2213. );
  2214. }
  2215. /**
  2216. * Convenience wrapper for synchronously reading file contents.
  2217. * @param {string} filePath The filename to read.
  2218. * @returns {string} The file contents, with the BOM removed.
  2219. * @private
  2220. */
  2221. function readFile(filePath) {
  2222. return fs__default["default"].readFileSync(filePath, "utf8").replace(/^\ufeff/u, "");
  2223. }
  2224. /**
  2225. * Loads a YAML configuration from a file.
  2226. * @param {string} filePath The filename to load.
  2227. * @returns {ConfigData} The configuration object from the file.
  2228. * @throws {Error} If the file cannot be read.
  2229. * @private
  2230. */
  2231. function loadYAMLConfigFile(filePath) {
  2232. debug$2(`Loading YAML config file: ${filePath}`);
  2233. // lazy load YAML to improve performance when not used
  2234. const yaml = require$1("js-yaml");
  2235. try {
  2236. // empty YAML file can be null, so always use
  2237. return yaml.load(readFile(filePath)) || {};
  2238. } catch (e) {
  2239. debug$2(`Error reading YAML file: ${filePath}`);
  2240. e.message = `Cannot read config file: ${filePath}\nError: ${e.message}`;
  2241. throw e;
  2242. }
  2243. }
  2244. /**
  2245. * Loads a JSON configuration from a file.
  2246. * @param {string} filePath The filename to load.
  2247. * @returns {ConfigData} The configuration object from the file.
  2248. * @throws {Error} If the file cannot be read.
  2249. * @private
  2250. */
  2251. function loadJSONConfigFile(filePath) {
  2252. debug$2(`Loading JSON config file: ${filePath}`);
  2253. try {
  2254. return JSON.parse(stripComments__default["default"](readFile(filePath)));
  2255. } catch (e) {
  2256. debug$2(`Error reading JSON file: ${filePath}`);
  2257. e.message = `Cannot read config file: ${filePath}\nError: ${e.message}`;
  2258. e.messageTemplate = "failed-to-read-json";
  2259. e.messageData = {
  2260. path: filePath,
  2261. message: e.message
  2262. };
  2263. throw e;
  2264. }
  2265. }
  2266. /**
  2267. * Loads a legacy (.eslintrc) configuration from a file.
  2268. * @param {string} filePath The filename to load.
  2269. * @returns {ConfigData} The configuration object from the file.
  2270. * @throws {Error} If the file cannot be read.
  2271. * @private
  2272. */
  2273. function loadLegacyConfigFile(filePath) {
  2274. debug$2(`Loading legacy config file: ${filePath}`);
  2275. // lazy load YAML to improve performance when not used
  2276. const yaml = require$1("js-yaml");
  2277. try {
  2278. return yaml.load(stripComments__default["default"](readFile(filePath))) || /* istanbul ignore next */ {};
  2279. } catch (e) {
  2280. debug$2("Error reading YAML file: %s\n%o", filePath, e);
  2281. e.message = `Cannot read config file: ${filePath}\nError: ${e.message}`;
  2282. throw e;
  2283. }
  2284. }
  2285. /**
  2286. * Loads a JavaScript configuration from a file.
  2287. * @param {string} filePath The filename to load.
  2288. * @returns {ConfigData} The configuration object from the file.
  2289. * @throws {Error} If the file cannot be read.
  2290. * @private
  2291. */
  2292. function loadJSConfigFile(filePath) {
  2293. debug$2(`Loading JS config file: ${filePath}`);
  2294. try {
  2295. return importFresh__default["default"](filePath);
  2296. } catch (e) {
  2297. debug$2(`Error reading JavaScript file: ${filePath}`);
  2298. e.message = `Cannot read config file: ${filePath}\nError: ${e.message}`;
  2299. throw e;
  2300. }
  2301. }
  2302. /**
  2303. * Loads a configuration from a package.json file.
  2304. * @param {string} filePath The filename to load.
  2305. * @returns {ConfigData} The configuration object from the file.
  2306. * @throws {Error} If the file cannot be read.
  2307. * @private
  2308. */
  2309. function loadPackageJSONConfigFile(filePath) {
  2310. debug$2(`Loading package.json config file: ${filePath}`);
  2311. try {
  2312. const packageData = loadJSONConfigFile(filePath);
  2313. if (!Object.hasOwnProperty.call(packageData, "eslintConfig")) {
  2314. throw Object.assign(
  2315. new Error("package.json file doesn't have 'eslintConfig' field."),
  2316. { code: "ESLINT_CONFIG_FIELD_NOT_FOUND" }
  2317. );
  2318. }
  2319. return packageData.eslintConfig;
  2320. } catch (e) {
  2321. debug$2(`Error reading package.json file: ${filePath}`);
  2322. e.message = `Cannot read config file: ${filePath}\nError: ${e.message}`;
  2323. throw e;
  2324. }
  2325. }
  2326. /**
  2327. * Loads a `.eslintignore` from a file.
  2328. * @param {string} filePath The filename to load.
  2329. * @returns {string[]} The ignore patterns from the file.
  2330. * @private
  2331. */
  2332. function loadESLintIgnoreFile(filePath) {
  2333. debug$2(`Loading .eslintignore file: ${filePath}`);
  2334. try {
  2335. return readFile(filePath)
  2336. .split(/\r?\n/gu)
  2337. .filter(line => line.trim() !== "" && !line.startsWith("#"));
  2338. } catch (e) {
  2339. debug$2(`Error reading .eslintignore file: ${filePath}`);
  2340. e.message = `Cannot read .eslintignore file: ${filePath}\nError: ${e.message}`;
  2341. throw e;
  2342. }
  2343. }
  2344. /**
  2345. * Creates an error to notify about a missing config to extend from.
  2346. * @param {string} configName The name of the missing config.
  2347. * @param {string} importerName The name of the config that imported the missing config
  2348. * @param {string} messageTemplate The text template to source error strings from.
  2349. * @returns {Error} The error object to throw
  2350. * @private
  2351. */
  2352. function configInvalidError(configName, importerName, messageTemplate) {
  2353. return Object.assign(
  2354. new Error(`Failed to load config "${configName}" to extend from.`),
  2355. {
  2356. messageTemplate,
  2357. messageData: { configName, importerName }
  2358. }
  2359. );
  2360. }
  2361. /**
  2362. * Loads a configuration file regardless of the source. Inspects the file path
  2363. * to determine the correctly way to load the config file.
  2364. * @param {string} filePath The path to the configuration.
  2365. * @returns {ConfigData|null} The configuration information.
  2366. * @private
  2367. */
  2368. function loadConfigFile(filePath) {
  2369. switch (path__default["default"].extname(filePath)) {
  2370. case ".js":
  2371. case ".cjs":
  2372. return loadJSConfigFile(filePath);
  2373. case ".json":
  2374. if (path__default["default"].basename(filePath) === "package.json") {
  2375. return loadPackageJSONConfigFile(filePath);
  2376. }
  2377. return loadJSONConfigFile(filePath);
  2378. case ".yaml":
  2379. case ".yml":
  2380. return loadYAMLConfigFile(filePath);
  2381. default:
  2382. return loadLegacyConfigFile(filePath);
  2383. }
  2384. }
  2385. /**
  2386. * Write debug log.
  2387. * @param {string} request The requested module name.
  2388. * @param {string} relativeTo The file path to resolve the request relative to.
  2389. * @param {string} filePath The resolved file path.
  2390. * @returns {void}
  2391. */
  2392. function writeDebugLogForLoading(request, relativeTo, filePath) {
  2393. /* istanbul ignore next */
  2394. if (debug$2.enabled) {
  2395. let nameAndVersion = null;
  2396. try {
  2397. const packageJsonPath = resolve(
  2398. `${request}/package.json`,
  2399. relativeTo
  2400. );
  2401. const { version = "unknown" } = require$1(packageJsonPath);
  2402. nameAndVersion = `${request}@${version}`;
  2403. } catch (error) {
  2404. debug$2("package.json was not found:", error.message);
  2405. nameAndVersion = request;
  2406. }
  2407. debug$2("Loaded: %s (%s)", nameAndVersion, filePath);
  2408. }
  2409. }
  2410. /**
  2411. * Create a new context with default values.
  2412. * @param {ConfigArrayFactoryInternalSlots} slots The internal slots.
  2413. * @param {"config" | "ignore" | "implicit-processor" | undefined} providedType The type of the current configuration. Default is `"config"`.
  2414. * @param {string | undefined} providedName The name of the current configuration. Default is the relative path from `cwd` to `filePath`.
  2415. * @param {string | undefined} providedFilePath The path to the current configuration. Default is empty string.
  2416. * @param {string | undefined} providedMatchBasePath The type of the current configuration. Default is the directory of `filePath` or `cwd`.
  2417. * @returns {ConfigArrayFactoryLoadingContext} The created context.
  2418. */
  2419. function createContext(
  2420. { cwd, resolvePluginsRelativeTo },
  2421. providedType,
  2422. providedName,
  2423. providedFilePath,
  2424. providedMatchBasePath
  2425. ) {
  2426. const filePath = providedFilePath
  2427. ? path__default["default"].resolve(cwd, providedFilePath)
  2428. : "";
  2429. const matchBasePath =
  2430. (providedMatchBasePath && path__default["default"].resolve(cwd, providedMatchBasePath)) ||
  2431. (filePath && path__default["default"].dirname(filePath)) ||
  2432. cwd;
  2433. const name =
  2434. providedName ||
  2435. (filePath && path__default["default"].relative(cwd, filePath)) ||
  2436. "";
  2437. const pluginBasePath =
  2438. resolvePluginsRelativeTo ||
  2439. (filePath && path__default["default"].dirname(filePath)) ||
  2440. cwd;
  2441. const type = providedType || "config";
  2442. return { filePath, matchBasePath, name, pluginBasePath, type };
  2443. }
  2444. /**
  2445. * Normalize a given plugin.
  2446. * - Ensure the object to have four properties: configs, environments, processors, and rules.
  2447. * - Ensure the object to not have other properties.
  2448. * @param {Plugin} plugin The plugin to normalize.
  2449. * @returns {Plugin} The normalized plugin.
  2450. */
  2451. function normalizePlugin(plugin) {
  2452. // first check the cache
  2453. let normalizedPlugin = normalizedPlugins.get(plugin);
  2454. if (normalizedPlugin) {
  2455. return normalizedPlugin;
  2456. }
  2457. normalizedPlugin = {
  2458. configs: plugin.configs || {},
  2459. environments: plugin.environments || {},
  2460. processors: plugin.processors || {},
  2461. rules: plugin.rules || {}
  2462. };
  2463. // save the reference for later
  2464. normalizedPlugins.set(plugin, normalizedPlugin);
  2465. return normalizedPlugin;
  2466. }
  2467. //------------------------------------------------------------------------------
  2468. // Public Interface
  2469. //------------------------------------------------------------------------------
  2470. /**
  2471. * The factory of `ConfigArray` objects.
  2472. */
  2473. class ConfigArrayFactory {
  2474. /**
  2475. * Initialize this instance.
  2476. * @param {ConfigArrayFactoryOptions} [options] The map for additional plugins.
  2477. */
  2478. constructor({
  2479. additionalPluginPool = new Map(),
  2480. cwd = process.cwd(),
  2481. resolvePluginsRelativeTo,
  2482. builtInRules,
  2483. resolver = ModuleResolver,
  2484. eslintAllPath,
  2485. getEslintAllConfig,
  2486. eslintRecommendedPath,
  2487. getEslintRecommendedConfig
  2488. } = {}) {
  2489. internalSlotsMap$1.set(this, {
  2490. additionalPluginPool,
  2491. cwd,
  2492. resolvePluginsRelativeTo:
  2493. resolvePluginsRelativeTo &&
  2494. path__default["default"].resolve(cwd, resolvePluginsRelativeTo),
  2495. builtInRules,
  2496. resolver,
  2497. eslintAllPath,
  2498. getEslintAllConfig,
  2499. eslintRecommendedPath,
  2500. getEslintRecommendedConfig
  2501. });
  2502. }
  2503. /**
  2504. * Create `ConfigArray` instance from a config data.
  2505. * @param {ConfigData|null} configData The config data to create.
  2506. * @param {Object} [options] The options.
  2507. * @param {string} [options.basePath] The base path to resolve relative paths in `overrides[].files`, `overrides[].excludedFiles`, and `ignorePatterns`.
  2508. * @param {string} [options.filePath] The path to this config data.
  2509. * @param {string} [options.name] The config name.
  2510. * @returns {ConfigArray} Loaded config.
  2511. */
  2512. create(configData, { basePath, filePath, name } = {}) {
  2513. if (!configData) {
  2514. return new ConfigArray();
  2515. }
  2516. const slots = internalSlotsMap$1.get(this);
  2517. const ctx = createContext(slots, "config", name, filePath, basePath);
  2518. const elements = this._normalizeConfigData(configData, ctx);
  2519. return new ConfigArray(...elements);
  2520. }
  2521. /**
  2522. * Load a config file.
  2523. * @param {string} filePath The path to a config file.
  2524. * @param {Object} [options] The options.
  2525. * @param {string} [options.basePath] The base path to resolve relative paths in `overrides[].files`, `overrides[].excludedFiles`, and `ignorePatterns`.
  2526. * @param {string} [options.name] The config name.
  2527. * @returns {ConfigArray} Loaded config.
  2528. */
  2529. loadFile(filePath, { basePath, name } = {}) {
  2530. const slots = internalSlotsMap$1.get(this);
  2531. const ctx = createContext(slots, "config", name, filePath, basePath);
  2532. return new ConfigArray(...this._loadConfigData(ctx));
  2533. }
  2534. /**
  2535. * Load the config file on a given directory if exists.
  2536. * @param {string} directoryPath The path to a directory.
  2537. * @param {Object} [options] The options.
  2538. * @param {string} [options.basePath] The base path to resolve relative paths in `overrides[].files`, `overrides[].excludedFiles`, and `ignorePatterns`.
  2539. * @param {string} [options.name] The config name.
  2540. * @returns {ConfigArray} Loaded config. An empty `ConfigArray` if any config doesn't exist.
  2541. */
  2542. loadInDirectory(directoryPath, { basePath, name } = {}) {
  2543. const slots = internalSlotsMap$1.get(this);
  2544. for (const filename of configFilenames) {
  2545. const ctx = createContext(
  2546. slots,
  2547. "config",
  2548. name,
  2549. path__default["default"].join(directoryPath, filename),
  2550. basePath
  2551. );
  2552. if (fs__default["default"].existsSync(ctx.filePath) && fs__default["default"].statSync(ctx.filePath).isFile()) {
  2553. let configData;
  2554. try {
  2555. configData = loadConfigFile(ctx.filePath);
  2556. } catch (error) {
  2557. if (!error || error.code !== "ESLINT_CONFIG_FIELD_NOT_FOUND") {
  2558. throw error;
  2559. }
  2560. }
  2561. if (configData) {
  2562. debug$2(`Config file found: ${ctx.filePath}`);
  2563. return new ConfigArray(
  2564. ...this._normalizeConfigData(configData, ctx)
  2565. );
  2566. }
  2567. }
  2568. }
  2569. debug$2(`Config file not found on ${directoryPath}`);
  2570. return new ConfigArray();
  2571. }
  2572. /**
  2573. * Check if a config file on a given directory exists or not.
  2574. * @param {string} directoryPath The path to a directory.
  2575. * @returns {string | null} The path to the found config file. If not found then null.
  2576. */
  2577. static getPathToConfigFileInDirectory(directoryPath) {
  2578. for (const filename of configFilenames) {
  2579. const filePath = path__default["default"].join(directoryPath, filename);
  2580. if (fs__default["default"].existsSync(filePath)) {
  2581. if (filename === "package.json") {
  2582. try {
  2583. loadPackageJSONConfigFile(filePath);
  2584. return filePath;
  2585. } catch { /* ignore */ }
  2586. } else {
  2587. return filePath;
  2588. }
  2589. }
  2590. }
  2591. return null;
  2592. }
  2593. /**
  2594. * Load `.eslintignore` file.
  2595. * @param {string} filePath The path to a `.eslintignore` file to load.
  2596. * @returns {ConfigArray} Loaded config. An empty `ConfigArray` if any config doesn't exist.
  2597. */
  2598. loadESLintIgnore(filePath) {
  2599. const slots = internalSlotsMap$1.get(this);
  2600. const ctx = createContext(
  2601. slots,
  2602. "ignore",
  2603. void 0,
  2604. filePath,
  2605. slots.cwd
  2606. );
  2607. const ignorePatterns = loadESLintIgnoreFile(ctx.filePath);
  2608. return new ConfigArray(
  2609. ...this._normalizeESLintIgnoreData(ignorePatterns, ctx)
  2610. );
  2611. }
  2612. /**
  2613. * Load `.eslintignore` file in the current working directory.
  2614. * @returns {ConfigArray} Loaded config. An empty `ConfigArray` if any config doesn't exist.
  2615. */
  2616. loadDefaultESLintIgnore() {
  2617. const slots = internalSlotsMap$1.get(this);
  2618. const eslintIgnorePath = path__default["default"].resolve(slots.cwd, ".eslintignore");
  2619. const packageJsonPath = path__default["default"].resolve(slots.cwd, "package.json");
  2620. if (fs__default["default"].existsSync(eslintIgnorePath)) {
  2621. return this.loadESLintIgnore(eslintIgnorePath);
  2622. }
  2623. if (fs__default["default"].existsSync(packageJsonPath)) {
  2624. const data = loadJSONConfigFile(packageJsonPath);
  2625. if (Object.hasOwnProperty.call(data, "eslintIgnore")) {
  2626. if (!Array.isArray(data.eslintIgnore)) {
  2627. throw new Error("Package.json eslintIgnore property requires an array of paths");
  2628. }
  2629. const ctx = createContext(
  2630. slots,
  2631. "ignore",
  2632. "eslintIgnore in package.json",
  2633. packageJsonPath,
  2634. slots.cwd
  2635. );
  2636. return new ConfigArray(
  2637. ...this._normalizeESLintIgnoreData(data.eslintIgnore, ctx)
  2638. );
  2639. }
  2640. }
  2641. return new ConfigArray();
  2642. }
  2643. /**
  2644. * Load a given config file.
  2645. * @param {ConfigArrayFactoryLoadingContext} ctx The loading context.
  2646. * @returns {IterableIterator<ConfigArrayElement>} Loaded config.
  2647. * @private
  2648. */
  2649. _loadConfigData(ctx) {
  2650. return this._normalizeConfigData(loadConfigFile(ctx.filePath), ctx);
  2651. }
  2652. /**
  2653. * Normalize a given `.eslintignore` data to config array elements.
  2654. * @param {string[]} ignorePatterns The patterns to ignore files.
  2655. * @param {ConfigArrayFactoryLoadingContext} ctx The loading context.
  2656. * @returns {IterableIterator<ConfigArrayElement>} The normalized config.
  2657. * @private
  2658. */
  2659. *_normalizeESLintIgnoreData(ignorePatterns, ctx) {
  2660. const elements = this._normalizeObjectConfigData(
  2661. { ignorePatterns },
  2662. ctx
  2663. );
  2664. // Set `ignorePattern.loose` flag for backward compatibility.
  2665. for (const element of elements) {
  2666. if (element.ignorePattern) {
  2667. element.ignorePattern.loose = true;
  2668. }
  2669. yield element;
  2670. }
  2671. }
  2672. /**
  2673. * Normalize a given config to an array.
  2674. * @param {ConfigData} configData The config data to normalize.
  2675. * @param {ConfigArrayFactoryLoadingContext} ctx The loading context.
  2676. * @returns {IterableIterator<ConfigArrayElement>} The normalized config.
  2677. * @private
  2678. */
  2679. _normalizeConfigData(configData, ctx) {
  2680. const validator = new ConfigValidator();
  2681. validator.validateConfigSchema(configData, ctx.name || ctx.filePath);
  2682. return this._normalizeObjectConfigData(configData, ctx);
  2683. }
  2684. /**
  2685. * Normalize a given config to an array.
  2686. * @param {ConfigData|OverrideConfigData} configData The config data to normalize.
  2687. * @param {ConfigArrayFactoryLoadingContext} ctx The loading context.
  2688. * @returns {IterableIterator<ConfigArrayElement>} The normalized config.
  2689. * @private
  2690. */
  2691. *_normalizeObjectConfigData(configData, ctx) {
  2692. const { files, excludedFiles, ...configBody } = configData;
  2693. const criteria = OverrideTester.create(
  2694. files,
  2695. excludedFiles,
  2696. ctx.matchBasePath
  2697. );
  2698. const elements = this._normalizeObjectConfigDataBody(configBody, ctx);
  2699. // Apply the criteria to every element.
  2700. for (const element of elements) {
  2701. /*
  2702. * Merge the criteria.
  2703. * This is for the `overrides` entries that came from the
  2704. * configurations of `overrides[].extends`.
  2705. */
  2706. element.criteria = OverrideTester.and(criteria, element.criteria);
  2707. /*
  2708. * Remove `root` property to ignore `root` settings which came from
  2709. * `extends` in `overrides`.
  2710. */
  2711. if (element.criteria) {
  2712. element.root = void 0;
  2713. }
  2714. yield element;
  2715. }
  2716. }
  2717. /**
  2718. * Normalize a given config to an array.
  2719. * @param {ConfigData} configData The config data to normalize.
  2720. * @param {ConfigArrayFactoryLoadingContext} ctx The loading context.
  2721. * @returns {IterableIterator<ConfigArrayElement>} The normalized config.
  2722. * @private
  2723. */
  2724. *_normalizeObjectConfigDataBody(
  2725. {
  2726. env,
  2727. extends: extend,
  2728. globals,
  2729. ignorePatterns,
  2730. noInlineConfig,
  2731. parser: parserName,
  2732. parserOptions,
  2733. plugins: pluginList,
  2734. processor,
  2735. reportUnusedDisableDirectives,
  2736. root,
  2737. rules,
  2738. settings,
  2739. overrides: overrideList = []
  2740. },
  2741. ctx
  2742. ) {
  2743. const extendList = Array.isArray(extend) ? extend : [extend];
  2744. const ignorePattern = ignorePatterns && new IgnorePattern(
  2745. Array.isArray(ignorePatterns) ? ignorePatterns : [ignorePatterns],
  2746. ctx.matchBasePath
  2747. );
  2748. // Flatten `extends`.
  2749. for (const extendName of extendList.filter(Boolean)) {
  2750. yield* this._loadExtends(extendName, ctx);
  2751. }
  2752. // Load parser & plugins.
  2753. const parser = parserName && this._loadParser(parserName, ctx);
  2754. const plugins = pluginList && this._loadPlugins(pluginList, ctx);
  2755. // Yield pseudo config data for file extension processors.
  2756. if (plugins) {
  2757. yield* this._takeFileExtensionProcessors(plugins, ctx);
  2758. }
  2759. // Yield the config data except `extends` and `overrides`.
  2760. yield {
  2761. // Debug information.
  2762. type: ctx.type,
  2763. name: ctx.name,
  2764. filePath: ctx.filePath,
  2765. // Config data.
  2766. criteria: null,
  2767. env,
  2768. globals,
  2769. ignorePattern,
  2770. noInlineConfig,
  2771. parser,
  2772. parserOptions,
  2773. plugins,
  2774. processor,
  2775. reportUnusedDisableDirectives,
  2776. root,
  2777. rules,
  2778. settings
  2779. };
  2780. // Flatten `overries`.
  2781. for (let i = 0; i < overrideList.length; ++i) {
  2782. yield* this._normalizeObjectConfigData(
  2783. overrideList[i],
  2784. { ...ctx, name: `${ctx.name}#overrides[${i}]` }
  2785. );
  2786. }
  2787. }
  2788. /**
  2789. * Load configs of an element in `extends`.
  2790. * @param {string} extendName The name of a base config.
  2791. * @param {ConfigArrayFactoryLoadingContext} ctx The loading context.
  2792. * @returns {IterableIterator<ConfigArrayElement>} The normalized config.
  2793. * @private
  2794. */
  2795. _loadExtends(extendName, ctx) {
  2796. debug$2("Loading {extends:%j} relative to %s", extendName, ctx.filePath);
  2797. try {
  2798. if (extendName.startsWith("eslint:")) {
  2799. return this._loadExtendedBuiltInConfig(extendName, ctx);
  2800. }
  2801. if (extendName.startsWith("plugin:")) {
  2802. return this._loadExtendedPluginConfig(extendName, ctx);
  2803. }
  2804. return this._loadExtendedShareableConfig(extendName, ctx);
  2805. } catch (error) {
  2806. error.message += `\nReferenced from: ${ctx.filePath || ctx.name}`;
  2807. throw error;
  2808. }
  2809. }
  2810. /**
  2811. * Load configs of an element in `extends`.
  2812. * @param {string} extendName The name of a base config.
  2813. * @param {ConfigArrayFactoryLoadingContext} ctx The loading context.
  2814. * @returns {IterableIterator<ConfigArrayElement>} The normalized config.
  2815. * @private
  2816. */
  2817. _loadExtendedBuiltInConfig(extendName, ctx) {
  2818. const {
  2819. eslintAllPath,
  2820. getEslintAllConfig,
  2821. eslintRecommendedPath,
  2822. getEslintRecommendedConfig
  2823. } = internalSlotsMap$1.get(this);
  2824. if (extendName === "eslint:recommended") {
  2825. const name = `${ctx.name} » ${extendName}`;
  2826. if (getEslintRecommendedConfig) {
  2827. if (typeof getEslintRecommendedConfig !== "function") {
  2828. throw new Error(`getEslintRecommendedConfig must be a function instead of '${getEslintRecommendedConfig}'`);
  2829. }
  2830. return this._normalizeConfigData(getEslintRecommendedConfig(), { ...ctx, name, filePath: "" });
  2831. }
  2832. return this._loadConfigData({
  2833. ...ctx,
  2834. name,
  2835. filePath: eslintRecommendedPath
  2836. });
  2837. }
  2838. if (extendName === "eslint:all") {
  2839. const name = `${ctx.name} » ${extendName}`;
  2840. if (getEslintAllConfig) {
  2841. if (typeof getEslintAllConfig !== "function") {
  2842. throw new Error(`getEslintAllConfig must be a function instead of '${getEslintAllConfig}'`);
  2843. }
  2844. return this._normalizeConfigData(getEslintAllConfig(), { ...ctx, name, filePath: "" });
  2845. }
  2846. return this._loadConfigData({
  2847. ...ctx,
  2848. name,
  2849. filePath: eslintAllPath
  2850. });
  2851. }
  2852. throw configInvalidError(extendName, ctx.name, "extend-config-missing");
  2853. }
  2854. /**
  2855. * Load configs of an element in `extends`.
  2856. * @param {string} extendName The name of a base config.
  2857. * @param {ConfigArrayFactoryLoadingContext} ctx The loading context.
  2858. * @returns {IterableIterator<ConfigArrayElement>} The normalized config.
  2859. * @private
  2860. */
  2861. _loadExtendedPluginConfig(extendName, ctx) {
  2862. const slashIndex = extendName.lastIndexOf("/");
  2863. if (slashIndex === -1) {
  2864. throw configInvalidError(extendName, ctx.filePath, "plugin-invalid");
  2865. }
  2866. const pluginName = extendName.slice("plugin:".length, slashIndex);
  2867. const configName = extendName.slice(slashIndex + 1);
  2868. if (isFilePath(pluginName)) {
  2869. throw new Error("'extends' cannot use a file path for plugins.");
  2870. }
  2871. const plugin = this._loadPlugin(pluginName, ctx);
  2872. const configData =
  2873. plugin.definition &&
  2874. plugin.definition.configs[configName];
  2875. if (configData) {
  2876. return this._normalizeConfigData(configData, {
  2877. ...ctx,
  2878. filePath: plugin.filePath || ctx.filePath,
  2879. name: `${ctx.name} » plugin:${plugin.id}/${configName}`
  2880. });
  2881. }
  2882. throw plugin.error || configInvalidError(extendName, ctx.filePath, "extend-config-missing");
  2883. }
  2884. /**
  2885. * Load configs of an element in `extends`.
  2886. * @param {string} extendName The name of a base config.
  2887. * @param {ConfigArrayFactoryLoadingContext} ctx The loading context.
  2888. * @returns {IterableIterator<ConfigArrayElement>} The normalized config.
  2889. * @private
  2890. */
  2891. _loadExtendedShareableConfig(extendName, ctx) {
  2892. const { cwd, resolver } = internalSlotsMap$1.get(this);
  2893. const relativeTo = ctx.filePath || path__default["default"].join(cwd, "__placeholder__.js");
  2894. let request;
  2895. if (isFilePath(extendName)) {
  2896. request = extendName;
  2897. } else if (extendName.startsWith(".")) {
  2898. request = `./${extendName}`; // For backward compatibility. A ton of tests depended on this behavior.
  2899. } else {
  2900. request = normalizePackageName(
  2901. extendName,
  2902. "eslint-config"
  2903. );
  2904. }
  2905. let filePath;
  2906. try {
  2907. filePath = resolver.resolve(request, relativeTo);
  2908. } catch (error) {
  2909. /* istanbul ignore else */
  2910. if (error && error.code === "MODULE_NOT_FOUND") {
  2911. throw configInvalidError(extendName, ctx.filePath, "extend-config-missing");
  2912. }
  2913. throw error;
  2914. }
  2915. writeDebugLogForLoading(request, relativeTo, filePath);
  2916. return this._loadConfigData({
  2917. ...ctx,
  2918. filePath,
  2919. name: `${ctx.name} » ${request}`
  2920. });
  2921. }
  2922. /**
  2923. * Load given plugins.
  2924. * @param {string[]} names The plugin names to load.
  2925. * @param {ConfigArrayFactoryLoadingContext} ctx The loading context.
  2926. * @returns {Record<string,DependentPlugin>} The loaded parser.
  2927. * @private
  2928. */
  2929. _loadPlugins(names, ctx) {
  2930. return names.reduce((map, name) => {
  2931. if (isFilePath(name)) {
  2932. throw new Error("Plugins array cannot includes file paths.");
  2933. }
  2934. const plugin = this._loadPlugin(name, ctx);
  2935. map[plugin.id] = plugin;
  2936. return map;
  2937. }, {});
  2938. }
  2939. /**
  2940. * Load a given parser.
  2941. * @param {string} nameOrPath The package name or the path to a parser file.
  2942. * @param {ConfigArrayFactoryLoadingContext} ctx The loading context.
  2943. * @returns {DependentParser} The loaded parser.
  2944. */
  2945. _loadParser(nameOrPath, ctx) {
  2946. debug$2("Loading parser %j from %s", nameOrPath, ctx.filePath);
  2947. const { cwd, resolver } = internalSlotsMap$1.get(this);
  2948. const relativeTo = ctx.filePath || path__default["default"].join(cwd, "__placeholder__.js");
  2949. try {
  2950. const filePath = resolver.resolve(nameOrPath, relativeTo);
  2951. writeDebugLogForLoading(nameOrPath, relativeTo, filePath);
  2952. return new ConfigDependency({
  2953. definition: require$1(filePath),
  2954. filePath,
  2955. id: nameOrPath,
  2956. importerName: ctx.name,
  2957. importerPath: ctx.filePath
  2958. });
  2959. } catch (error) {
  2960. // If the parser name is "espree", load the espree of ESLint.
  2961. if (nameOrPath === "espree") {
  2962. debug$2("Fallback espree.");
  2963. return new ConfigDependency({
  2964. definition: require$1("espree"),
  2965. filePath: require$1.resolve("espree"),
  2966. id: nameOrPath,
  2967. importerName: ctx.name,
  2968. importerPath: ctx.filePath
  2969. });
  2970. }
  2971. debug$2("Failed to load parser '%s' declared in '%s'.", nameOrPath, ctx.name);
  2972. error.message = `Failed to load parser '${nameOrPath}' declared in '${ctx.name}': ${error.message}`;
  2973. return new ConfigDependency({
  2974. error,
  2975. id: nameOrPath,
  2976. importerName: ctx.name,
  2977. importerPath: ctx.filePath
  2978. });
  2979. }
  2980. }
  2981. /**
  2982. * Load a given plugin.
  2983. * @param {string} name The plugin name to load.
  2984. * @param {ConfigArrayFactoryLoadingContext} ctx The loading context.
  2985. * @returns {DependentPlugin} The loaded plugin.
  2986. * @private
  2987. */
  2988. _loadPlugin(name, ctx) {
  2989. debug$2("Loading plugin %j from %s", name, ctx.filePath);
  2990. const { additionalPluginPool, resolver } = internalSlotsMap$1.get(this);
  2991. const request = normalizePackageName(name, "eslint-plugin");
  2992. const id = getShorthandName(request, "eslint-plugin");
  2993. const relativeTo = path__default["default"].join(ctx.pluginBasePath, "__placeholder__.js");
  2994. if (name.match(/\s+/u)) {
  2995. const error = Object.assign(
  2996. new Error(`Whitespace found in plugin name '${name}'`),
  2997. {
  2998. messageTemplate: "whitespace-found",
  2999. messageData: { pluginName: request }
  3000. }
  3001. );
  3002. return new ConfigDependency({
  3003. error,
  3004. id,
  3005. importerName: ctx.name,
  3006. importerPath: ctx.filePath
  3007. });
  3008. }
  3009. // Check for additional pool.
  3010. const plugin =
  3011. additionalPluginPool.get(request) ||
  3012. additionalPluginPool.get(id);
  3013. if (plugin) {
  3014. return new ConfigDependency({
  3015. definition: normalizePlugin(plugin),
  3016. original: plugin,
  3017. filePath: "", // It's unknown where the plugin came from.
  3018. id,
  3019. importerName: ctx.name,
  3020. importerPath: ctx.filePath
  3021. });
  3022. }
  3023. let filePath;
  3024. let error;
  3025. try {
  3026. filePath = resolver.resolve(request, relativeTo);
  3027. } catch (resolveError) {
  3028. error = resolveError;
  3029. /* istanbul ignore else */
  3030. if (error && error.code === "MODULE_NOT_FOUND") {
  3031. error.messageTemplate = "plugin-missing";
  3032. error.messageData = {
  3033. pluginName: request,
  3034. resolvePluginsRelativeTo: ctx.pluginBasePath,
  3035. importerName: ctx.name
  3036. };
  3037. }
  3038. }
  3039. if (filePath) {
  3040. try {
  3041. writeDebugLogForLoading(request, relativeTo, filePath);
  3042. const startTime = Date.now();
  3043. const pluginDefinition = require$1(filePath);
  3044. debug$2(`Plugin ${filePath} loaded in: ${Date.now() - startTime}ms`);
  3045. return new ConfigDependency({
  3046. definition: normalizePlugin(pluginDefinition),
  3047. original: pluginDefinition,
  3048. filePath,
  3049. id,
  3050. importerName: ctx.name,
  3051. importerPath: ctx.filePath
  3052. });
  3053. } catch (loadError) {
  3054. error = loadError;
  3055. }
  3056. }
  3057. debug$2("Failed to load plugin '%s' declared in '%s'.", name, ctx.name);
  3058. error.message = `Failed to load plugin '${name}' declared in '${ctx.name}': ${error.message}`;
  3059. return new ConfigDependency({
  3060. error,
  3061. id,
  3062. importerName: ctx.name,
  3063. importerPath: ctx.filePath
  3064. });
  3065. }
  3066. /**
  3067. * Take file expression processors as config array elements.
  3068. * @param {Record<string,DependentPlugin>} plugins The plugin definitions.
  3069. * @param {ConfigArrayFactoryLoadingContext} ctx The loading context.
  3070. * @returns {IterableIterator<ConfigArrayElement>} The config array elements of file expression processors.
  3071. * @private
  3072. */
  3073. *_takeFileExtensionProcessors(plugins, ctx) {
  3074. for (const pluginId of Object.keys(plugins)) {
  3075. const processors =
  3076. plugins[pluginId] &&
  3077. plugins[pluginId].definition &&
  3078. plugins[pluginId].definition.processors;
  3079. if (!processors) {
  3080. continue;
  3081. }
  3082. for (const processorId of Object.keys(processors)) {
  3083. if (processorId.startsWith(".")) {
  3084. yield* this._normalizeObjectConfigData(
  3085. {
  3086. files: [`*${processorId}`],
  3087. processor: `${pluginId}/${processorId}`
  3088. },
  3089. {
  3090. ...ctx,
  3091. type: "implicit-processor",
  3092. name: `${ctx.name}#processors["${pluginId}/${processorId}"]`
  3093. }
  3094. );
  3095. }
  3096. }
  3097. }
  3098. }
  3099. }
  3100. /**
  3101. * @fileoverview `CascadingConfigArrayFactory` class.
  3102. *
  3103. * `CascadingConfigArrayFactory` class has a responsibility:
  3104. *
  3105. * 1. Handles cascading of config files.
  3106. *
  3107. * It provides two methods:
  3108. *
  3109. * - `getConfigArrayForFile(filePath)`
  3110. * Get the corresponded configuration of a given file. This method doesn't
  3111. * throw even if the given file didn't exist.
  3112. * - `clearCache()`
  3113. * Clear the internal cache. You have to call this method when
  3114. * `additionalPluginPool` was updated if `baseConfig` or `cliConfig` depends
  3115. * on the additional plugins. (`CLIEngine#addPlugin()` method calls this.)
  3116. *
  3117. * @author Toru Nagashima <https://github.com/mysticatea>
  3118. */
  3119. const debug$1 = debugOrig__default["default"]("eslintrc:cascading-config-array-factory");
  3120. //------------------------------------------------------------------------------
  3121. // Helpers
  3122. //------------------------------------------------------------------------------
  3123. // Define types for VSCode IntelliSense.
  3124. /** @typedef {import("./shared/types").ConfigData} ConfigData */
  3125. /** @typedef {import("./shared/types").Parser} Parser */
  3126. /** @typedef {import("./shared/types").Plugin} Plugin */
  3127. /** @typedef {import("./shared/types").Rule} Rule */
  3128. /** @typedef {ReturnType<ConfigArrayFactory["create"]>} ConfigArray */
  3129. /**
  3130. * @typedef {Object} CascadingConfigArrayFactoryOptions
  3131. * @property {Map<string,Plugin>} [additionalPluginPool] The map for additional plugins.
  3132. * @property {ConfigData} [baseConfig] The config by `baseConfig` option.
  3133. * @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.
  3134. * @property {string} [cwd] The base directory to start lookup.
  3135. * @property {string} [ignorePath] The path to the alternative file of `.eslintignore`.
  3136. * @property {string[]} [rulePaths] The value of `--rulesdir` option.
  3137. * @property {string} [specificConfigPath] The value of `--config` option.
  3138. * @property {boolean} [useEslintrc] if `false` then it doesn't load config files.
  3139. * @property {Function} loadRules The function to use to load rules.
  3140. * @property {Map<string,Rule>} builtInRules The rules that are built in to ESLint.
  3141. * @property {Object} [resolver=ModuleResolver] The module resolver object.
  3142. * @property {string} eslintAllPath The path to the definitions for eslint:all.
  3143. * @property {Function} getEslintAllConfig Returns the config data for eslint:all.
  3144. * @property {string} eslintRecommendedPath The path to the definitions for eslint:recommended.
  3145. * @property {Function} getEslintRecommendedConfig Returns the config data for eslint:recommended.
  3146. */
  3147. /**
  3148. * @typedef {Object} CascadingConfigArrayFactoryInternalSlots
  3149. * @property {ConfigArray} baseConfigArray The config array of `baseConfig` option.
  3150. * @property {ConfigData} baseConfigData The config data of `baseConfig` option. This is used to reset `baseConfigArray`.
  3151. * @property {ConfigArray} cliConfigArray The config array of CLI options.
  3152. * @property {ConfigData} cliConfigData The config data of CLI options. This is used to reset `cliConfigArray`.
  3153. * @property {ConfigArrayFactory} configArrayFactory The factory for config arrays.
  3154. * @property {Map<string, ConfigArray>} configCache The cache from directory paths to config arrays.
  3155. * @property {string} cwd The base directory to start lookup.
  3156. * @property {WeakMap<ConfigArray, ConfigArray>} finalizeCache The cache from config arrays to finalized config arrays.
  3157. * @property {string} [ignorePath] The path to the alternative file of `.eslintignore`.
  3158. * @property {string[]|null} rulePaths The value of `--rulesdir` option. This is used to reset `baseConfigArray`.
  3159. * @property {string|null} specificConfigPath The value of `--config` option. This is used to reset `cliConfigArray`.
  3160. * @property {boolean} useEslintrc if `false` then it doesn't load config files.
  3161. * @property {Function} loadRules The function to use to load rules.
  3162. * @property {Map<string,Rule>} builtInRules The rules that are built in to ESLint.
  3163. * @property {Object} [resolver=ModuleResolver] The module resolver object.
  3164. * @property {string} eslintAllPath The path to the definitions for eslint:all.
  3165. * @property {Function} getEslintAllConfig Returns the config data for eslint:all.
  3166. * @property {string} eslintRecommendedPath The path to the definitions for eslint:recommended.
  3167. * @property {Function} getEslintRecommendedConfig Returns the config data for eslint:recommended.
  3168. */
  3169. /** @type {WeakMap<CascadingConfigArrayFactory, CascadingConfigArrayFactoryInternalSlots>} */
  3170. const internalSlotsMap = new WeakMap();
  3171. /**
  3172. * Create the config array from `baseConfig` and `rulePaths`.
  3173. * @param {CascadingConfigArrayFactoryInternalSlots} slots The slots.
  3174. * @returns {ConfigArray} The config array of the base configs.
  3175. */
  3176. function createBaseConfigArray({
  3177. configArrayFactory,
  3178. baseConfigData,
  3179. rulePaths,
  3180. cwd,
  3181. loadRules
  3182. }) {
  3183. const baseConfigArray = configArrayFactory.create(
  3184. baseConfigData,
  3185. { name: "BaseConfig" }
  3186. );
  3187. /*
  3188. * Create the config array element for the default ignore patterns.
  3189. * This element has `ignorePattern` property that ignores the default
  3190. * patterns in the current working directory.
  3191. */
  3192. baseConfigArray.unshift(configArrayFactory.create(
  3193. { ignorePatterns: IgnorePattern.DefaultPatterns },
  3194. { name: "DefaultIgnorePattern" }
  3195. )[0]);
  3196. /*
  3197. * Load rules `--rulesdir` option as a pseudo plugin.
  3198. * Use a pseudo plugin to define rules of `--rulesdir`, so we can validate
  3199. * the rule's options with only information in the config array.
  3200. */
  3201. if (rulePaths && rulePaths.length > 0) {
  3202. baseConfigArray.push({
  3203. type: "config",
  3204. name: "--rulesdir",
  3205. filePath: "",
  3206. plugins: {
  3207. "": new ConfigDependency({
  3208. definition: {
  3209. rules: rulePaths.reduce(
  3210. (map, rulesPath) => Object.assign(
  3211. map,
  3212. loadRules(rulesPath, cwd)
  3213. ),
  3214. {}
  3215. )
  3216. },
  3217. filePath: "",
  3218. id: "",
  3219. importerName: "--rulesdir",
  3220. importerPath: ""
  3221. })
  3222. }
  3223. });
  3224. }
  3225. return baseConfigArray;
  3226. }
  3227. /**
  3228. * Create the config array from CLI options.
  3229. * @param {CascadingConfigArrayFactoryInternalSlots} slots The slots.
  3230. * @returns {ConfigArray} The config array of the base configs.
  3231. */
  3232. function createCLIConfigArray({
  3233. cliConfigData,
  3234. configArrayFactory,
  3235. cwd,
  3236. ignorePath,
  3237. specificConfigPath
  3238. }) {
  3239. const cliConfigArray = configArrayFactory.create(
  3240. cliConfigData,
  3241. { name: "CLIOptions" }
  3242. );
  3243. cliConfigArray.unshift(
  3244. ...(ignorePath
  3245. ? configArrayFactory.loadESLintIgnore(ignorePath)
  3246. : configArrayFactory.loadDefaultESLintIgnore())
  3247. );
  3248. if (specificConfigPath) {
  3249. cliConfigArray.unshift(
  3250. ...configArrayFactory.loadFile(
  3251. specificConfigPath,
  3252. { name: "--config", basePath: cwd }
  3253. )
  3254. );
  3255. }
  3256. return cliConfigArray;
  3257. }
  3258. /**
  3259. * The error type when there are files matched by a glob, but all of them have been ignored.
  3260. */
  3261. class ConfigurationNotFoundError extends Error {
  3262. // eslint-disable-next-line jsdoc/require-description
  3263. /**
  3264. * @param {string} directoryPath The directory path.
  3265. */
  3266. constructor(directoryPath) {
  3267. super(`No ESLint configuration found in ${directoryPath}.`);
  3268. this.messageTemplate = "no-config-found";
  3269. this.messageData = { directoryPath };
  3270. }
  3271. }
  3272. /**
  3273. * This class provides the functionality that enumerates every file which is
  3274. * matched by given glob patterns and that configuration.
  3275. */
  3276. class CascadingConfigArrayFactory {
  3277. /**
  3278. * Initialize this enumerator.
  3279. * @param {CascadingConfigArrayFactoryOptions} options The options.
  3280. */
  3281. constructor({
  3282. additionalPluginPool = new Map(),
  3283. baseConfig: baseConfigData = null,
  3284. cliConfig: cliConfigData = null,
  3285. cwd = process.cwd(),
  3286. ignorePath,
  3287. resolvePluginsRelativeTo,
  3288. rulePaths = [],
  3289. specificConfigPath = null,
  3290. useEslintrc = true,
  3291. builtInRules = new Map(),
  3292. loadRules,
  3293. resolver,
  3294. eslintRecommendedPath,
  3295. getEslintRecommendedConfig,
  3296. eslintAllPath,
  3297. getEslintAllConfig
  3298. } = {}) {
  3299. const configArrayFactory = new ConfigArrayFactory({
  3300. additionalPluginPool,
  3301. cwd,
  3302. resolvePluginsRelativeTo,
  3303. builtInRules,
  3304. resolver,
  3305. eslintRecommendedPath,
  3306. getEslintRecommendedConfig,
  3307. eslintAllPath,
  3308. getEslintAllConfig
  3309. });
  3310. internalSlotsMap.set(this, {
  3311. baseConfigArray: createBaseConfigArray({
  3312. baseConfigData,
  3313. configArrayFactory,
  3314. cwd,
  3315. rulePaths,
  3316. loadRules
  3317. }),
  3318. baseConfigData,
  3319. cliConfigArray: createCLIConfigArray({
  3320. cliConfigData,
  3321. configArrayFactory,
  3322. cwd,
  3323. ignorePath,
  3324. specificConfigPath
  3325. }),
  3326. cliConfigData,
  3327. configArrayFactory,
  3328. configCache: new Map(),
  3329. cwd,
  3330. finalizeCache: new WeakMap(),
  3331. ignorePath,
  3332. rulePaths,
  3333. specificConfigPath,
  3334. useEslintrc,
  3335. builtInRules,
  3336. loadRules
  3337. });
  3338. }
  3339. /**
  3340. * The path to the current working directory.
  3341. * This is used by tests.
  3342. * @type {string}
  3343. */
  3344. get cwd() {
  3345. const { cwd } = internalSlotsMap.get(this);
  3346. return cwd;
  3347. }
  3348. /**
  3349. * Get the config array of a given file.
  3350. * If `filePath` was not given, it returns the config which contains only
  3351. * `baseConfigData` and `cliConfigData`.
  3352. * @param {string} [filePath] The file path to a file.
  3353. * @param {Object} [options] The options.
  3354. * @param {boolean} [options.ignoreNotFoundError] If `true` then it doesn't throw `ConfigurationNotFoundError`.
  3355. * @returns {ConfigArray} The config array of the file.
  3356. */
  3357. getConfigArrayForFile(filePath, { ignoreNotFoundError = false } = {}) {
  3358. const {
  3359. baseConfigArray,
  3360. cliConfigArray,
  3361. cwd
  3362. } = internalSlotsMap.get(this);
  3363. if (!filePath) {
  3364. return new ConfigArray(...baseConfigArray, ...cliConfigArray);
  3365. }
  3366. const directoryPath = path__default["default"].dirname(path__default["default"].resolve(cwd, filePath));
  3367. debug$1(`Load config files for ${directoryPath}.`);
  3368. return this._finalizeConfigArray(
  3369. this._loadConfigInAncestors(directoryPath),
  3370. directoryPath,
  3371. ignoreNotFoundError
  3372. );
  3373. }
  3374. /**
  3375. * Set the config data to override all configs.
  3376. * Require to call `clearCache()` method after this method is called.
  3377. * @param {ConfigData} configData The config data to override all configs.
  3378. * @returns {void}
  3379. */
  3380. setOverrideConfig(configData) {
  3381. const slots = internalSlotsMap.get(this);
  3382. slots.cliConfigData = configData;
  3383. }
  3384. /**
  3385. * Clear config cache.
  3386. * @returns {void}
  3387. */
  3388. clearCache() {
  3389. const slots = internalSlotsMap.get(this);
  3390. slots.baseConfigArray = createBaseConfigArray(slots);
  3391. slots.cliConfigArray = createCLIConfigArray(slots);
  3392. slots.configCache.clear();
  3393. }
  3394. /**
  3395. * Load and normalize config files from the ancestor directories.
  3396. * @param {string} directoryPath The path to a leaf directory.
  3397. * @param {boolean} configsExistInSubdirs `true` if configurations exist in subdirectories.
  3398. * @returns {ConfigArray} The loaded config.
  3399. * @private
  3400. */
  3401. _loadConfigInAncestors(directoryPath, configsExistInSubdirs = false) {
  3402. const {
  3403. baseConfigArray,
  3404. configArrayFactory,
  3405. configCache,
  3406. cwd,
  3407. useEslintrc
  3408. } = internalSlotsMap.get(this);
  3409. if (!useEslintrc) {
  3410. return baseConfigArray;
  3411. }
  3412. let configArray = configCache.get(directoryPath);
  3413. // Hit cache.
  3414. if (configArray) {
  3415. debug$1(`Cache hit: ${directoryPath}.`);
  3416. return configArray;
  3417. }
  3418. debug$1(`No cache found: ${directoryPath}.`);
  3419. const homePath = os__default["default"].homedir();
  3420. // Consider this is root.
  3421. if (directoryPath === homePath && cwd !== homePath) {
  3422. debug$1("Stop traversing because of considered root.");
  3423. if (configsExistInSubdirs) {
  3424. const filePath = ConfigArrayFactory.getPathToConfigFileInDirectory(directoryPath);
  3425. if (filePath) {
  3426. emitDeprecationWarning(
  3427. filePath,
  3428. "ESLINT_PERSONAL_CONFIG_SUPPRESS"
  3429. );
  3430. }
  3431. }
  3432. return this._cacheConfig(directoryPath, baseConfigArray);
  3433. }
  3434. // Load the config on this directory.
  3435. try {
  3436. configArray = configArrayFactory.loadInDirectory(directoryPath);
  3437. } catch (error) {
  3438. /* istanbul ignore next */
  3439. if (error.code === "EACCES") {
  3440. debug$1("Stop traversing because of 'EACCES' error.");
  3441. return this._cacheConfig(directoryPath, baseConfigArray);
  3442. }
  3443. throw error;
  3444. }
  3445. if (configArray.length > 0 && configArray.isRoot()) {
  3446. debug$1("Stop traversing because of 'root:true'.");
  3447. configArray.unshift(...baseConfigArray);
  3448. return this._cacheConfig(directoryPath, configArray);
  3449. }
  3450. // Load from the ancestors and merge it.
  3451. const parentPath = path__default["default"].dirname(directoryPath);
  3452. const parentConfigArray = parentPath && parentPath !== directoryPath
  3453. ? this._loadConfigInAncestors(
  3454. parentPath,
  3455. configsExistInSubdirs || configArray.length > 0
  3456. )
  3457. : baseConfigArray;
  3458. if (configArray.length > 0) {
  3459. configArray.unshift(...parentConfigArray);
  3460. } else {
  3461. configArray = parentConfigArray;
  3462. }
  3463. // Cache and return.
  3464. return this._cacheConfig(directoryPath, configArray);
  3465. }
  3466. /**
  3467. * Freeze and cache a given config.
  3468. * @param {string} directoryPath The path to a directory as a cache key.
  3469. * @param {ConfigArray} configArray The config array as a cache value.
  3470. * @returns {ConfigArray} The `configArray` (frozen).
  3471. */
  3472. _cacheConfig(directoryPath, configArray) {
  3473. const { configCache } = internalSlotsMap.get(this);
  3474. Object.freeze(configArray);
  3475. configCache.set(directoryPath, configArray);
  3476. return configArray;
  3477. }
  3478. /**
  3479. * Finalize a given config array.
  3480. * Concatenate `--config` and other CLI options.
  3481. * @param {ConfigArray} configArray The parent config array.
  3482. * @param {string} directoryPath The path to the leaf directory to find config files.
  3483. * @param {boolean} ignoreNotFoundError If `true` then it doesn't throw `ConfigurationNotFoundError`.
  3484. * @returns {ConfigArray} The loaded config.
  3485. * @private
  3486. */
  3487. _finalizeConfigArray(configArray, directoryPath, ignoreNotFoundError) {
  3488. const {
  3489. cliConfigArray,
  3490. configArrayFactory,
  3491. finalizeCache,
  3492. useEslintrc,
  3493. builtInRules
  3494. } = internalSlotsMap.get(this);
  3495. let finalConfigArray = finalizeCache.get(configArray);
  3496. if (!finalConfigArray) {
  3497. finalConfigArray = configArray;
  3498. // Load the personal config if there are no regular config files.
  3499. if (
  3500. useEslintrc &&
  3501. configArray.every(c => !c.filePath) &&
  3502. cliConfigArray.every(c => !c.filePath) // `--config` option can be a file.
  3503. ) {
  3504. const homePath = os__default["default"].homedir();
  3505. debug$1("Loading the config file of the home directory:", homePath);
  3506. const personalConfigArray = configArrayFactory.loadInDirectory(
  3507. homePath,
  3508. { name: "PersonalConfig" }
  3509. );
  3510. if (
  3511. personalConfigArray.length > 0 &&
  3512. !directoryPath.startsWith(homePath)
  3513. ) {
  3514. const lastElement =
  3515. personalConfigArray[personalConfigArray.length - 1];
  3516. emitDeprecationWarning(
  3517. lastElement.filePath,
  3518. "ESLINT_PERSONAL_CONFIG_LOAD"
  3519. );
  3520. }
  3521. finalConfigArray = finalConfigArray.concat(personalConfigArray);
  3522. }
  3523. // Apply CLI options.
  3524. if (cliConfigArray.length > 0) {
  3525. finalConfigArray = finalConfigArray.concat(cliConfigArray);
  3526. }
  3527. // Validate rule settings and environments.
  3528. const validator = new ConfigValidator({
  3529. builtInRules
  3530. });
  3531. validator.validateConfigArray(finalConfigArray);
  3532. // Cache it.
  3533. Object.freeze(finalConfigArray);
  3534. finalizeCache.set(configArray, finalConfigArray);
  3535. debug$1(
  3536. "Configuration was determined: %o on %s",
  3537. finalConfigArray,
  3538. directoryPath
  3539. );
  3540. }
  3541. // At least one element (the default ignore patterns) exists.
  3542. if (!ignoreNotFoundError && useEslintrc && finalConfigArray.length <= 1) {
  3543. throw new ConfigurationNotFoundError(directoryPath);
  3544. }
  3545. return finalConfigArray;
  3546. }
  3547. }
  3548. /**
  3549. * @fileoverview Compatibility class for flat config.
  3550. * @author Nicholas C. Zakas
  3551. */
  3552. //-----------------------------------------------------------------------------
  3553. // Helpers
  3554. //-----------------------------------------------------------------------------
  3555. /** @typedef {import("../../shared/types").Environment} Environment */
  3556. /** @typedef {import("../../shared/types").Processor} Processor */
  3557. const debug = debugOrig__default["default"]("eslintrc:flat-compat");
  3558. const cafactory = Symbol("cafactory");
  3559. /**
  3560. * Translates an ESLintRC-style config object into a flag-config-style config
  3561. * object.
  3562. * @param {Object} eslintrcConfig An ESLintRC-style config object.
  3563. * @param {Object} options Options to help translate the config.
  3564. * @param {string} options.resolveConfigRelativeTo To the directory to resolve
  3565. * configs from.
  3566. * @param {string} options.resolvePluginsRelativeTo The directory to resolve
  3567. * plugins from.
  3568. * @param {ReadOnlyMap<string,Environment>} options.pluginEnvironments A map of plugin environment
  3569. * names to objects.
  3570. * @param {ReadOnlyMap<string,Processor>} options.pluginProcessors A map of plugin processor
  3571. * names to objects.
  3572. * @returns {Object} A flag-config-style config object.
  3573. */
  3574. function translateESLintRC(eslintrcConfig, {
  3575. resolveConfigRelativeTo,
  3576. resolvePluginsRelativeTo,
  3577. pluginEnvironments,
  3578. pluginProcessors
  3579. }) {
  3580. const flatConfig = {};
  3581. const configs = [];
  3582. const languageOptions = {};
  3583. const linterOptions = {};
  3584. const keysToCopy = ["settings", "rules", "processor"];
  3585. const languageOptionsKeysToCopy = ["globals", "parser", "parserOptions"];
  3586. const linterOptionsKeysToCopy = ["noInlineConfig", "reportUnusedDisableDirectives"];
  3587. // copy over simple translations
  3588. for (const key of keysToCopy) {
  3589. if (key in eslintrcConfig && typeof eslintrcConfig[key] !== "undefined") {
  3590. flatConfig[key] = eslintrcConfig[key];
  3591. }
  3592. }
  3593. // copy over languageOptions
  3594. for (const key of languageOptionsKeysToCopy) {
  3595. if (key in eslintrcConfig && typeof eslintrcConfig[key] !== "undefined") {
  3596. // create the languageOptions key in the flat config
  3597. flatConfig.languageOptions = languageOptions;
  3598. if (key === "parser") {
  3599. debug(`Resolving parser '${languageOptions[key]}' relative to ${resolveConfigRelativeTo}`);
  3600. if (eslintrcConfig[key].error) {
  3601. throw eslintrcConfig[key].error;
  3602. }
  3603. languageOptions[key] = eslintrcConfig[key].definition;
  3604. continue;
  3605. }
  3606. // clone any object values that are in the eslintrc config
  3607. if (eslintrcConfig[key] && typeof eslintrcConfig[key] === "object") {
  3608. languageOptions[key] = {
  3609. ...eslintrcConfig[key]
  3610. };
  3611. } else {
  3612. languageOptions[key] = eslintrcConfig[key];
  3613. }
  3614. }
  3615. }
  3616. // copy over linterOptions
  3617. for (const key of linterOptionsKeysToCopy) {
  3618. if (key in eslintrcConfig && typeof eslintrcConfig[key] !== "undefined") {
  3619. flatConfig.linterOptions = linterOptions;
  3620. linterOptions[key] = eslintrcConfig[key];
  3621. }
  3622. }
  3623. // move ecmaVersion a level up
  3624. if (languageOptions.parserOptions) {
  3625. if ("ecmaVersion" in languageOptions.parserOptions) {
  3626. languageOptions.ecmaVersion = languageOptions.parserOptions.ecmaVersion;
  3627. delete languageOptions.parserOptions.ecmaVersion;
  3628. }
  3629. if ("sourceType" in languageOptions.parserOptions) {
  3630. languageOptions.sourceType = languageOptions.parserOptions.sourceType;
  3631. delete languageOptions.parserOptions.sourceType;
  3632. }
  3633. // check to see if we even need parserOptions anymore and remove it if not
  3634. if (Object.keys(languageOptions.parserOptions).length === 0) {
  3635. delete languageOptions.parserOptions;
  3636. }
  3637. }
  3638. // overrides
  3639. if (eslintrcConfig.criteria) {
  3640. flatConfig.files = [absoluteFilePath => eslintrcConfig.criteria.test(absoluteFilePath)];
  3641. }
  3642. // translate plugins
  3643. if (eslintrcConfig.plugins && typeof eslintrcConfig.plugins === "object") {
  3644. debug(`Translating plugins: ${eslintrcConfig.plugins}`);
  3645. flatConfig.plugins = {};
  3646. for (const pluginName of Object.keys(eslintrcConfig.plugins)) {
  3647. debug(`Translating plugin: ${pluginName}`);
  3648. debug(`Resolving plugin '${pluginName} relative to ${resolvePluginsRelativeTo}`);
  3649. const { original: plugin, error } = eslintrcConfig.plugins[pluginName];
  3650. if (error) {
  3651. throw error;
  3652. }
  3653. flatConfig.plugins[pluginName] = plugin;
  3654. // create a config for any processors
  3655. if (plugin.processors) {
  3656. for (const processorName of Object.keys(plugin.processors)) {
  3657. if (processorName.startsWith(".")) {
  3658. debug(`Assigning processor: ${pluginName}/${processorName}`);
  3659. configs.unshift({
  3660. files: [`**/*${processorName}`],
  3661. processor: pluginProcessors.get(`${pluginName}/${processorName}`)
  3662. });
  3663. }
  3664. }
  3665. }
  3666. }
  3667. }
  3668. // translate env - must come after plugins
  3669. if (eslintrcConfig.env && typeof eslintrcConfig.env === "object") {
  3670. for (const envName of Object.keys(eslintrcConfig.env)) {
  3671. // only add environments that are true
  3672. if (eslintrcConfig.env[envName]) {
  3673. debug(`Translating environment: ${envName}`);
  3674. if (environments.has(envName)) {
  3675. // built-in environments should be defined first
  3676. configs.unshift(...translateESLintRC({
  3677. criteria: eslintrcConfig.criteria,
  3678. ...environments.get(envName)
  3679. }, {
  3680. resolveConfigRelativeTo,
  3681. resolvePluginsRelativeTo
  3682. }));
  3683. } else if (pluginEnvironments.has(envName)) {
  3684. // if the environment comes from a plugin, it should come after the plugin config
  3685. configs.push(...translateESLintRC({
  3686. criteria: eslintrcConfig.criteria,
  3687. ...pluginEnvironments.get(envName)
  3688. }, {
  3689. resolveConfigRelativeTo,
  3690. resolvePluginsRelativeTo
  3691. }));
  3692. }
  3693. }
  3694. }
  3695. }
  3696. // only add if there are actually keys in the config
  3697. if (Object.keys(flatConfig).length > 0) {
  3698. configs.push(flatConfig);
  3699. }
  3700. return configs;
  3701. }
  3702. //-----------------------------------------------------------------------------
  3703. // Exports
  3704. //-----------------------------------------------------------------------------
  3705. /**
  3706. * A compatibility class for working with configs.
  3707. */
  3708. class FlatCompat {
  3709. constructor({
  3710. baseDirectory = process.cwd(),
  3711. resolvePluginsRelativeTo = baseDirectory,
  3712. recommendedConfig,
  3713. allConfig
  3714. } = {}) {
  3715. this.baseDirectory = baseDirectory;
  3716. this.resolvePluginsRelativeTo = resolvePluginsRelativeTo;
  3717. this[cafactory] = new ConfigArrayFactory({
  3718. cwd: baseDirectory,
  3719. resolvePluginsRelativeTo,
  3720. getEslintAllConfig: () => {
  3721. if (!allConfig) {
  3722. throw new TypeError("Missing parameter 'allConfig' in FlatCompat constructor.");
  3723. }
  3724. return allConfig;
  3725. },
  3726. getEslintRecommendedConfig: () => {
  3727. if (!recommendedConfig) {
  3728. throw new TypeError("Missing parameter 'recommendedConfig' in FlatCompat constructor.");
  3729. }
  3730. return recommendedConfig;
  3731. }
  3732. });
  3733. }
  3734. /**
  3735. * Translates an ESLintRC-style config into a flag-config-style config.
  3736. * @param {Object} eslintrcConfig The ESLintRC-style config object.
  3737. * @returns {Object} A flag-config-style config object.
  3738. */
  3739. config(eslintrcConfig) {
  3740. const eslintrcArray = this[cafactory].create(eslintrcConfig, {
  3741. basePath: this.baseDirectory
  3742. });
  3743. const flatArray = [];
  3744. let hasIgnorePatterns = false;
  3745. eslintrcArray.forEach(configData => {
  3746. if (configData.type === "config") {
  3747. hasIgnorePatterns = hasIgnorePatterns || configData.ignorePattern;
  3748. flatArray.push(...translateESLintRC(configData, {
  3749. resolveConfigRelativeTo: path__default["default"].join(this.baseDirectory, "__placeholder.js"),
  3750. resolvePluginsRelativeTo: path__default["default"].join(this.resolvePluginsRelativeTo, "__placeholder.js"),
  3751. pluginEnvironments: eslintrcArray.pluginEnvironments,
  3752. pluginProcessors: eslintrcArray.pluginProcessors
  3753. }));
  3754. }
  3755. });
  3756. // combine ignorePatterns to emulate ESLintRC behavior better
  3757. if (hasIgnorePatterns) {
  3758. flatArray.unshift({
  3759. ignores: [filePath => {
  3760. // Compute the final config for this file.
  3761. // This filters config array elements by `files`/`excludedFiles` then merges the elements.
  3762. const finalConfig = eslintrcArray.extractConfig(filePath);
  3763. // Test the `ignorePattern` properties of the final config.
  3764. return Boolean(finalConfig.ignores) && finalConfig.ignores(filePath);
  3765. }]
  3766. });
  3767. }
  3768. return flatArray;
  3769. }
  3770. /**
  3771. * Translates the `env` section of an ESLintRC-style config.
  3772. * @param {Object} envConfig The `env` section of an ESLintRC config.
  3773. * @returns {Object[]} An array of flag-config objects representing the environments.
  3774. */
  3775. env(envConfig) {
  3776. return this.config({
  3777. env: envConfig
  3778. });
  3779. }
  3780. /**
  3781. * Translates the `extends` section of an ESLintRC-style config.
  3782. * @param {...string} configsToExtend The names of the configs to load.
  3783. * @returns {Object[]} An array of flag-config objects representing the config.
  3784. */
  3785. extends(...configsToExtend) {
  3786. return this.config({
  3787. extends: configsToExtend
  3788. });
  3789. }
  3790. /**
  3791. * Translates the `plugins` section of an ESLintRC-style config.
  3792. * @param {...string} plugins The names of the plugins to load.
  3793. * @returns {Object[]} An array of flag-config objects representing the plugins.
  3794. */
  3795. plugins(...plugins) {
  3796. return this.config({
  3797. plugins
  3798. });
  3799. }
  3800. }
  3801. /**
  3802. * @fileoverview Package exports for @eslint/eslintrc
  3803. * @author Nicholas C. Zakas
  3804. */
  3805. //-----------------------------------------------------------------------------
  3806. // Exports
  3807. //-----------------------------------------------------------------------------
  3808. const Legacy = {
  3809. ConfigArray,
  3810. createConfigArrayFactoryContext: createContext,
  3811. CascadingConfigArrayFactory,
  3812. ConfigArrayFactory,
  3813. ConfigDependency,
  3814. ExtractedConfig,
  3815. IgnorePattern,
  3816. OverrideTester,
  3817. getUsedExtractedConfigs,
  3818. environments,
  3819. loadConfigFile,
  3820. // shared
  3821. ConfigOps,
  3822. ConfigValidator,
  3823. ModuleResolver,
  3824. naming
  3825. };
  3826. exports.FlatCompat = FlatCompat;
  3827. exports.Legacy = Legacy;
  3828. //# sourceMappingURL=eslintrc.cjs.map