eslintrc.cjs 144 KB

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