eslintrc.cjs 143 KB

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