12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310 |
- 'use strict';
- Object.defineProperty(exports, '__esModule', { value: true });
- var debugOrig = require('debug');
- var fs = require('fs');
- var importFresh = require('import-fresh');
- var Module = require('module');
- var path = require('path');
- var stripComments = require('strip-json-comments');
- var assert = require('assert');
- var ignore = require('ignore');
- var util = require('util');
- var minimatch = require('minimatch');
- var Ajv = require('ajv');
- var globals = require('globals');
- var os = require('os');
- function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
- var debugOrig__default = /*#__PURE__*/_interopDefaultLegacy(debugOrig);
- var fs__default = /*#__PURE__*/_interopDefaultLegacy(fs);
- var importFresh__default = /*#__PURE__*/_interopDefaultLegacy(importFresh);
- var Module__default = /*#__PURE__*/_interopDefaultLegacy(Module);
- var path__default = /*#__PURE__*/_interopDefaultLegacy(path);
- var stripComments__default = /*#__PURE__*/_interopDefaultLegacy(stripComments);
- var assert__default = /*#__PURE__*/_interopDefaultLegacy(assert);
- var ignore__default = /*#__PURE__*/_interopDefaultLegacy(ignore);
- var util__default = /*#__PURE__*/_interopDefaultLegacy(util);
- var minimatch__default = /*#__PURE__*/_interopDefaultLegacy(minimatch);
- var Ajv__default = /*#__PURE__*/_interopDefaultLegacy(Ajv);
- var globals__default = /*#__PURE__*/_interopDefaultLegacy(globals);
- var os__default = /*#__PURE__*/_interopDefaultLegacy(os);
- /**
- * @fileoverview `IgnorePattern` class.
- *
- * `IgnorePattern` class has the set of glob patterns and the base path.
- *
- * It provides two static methods.
- *
- * - `IgnorePattern.createDefaultIgnore(cwd)`
- * Create the default predicate function.
- * - `IgnorePattern.createIgnore(ignorePatterns)`
- * Create the predicate function from multiple `IgnorePattern` objects.
- *
- * It provides two properties and a method.
- *
- * - `patterns`
- * The glob patterns that ignore to lint.
- * - `basePath`
- * The base path of the glob patterns. If absolute paths existed in the
- * glob patterns, those are handled as relative paths to the base path.
- * - `getPatternsRelativeTo(basePath)`
- * Get `patterns` as modified for a given base path. It modifies the
- * absolute paths in the patterns as prepending the difference of two base
- * paths.
- *
- * `ConfigArrayFactory` creates `IgnorePattern` objects when it processes
- * `ignorePatterns` properties.
- *
- * @author Toru Nagashima <https://github.com/mysticatea>
- */
- const debug$3 = debugOrig__default["default"]("eslintrc:ignore-pattern");
- /** @typedef {ReturnType<import("ignore").default>} Ignore */
- //------------------------------------------------------------------------------
- // Helpers
- //------------------------------------------------------------------------------
- /**
- * Get the path to the common ancestor directory of given paths.
- * @param {string[]} sourcePaths The paths to calculate the common ancestor.
- * @returns {string} The path to the common ancestor directory.
- */
- function getCommonAncestorPath(sourcePaths) {
- let result = sourcePaths[0];
- for (let i = 1; i < sourcePaths.length; ++i) {
- const a = result;
- const b = sourcePaths[i];
- // Set the shorter one (it's the common ancestor if one includes the other).
- result = a.length < b.length ? a : b;
- // Set the common ancestor.
- for (let j = 0, lastSepPos = 0; j < a.length && j < b.length; ++j) {
- if (a[j] !== b[j]) {
- result = a.slice(0, lastSepPos);
- break;
- }
- if (a[j] === path__default["default"].sep) {
- lastSepPos = j;
- }
- }
- }
- let resolvedResult = result || path__default["default"].sep;
- // if Windows common ancestor is root of drive must have trailing slash to be absolute.
- if (resolvedResult && resolvedResult.endsWith(":") && process.platform === "win32") {
- resolvedResult += path__default["default"].sep;
- }
- return resolvedResult;
- }
- /**
- * Make relative path.
- * @param {string} from The source path to get relative path.
- * @param {string} to The destination path to get relative path.
- * @returns {string} The relative path.
- */
- function relative(from, to) {
- const relPath = path__default["default"].relative(from, to);
- if (path__default["default"].sep === "/") {
- return relPath;
- }
- return relPath.split(path__default["default"].sep).join("/");
- }
- /**
- * Get the trailing slash if existed.
- * @param {string} filePath The path to check.
- * @returns {string} The trailing slash if existed.
- */
- function dirSuffix(filePath) {
- const isDir = (
- filePath.endsWith(path__default["default"].sep) ||
- (process.platform === "win32" && filePath.endsWith("/"))
- );
- return isDir ? "/" : "";
- }
- const DefaultPatterns = Object.freeze(["/**/node_modules/*"]);
- const DotPatterns = Object.freeze([".*", "!.eslintrc.*", "!../"]);
- //------------------------------------------------------------------------------
- // Public
- //------------------------------------------------------------------------------
- class IgnorePattern {
- /**
- * The default patterns.
- * @type {string[]}
- */
- static get DefaultPatterns() {
- return DefaultPatterns;
- }
- /**
- * Create the default predicate function.
- * @param {string} cwd The current working directory.
- * @returns {((filePath:string, dot:boolean) => boolean) & {basePath:string; patterns:string[]}}
- * The preficate function.
- * The first argument is an absolute path that is checked.
- * The second argument is the flag to not ignore dotfiles.
- * If the predicate function returned `true`, it means the path should be ignored.
- */
- static createDefaultIgnore(cwd) {
- return this.createIgnore([new IgnorePattern(DefaultPatterns, cwd)]);
- }
- /**
- * Create the predicate function from multiple `IgnorePattern` objects.
- * @param {IgnorePattern[]} ignorePatterns The list of ignore patterns.
- * @returns {((filePath:string, dot?:boolean) => boolean) & {basePath:string; patterns:string[]}}
- * The preficate function.
- * The first argument is an absolute path that is checked.
- * The second argument is the flag to not ignore dotfiles.
- * If the predicate function returned `true`, it means the path should be ignored.
- */
- static createIgnore(ignorePatterns) {
- debug$3("Create with: %o", ignorePatterns);
- const basePath = getCommonAncestorPath(ignorePatterns.map(p => p.basePath));
- const patterns = [].concat(
- ...ignorePatterns.map(p => p.getPatternsRelativeTo(basePath))
- );
- const ig = ignore__default["default"]({ allowRelativePaths: true }).add([...DotPatterns, ...patterns]);
- const dotIg = ignore__default["default"]({ allowRelativePaths: true }).add(patterns);
- debug$3(" processed: %o", { basePath, patterns });
- return Object.assign(
- (filePath, dot = false) => {
- assert__default["default"](path__default["default"].isAbsolute(filePath), "'filePath' should be an absolute path.");
- const relPathRaw = relative(basePath, filePath);
- const relPath = relPathRaw && (relPathRaw + dirSuffix(filePath));
- const adoptedIg = dot ? dotIg : ig;
- const result = relPath !== "" && adoptedIg.ignores(relPath);
- debug$3("Check", { filePath, dot, relativePath: relPath, result });
- return result;
- },
- { basePath, patterns }
- );
- }
- /**
- * Initialize a new `IgnorePattern` instance.
- * @param {string[]} patterns The glob patterns that ignore to lint.
- * @param {string} basePath The base path of `patterns`.
- */
- constructor(patterns, basePath) {
- assert__default["default"](path__default["default"].isAbsolute(basePath), "'basePath' should be an absolute path.");
- /**
- * The glob patterns that ignore to lint.
- * @type {string[]}
- */
- this.patterns = patterns;
- /**
- * The base path of `patterns`.
- * @type {string}
- */
- this.basePath = basePath;
- /**
- * If `true` then patterns which don't start with `/` will match the paths to the outside of `basePath`. Defaults to `false`.
- *
- * It's set `true` for `.eslintignore`, `package.json`, and `--ignore-path` for backward compatibility.
- * It's `false` as-is for `ignorePatterns` property in config files.
- * @type {boolean}
- */
- this.loose = false;
- }
- /**
- * Get `patterns` as modified for a given base path. It modifies the
- * absolute paths in the patterns as prepending the difference of two base
- * paths.
- * @param {string} newBasePath The base path.
- * @returns {string[]} Modifired patterns.
- */
- getPatternsRelativeTo(newBasePath) {
- assert__default["default"](path__default["default"].isAbsolute(newBasePath), "'newBasePath' should be an absolute path.");
- const { basePath, loose, patterns } = this;
- if (newBasePath === basePath) {
- return patterns;
- }
- const prefix = `/${relative(newBasePath, basePath)}`;
- return patterns.map(pattern => {
- const negative = pattern.startsWith("!");
- const head = negative ? "!" : "";
- const body = negative ? pattern.slice(1) : pattern;
- if (body.startsWith("/") || body.startsWith("../")) {
- return `${head}${prefix}${body}`;
- }
- return loose ? pattern : `${head}${prefix}/**/${body}`;
- });
- }
- }
- /**
- * @fileoverview `ExtractedConfig` class.
- *
- * `ExtractedConfig` class expresses a final configuration for a specific file.
- *
- * It provides one method.
- *
- * - `toCompatibleObjectAsConfigFileContent()`
- * Convert this configuration to the compatible object as the content of
- * config files. It converts the loaded parser and plugins to strings.
- * `CLIEngine#getConfigForFile(filePath)` method uses this method.
- *
- * `ConfigArray#extractConfig(filePath)` creates a `ExtractedConfig` instance.
- *
- * @author Toru Nagashima <https://github.com/mysticatea>
- */
- // For VSCode intellisense
- /** @typedef {import("../../shared/types").ConfigData} ConfigData */
- /** @typedef {import("../../shared/types").GlobalConf} GlobalConf */
- /** @typedef {import("../../shared/types").SeverityConf} SeverityConf */
- /** @typedef {import("./config-dependency").DependentParser} DependentParser */
- /** @typedef {import("./config-dependency").DependentPlugin} DependentPlugin */
- /**
- * Check if `xs` starts with `ys`.
- * @template T
- * @param {T[]} xs The array to check.
- * @param {T[]} ys The array that may be the first part of `xs`.
- * @returns {boolean} `true` if `xs` starts with `ys`.
- */
- function startsWith(xs, ys) {
- return xs.length >= ys.length && ys.every((y, i) => y === xs[i]);
- }
- /**
- * The class for extracted config data.
- */
- class ExtractedConfig {
- constructor() {
- /**
- * The config name what `noInlineConfig` setting came from.
- * @type {string}
- */
- this.configNameOfNoInlineConfig = "";
- /**
- * Environments.
- * @type {Record<string, boolean>}
- */
- this.env = {};
- /**
- * Global variables.
- * @type {Record<string, GlobalConf>}
- */
- this.globals = {};
- /**
- * The glob patterns that ignore to lint.
- * @type {(((filePath:string, dot?:boolean) => boolean) & { basePath:string; patterns:string[] }) | undefined}
- */
- this.ignores = void 0;
- /**
- * The flag that disables directive comments.
- * @type {boolean|undefined}
- */
- this.noInlineConfig = void 0;
- /**
- * Parser definition.
- * @type {DependentParser|null}
- */
- this.parser = null;
- /**
- * Options for the parser.
- * @type {Object}
- */
- this.parserOptions = {};
- /**
- * Plugin definitions.
- * @type {Record<string, DependentPlugin>}
- */
- this.plugins = {};
- /**
- * Processor ID.
- * @type {string|null}
- */
- this.processor = null;
- /**
- * The flag that reports unused `eslint-disable` directive comments.
- * @type {boolean|undefined}
- */
- this.reportUnusedDisableDirectives = void 0;
- /**
- * Rule settings.
- * @type {Record<string, [SeverityConf, ...any[]]>}
- */
- this.rules = {};
- /**
- * Shared settings.
- * @type {Object}
- */
- this.settings = {};
- }
- /**
- * Convert this config to the compatible object as a config file content.
- * @returns {ConfigData} The converted object.
- */
- toCompatibleObjectAsConfigFileContent() {
- const {
- /* eslint-disable no-unused-vars */
- configNameOfNoInlineConfig: _ignore1,
- processor: _ignore2,
- /* eslint-enable no-unused-vars */
- ignores,
- ...config
- } = this;
- config.parser = config.parser && config.parser.filePath;
- config.plugins = Object.keys(config.plugins).filter(Boolean).reverse();
- config.ignorePatterns = ignores ? ignores.patterns : [];
- // Strip the default patterns from `ignorePatterns`.
- if (startsWith(config.ignorePatterns, IgnorePattern.DefaultPatterns)) {
- config.ignorePatterns =
- config.ignorePatterns.slice(IgnorePattern.DefaultPatterns.length);
- }
- return config;
- }
- }
- /**
- * @fileoverview `ConfigArray` class.
- *
- * `ConfigArray` class expresses the full of a configuration. It has the entry
- * config file, base config files that were extended, loaded parsers, and loaded
- * plugins.
- *
- * `ConfigArray` class provides three properties and two methods.
- *
- * - `pluginEnvironments`
- * - `pluginProcessors`
- * - `pluginRules`
- * The `Map` objects that contain the members of all plugins that this
- * config array contains. Those map objects don't have mutation methods.
- * Those keys are the member ID such as `pluginId/memberName`.
- * - `isRoot()`
- * If `true` then this configuration has `root:true` property.
- * - `extractConfig(filePath)`
- * Extract the final configuration for a given file. This means merging
- * every config array element which that `criteria` property matched. The
- * `filePath` argument must be an absolute path.
- *
- * `ConfigArrayFactory` provides the loading logic of config files.
- *
- * @author Toru Nagashima <https://github.com/mysticatea>
- */
- //------------------------------------------------------------------------------
- // Helpers
- //------------------------------------------------------------------------------
- // Define types for VSCode IntelliSense.
- /** @typedef {import("../../shared/types").Environment} Environment */
- /** @typedef {import("../../shared/types").GlobalConf} GlobalConf */
- /** @typedef {import("../../shared/types").RuleConf} RuleConf */
- /** @typedef {import("../../shared/types").Rule} Rule */
- /** @typedef {import("../../shared/types").Plugin} Plugin */
- /** @typedef {import("../../shared/types").Processor} Processor */
- /** @typedef {import("./config-dependency").DependentParser} DependentParser */
- /** @typedef {import("./config-dependency").DependentPlugin} DependentPlugin */
- /** @typedef {import("./override-tester")["OverrideTester"]} OverrideTester */
- /**
- * @typedef {Object} ConfigArrayElement
- * @property {string} name The name of this config element.
- * @property {string} filePath The path to the source file of this config element.
- * @property {InstanceType<OverrideTester>|null} criteria The tester for the `files` and `excludedFiles` of this config element.
- * @property {Record<string, boolean>|undefined} env The environment settings.
- * @property {Record<string, GlobalConf>|undefined} globals The global variable settings.
- * @property {IgnorePattern|undefined} ignorePattern The ignore patterns.
- * @property {boolean|undefined} noInlineConfig The flag that disables directive comments.
- * @property {DependentParser|undefined} parser The parser loader.
- * @property {Object|undefined} parserOptions The parser options.
- * @property {Record<string, DependentPlugin>|undefined} plugins The plugin loaders.
- * @property {string|undefined} processor The processor name to refer plugin's processor.
- * @property {boolean|undefined} reportUnusedDisableDirectives The flag to report unused `eslint-disable` comments.
- * @property {boolean|undefined} root The flag to express root.
- * @property {Record<string, RuleConf>|undefined} rules The rule settings
- * @property {Object|undefined} settings The shared settings.
- * @property {"config" | "ignore" | "implicit-processor"} type The element type.
- */
- /**
- * @typedef {Object} ConfigArrayInternalSlots
- * @property {Map<string, ExtractedConfig>} cache The cache to extract configs.
- * @property {ReadonlyMap<string, Environment>|null} envMap The map from environment ID to environment definition.
- * @property {ReadonlyMap<string, Processor>|null} processorMap The map from processor ID to environment definition.
- * @property {ReadonlyMap<string, Rule>|null} ruleMap The map from rule ID to rule definition.
- */
- /** @type {WeakMap<ConfigArray, ConfigArrayInternalSlots>} */
- const internalSlotsMap$2 = new class extends WeakMap {
- get(key) {
- let value = super.get(key);
- if (!value) {
- value = {
- cache: new Map(),
- envMap: null,
- processorMap: null,
- ruleMap: null
- };
- super.set(key, value);
- }
- return value;
- }
- }();
- /**
- * Get the indices which are matched to a given file.
- * @param {ConfigArrayElement[]} elements The elements.
- * @param {string} filePath The path to a target file.
- * @returns {number[]} The indices.
- */
- function getMatchedIndices(elements, filePath) {
- const indices = [];
- for (let i = elements.length - 1; i >= 0; --i) {
- const element = elements[i];
- if (!element.criteria || (filePath && element.criteria.test(filePath))) {
- indices.push(i);
- }
- }
- return indices;
- }
- /**
- * Check if a value is a non-null object.
- * @param {any} x The value to check.
- * @returns {boolean} `true` if the value is a non-null object.
- */
- function isNonNullObject(x) {
- return typeof x === "object" && x !== null;
- }
- /**
- * Merge two objects.
- *
- * Assign every property values of `y` to `x` if `x` doesn't have the property.
- * If `x`'s property value is an object, it does recursive.
- * @param {Object} target The destination to merge
- * @param {Object|undefined} source The source to merge.
- * @returns {void}
- */
- function mergeWithoutOverwrite(target, source) {
- if (!isNonNullObject(source)) {
- return;
- }
- for (const key of Object.keys(source)) {
- if (key === "__proto__") {
- continue;
- }
- if (isNonNullObject(target[key])) {
- mergeWithoutOverwrite(target[key], source[key]);
- } else if (target[key] === void 0) {
- if (isNonNullObject(source[key])) {
- target[key] = Array.isArray(source[key]) ? [] : {};
- mergeWithoutOverwrite(target[key], source[key]);
- } else if (source[key] !== void 0) {
- target[key] = source[key];
- }
- }
- }
- }
- /**
- * The error for plugin conflicts.
- */
- class PluginConflictError extends Error {
- /**
- * Initialize this error object.
- * @param {string} pluginId The plugin ID.
- * @param {{filePath:string, importerName:string}[]} plugins The resolved plugins.
- */
- constructor(pluginId, plugins) {
- super(`Plugin "${pluginId}" was conflicted between ${plugins.map(p => `"${p.importerName}"`).join(" and ")}.`);
- this.messageTemplate = "plugin-conflict";
- this.messageData = { pluginId, plugins };
- }
- }
- /**
- * Merge plugins.
- * `target`'s definition is prior to `source`'s.
- * @param {Record<string, DependentPlugin>} target The destination to merge
- * @param {Record<string, DependentPlugin>|undefined} source The source to merge.
- * @returns {void}
- */
- function mergePlugins(target, source) {
- if (!isNonNullObject(source)) {
- return;
- }
- for (const key of Object.keys(source)) {
- if (key === "__proto__") {
- continue;
- }
- const targetValue = target[key];
- const sourceValue = source[key];
- // Adopt the plugin which was found at first.
- if (targetValue === void 0) {
- if (sourceValue.error) {
- throw sourceValue.error;
- }
- target[key] = sourceValue;
- } else if (sourceValue.filePath !== targetValue.filePath) {
- throw new PluginConflictError(key, [
- {
- filePath: targetValue.filePath,
- importerName: targetValue.importerName
- },
- {
- filePath: sourceValue.filePath,
- importerName: sourceValue.importerName
- }
- ]);
- }
- }
- }
- /**
- * Merge rule configs.
- * `target`'s definition is prior to `source`'s.
- * @param {Record<string, Array>} target The destination to merge
- * @param {Record<string, RuleConf>|undefined} source The source to merge.
- * @returns {void}
- */
- function mergeRuleConfigs(target, source) {
- if (!isNonNullObject(source)) {
- return;
- }
- for (const key of Object.keys(source)) {
- if (key === "__proto__") {
- continue;
- }
- const targetDef = target[key];
- const sourceDef = source[key];
- // Adopt the rule config which was found at first.
- if (targetDef === void 0) {
- if (Array.isArray(sourceDef)) {
- target[key] = [...sourceDef];
- } else {
- target[key] = [sourceDef];
- }
- /*
- * If the first found rule config is severity only and the current rule
- * config has options, merge the severity and the options.
- */
- } else if (
- targetDef.length === 1 &&
- Array.isArray(sourceDef) &&
- sourceDef.length >= 2
- ) {
- targetDef.push(...sourceDef.slice(1));
- }
- }
- }
- /**
- * Create the extracted config.
- * @param {ConfigArray} instance The config elements.
- * @param {number[]} indices The indices to use.
- * @returns {ExtractedConfig} The extracted config.
- */
- function createConfig(instance, indices) {
- const config = new ExtractedConfig();
- const ignorePatterns = [];
- // Merge elements.
- for (const index of indices) {
- const element = instance[index];
- // Adopt the parser which was found at first.
- if (!config.parser && element.parser) {
- if (element.parser.error) {
- throw element.parser.error;
- }
- config.parser = element.parser;
- }
- // Adopt the processor which was found at first.
- if (!config.processor && element.processor) {
- config.processor = element.processor;
- }
- // Adopt the noInlineConfig which was found at first.
- if (config.noInlineConfig === void 0 && element.noInlineConfig !== void 0) {
- config.noInlineConfig = element.noInlineConfig;
- config.configNameOfNoInlineConfig = element.name;
- }
- // Adopt the reportUnusedDisableDirectives which was found at first.
- if (config.reportUnusedDisableDirectives === void 0 && element.reportUnusedDisableDirectives !== void 0) {
- config.reportUnusedDisableDirectives = element.reportUnusedDisableDirectives;
- }
- // Collect ignorePatterns
- if (element.ignorePattern) {
- ignorePatterns.push(element.ignorePattern);
- }
- // Merge others.
- mergeWithoutOverwrite(config.env, element.env);
- mergeWithoutOverwrite(config.globals, element.globals);
- mergeWithoutOverwrite(config.parserOptions, element.parserOptions);
- mergeWithoutOverwrite(config.settings, element.settings);
- mergePlugins(config.plugins, element.plugins);
- mergeRuleConfigs(config.rules, element.rules);
- }
- // Create the predicate function for ignore patterns.
- if (ignorePatterns.length > 0) {
- config.ignores = IgnorePattern.createIgnore(ignorePatterns.reverse());
- }
- return config;
- }
- /**
- * Collect definitions.
- * @template T, U
- * @param {string} pluginId The plugin ID for prefix.
- * @param {Record<string,T>} defs The definitions to collect.
- * @param {Map<string, U>} map The map to output.
- * @param {function(T): U} [normalize] The normalize function for each value.
- * @returns {void}
- */
- function collect(pluginId, defs, map, normalize) {
- if (defs) {
- const prefix = pluginId && `${pluginId}/`;
- for (const [key, value] of Object.entries(defs)) {
- map.set(
- `${prefix}${key}`,
- normalize ? normalize(value) : value
- );
- }
- }
- }
- /**
- * Normalize a rule definition.
- * @param {Function|Rule} rule The rule definition to normalize.
- * @returns {Rule} The normalized rule definition.
- */
- function normalizePluginRule(rule) {
- return typeof rule === "function" ? { create: rule } : rule;
- }
- /**
- * Delete the mutation methods from a given map.
- * @param {Map<any, any>} map The map object to delete.
- * @returns {void}
- */
- function deleteMutationMethods(map) {
- Object.defineProperties(map, {
- clear: { configurable: true, value: void 0 },
- delete: { configurable: true, value: void 0 },
- set: { configurable: true, value: void 0 }
- });
- }
- /**
- * Create `envMap`, `processorMap`, `ruleMap` with the plugins in the config array.
- * @param {ConfigArrayElement[]} elements The config elements.
- * @param {ConfigArrayInternalSlots} slots The internal slots.
- * @returns {void}
- */
- function initPluginMemberMaps(elements, slots) {
- const processed = new Set();
- slots.envMap = new Map();
- slots.processorMap = new Map();
- slots.ruleMap = new Map();
- for (const element of elements) {
- if (!element.plugins) {
- continue;
- }
- for (const [pluginId, value] of Object.entries(element.plugins)) {
- const plugin = value.definition;
- if (!plugin || processed.has(pluginId)) {
- continue;
- }
- processed.add(pluginId);
- collect(pluginId, plugin.environments, slots.envMap);
- collect(pluginId, plugin.processors, slots.processorMap);
- collect(pluginId, plugin.rules, slots.ruleMap, normalizePluginRule);
- }
- }
- deleteMutationMethods(slots.envMap);
- deleteMutationMethods(slots.processorMap);
- deleteMutationMethods(slots.ruleMap);
- }
- /**
- * Create `envMap`, `processorMap`, `ruleMap` with the plugins in the config array.
- * @param {ConfigArray} instance The config elements.
- * @returns {ConfigArrayInternalSlots} The extracted config.
- */
- function ensurePluginMemberMaps(instance) {
- const slots = internalSlotsMap$2.get(instance);
- if (!slots.ruleMap) {
- initPluginMemberMaps(instance, slots);
- }
- return slots;
- }
- //------------------------------------------------------------------------------
- // Public Interface
- //------------------------------------------------------------------------------
- /**
- * The Config Array.
- *
- * `ConfigArray` instance contains all settings, parsers, and plugins.
- * You need to call `ConfigArray#extractConfig(filePath)` method in order to
- * extract, merge and get only the config data which is related to an arbitrary
- * file.
- * @extends {Array<ConfigArrayElement>}
- */
- class ConfigArray extends Array {
- /**
- * Get the plugin environments.
- * The returned map cannot be mutated.
- * @type {ReadonlyMap<string, Environment>} The plugin environments.
- */
- get pluginEnvironments() {
- return ensurePluginMemberMaps(this).envMap;
- }
- /**
- * Get the plugin processors.
- * The returned map cannot be mutated.
- * @type {ReadonlyMap<string, Processor>} The plugin processors.
- */
- get pluginProcessors() {
- return ensurePluginMemberMaps(this).processorMap;
- }
- /**
- * Get the plugin rules.
- * The returned map cannot be mutated.
- * @returns {ReadonlyMap<string, Rule>} The plugin rules.
- */
- get pluginRules() {
- return ensurePluginMemberMaps(this).ruleMap;
- }
- /**
- * Check if this config has `root` flag.
- * @returns {boolean} `true` if this config array is root.
- */
- isRoot() {
- for (let i = this.length - 1; i >= 0; --i) {
- const root = this[i].root;
- if (typeof root === "boolean") {
- return root;
- }
- }
- return false;
- }
- /**
- * Extract the config data which is related to a given file.
- * @param {string} filePath The absolute path to the target file.
- * @returns {ExtractedConfig} The extracted config data.
- */
- extractConfig(filePath) {
- const { cache } = internalSlotsMap$2.get(this);
- const indices = getMatchedIndices(this, filePath);
- const cacheKey = indices.join(",");
- if (!cache.has(cacheKey)) {
- cache.set(cacheKey, createConfig(this, indices));
- }
- return cache.get(cacheKey);
- }
- /**
- * Check if a given path is an additional lint target.
- * @param {string} filePath The absolute path to the target file.
- * @returns {boolean} `true` if the file is an additional lint target.
- */
- isAdditionalTargetPath(filePath) {
- for (const { criteria, type } of this) {
- if (
- type === "config" &&
- criteria &&
- !criteria.endsWithWildcard &&
- criteria.test(filePath)
- ) {
- return true;
- }
- }
- return false;
- }
- }
- /**
- * Get the used extracted configs.
- * CLIEngine will use this method to collect used deprecated rules.
- * @param {ConfigArray} instance The config array object to get.
- * @returns {ExtractedConfig[]} The used extracted configs.
- * @private
- */
- function getUsedExtractedConfigs(instance) {
- const { cache } = internalSlotsMap$2.get(instance);
- return Array.from(cache.values());
- }
- /**
- * @fileoverview `ConfigDependency` class.
- *
- * `ConfigDependency` class expresses a loaded parser or plugin.
- *
- * If the parser or plugin was loaded successfully, it has `definition` property
- * and `filePath` property. Otherwise, it has `error` property.
- *
- * When `JSON.stringify()` converted a `ConfigDependency` object to a JSON, it
- * omits `definition` property.
- *
- * `ConfigArrayFactory` creates `ConfigDependency` objects when it loads parsers
- * or plugins.
- *
- * @author Toru Nagashima <https://github.com/mysticatea>
- */
- /**
- * The class is to store parsers or plugins.
- * This class hides the loaded object from `JSON.stringify()` and `console.log`.
- * @template T
- */
- class ConfigDependency {
- /**
- * Initialize this instance.
- * @param {Object} data The dependency data.
- * @param {T} [data.definition] The dependency if the loading succeeded.
- * @param {Error} [data.error] The error object if the loading failed.
- * @param {string} [data.filePath] The actual path to the dependency if the loading succeeded.
- * @param {string} data.id The ID of this dependency.
- * @param {string} data.importerName The name of the config file which loads this dependency.
- * @param {string} data.importerPath The path to the config file which loads this dependency.
- */
- constructor({
- definition = null,
- error = null,
- filePath = null,
- id,
- importerName,
- importerPath
- }) {
- /**
- * The loaded dependency if the loading succeeded.
- * @type {T|null}
- */
- this.definition = definition;
- /**
- * The error object if the loading failed.
- * @type {Error|null}
- */
- this.error = error;
- /**
- * The loaded dependency if the loading succeeded.
- * @type {string|null}
- */
- this.filePath = filePath;
- /**
- * The ID of this dependency.
- * @type {string}
- */
- this.id = id;
- /**
- * The name of the config file which loads this dependency.
- * @type {string}
- */
- this.importerName = importerName;
- /**
- * The path to the config file which loads this dependency.
- * @type {string}
- */
- this.importerPath = importerPath;
- }
- // eslint-disable-next-line jsdoc/require-description
- /**
- * @returns {Object} a JSON compatible object.
- */
- toJSON() {
- const obj = this[util__default["default"].inspect.custom]();
- // Display `error.message` (`Error#message` is unenumerable).
- if (obj.error instanceof Error) {
- obj.error = { ...obj.error, message: obj.error.message };
- }
- return obj;
- }
- // eslint-disable-next-line jsdoc/require-description
- /**
- * @returns {Object} an object to display by `console.log()`.
- */
- [util__default["default"].inspect.custom]() {
- const {
- definition: _ignore, // eslint-disable-line no-unused-vars
- ...obj
- } = this;
- return obj;
- }
- }
- /**
- * @fileoverview `OverrideTester` class.
- *
- * `OverrideTester` class handles `files` property and `excludedFiles` property
- * of `overrides` config.
- *
- * It provides one method.
- *
- * - `test(filePath)`
- * Test if a file path matches the pair of `files` property and
- * `excludedFiles` property. The `filePath` argument must be an absolute
- * path.
- *
- * `ConfigArrayFactory` creates `OverrideTester` objects when it processes
- * `overrides` properties.
- *
- * @author Toru Nagashima <https://github.com/mysticatea>
- */
- const { Minimatch } = minimatch__default["default"];
- const minimatchOpts = { dot: true, matchBase: true };
- /**
- * @typedef {Object} Pattern
- * @property {InstanceType<Minimatch>[] | null} includes The positive matchers.
- * @property {InstanceType<Minimatch>[] | null} excludes The negative matchers.
- */
- /**
- * Normalize a given pattern to an array.
- * @param {string|string[]|undefined} patterns A glob pattern or an array of glob patterns.
- * @returns {string[]|null} Normalized patterns.
- * @private
- */
- function normalizePatterns(patterns) {
- if (Array.isArray(patterns)) {
- return patterns.filter(Boolean);
- }
- if (typeof patterns === "string" && patterns) {
- return [patterns];
- }
- return [];
- }
- /**
- * Create the matchers of given patterns.
- * @param {string[]} patterns The patterns.
- * @returns {InstanceType<Minimatch>[] | null} The matchers.
- */
- function toMatcher(patterns) {
- if (patterns.length === 0) {
- return null;
- }
- return patterns.map(pattern => {
- if (/^\.[/\\]/u.test(pattern)) {
- return new Minimatch(
- pattern.slice(2),
- // `./*.js` should not match with `subdir/foo.js`
- { ...minimatchOpts, matchBase: false }
- );
- }
- return new Minimatch(pattern, minimatchOpts);
- });
- }
- /**
- * Convert a given matcher to string.
- * @param {Pattern} matchers The matchers.
- * @returns {string} The string expression of the matcher.
- */
- function patternToJson({ includes, excludes }) {
- return {
- includes: includes && includes.map(m => m.pattern),
- excludes: excludes && excludes.map(m => m.pattern)
- };
- }
- /**
- * The class to test given paths are matched by the patterns.
- */
- class OverrideTester {
- /**
- * Create a tester with given criteria.
- * If there are no criteria, returns `null`.
- * @param {string|string[]} files The glob patterns for included files.
- * @param {string|string[]} excludedFiles The glob patterns for excluded files.
- * @param {string} basePath The path to the base directory to test paths.
- * @returns {OverrideTester|null} The created instance or `null`.
- */
- static create(files, excludedFiles, basePath) {
- const includePatterns = normalizePatterns(files);
- const excludePatterns = normalizePatterns(excludedFiles);
- let endsWithWildcard = false;
- if (includePatterns.length === 0) {
- return null;
- }
- // Rejects absolute paths or relative paths to parents.
- for (const pattern of includePatterns) {
- if (path__default["default"].isAbsolute(pattern) || pattern.includes("..")) {
- throw new Error(`Invalid override pattern (expected relative path not containing '..'): ${pattern}`);
- }
- if (pattern.endsWith("*")) {
- endsWithWildcard = true;
- }
- }
- for (const pattern of excludePatterns) {
- if (path__default["default"].isAbsolute(pattern) || pattern.includes("..")) {
- throw new Error(`Invalid override pattern (expected relative path not containing '..'): ${pattern}`);
- }
- }
- const includes = toMatcher(includePatterns);
- const excludes = toMatcher(excludePatterns);
- return new OverrideTester(
- [{ includes, excludes }],
- basePath,
- endsWithWildcard
- );
- }
- /**
- * Combine two testers by logical and.
- * If either of the testers was `null`, returns the other tester.
- * The `basePath` property of the two must be the same value.
- * @param {OverrideTester|null} a A tester.
- * @param {OverrideTester|null} b Another tester.
- * @returns {OverrideTester|null} Combined tester.
- */
- static and(a, b) {
- if (!b) {
- return a && new OverrideTester(
- a.patterns,
- a.basePath,
- a.endsWithWildcard
- );
- }
- if (!a) {
- return new OverrideTester(
- b.patterns,
- b.basePath,
- b.endsWithWildcard
- );
- }
- assert__default["default"].strictEqual(a.basePath, b.basePath);
- return new OverrideTester(
- a.patterns.concat(b.patterns),
- a.basePath,
- a.endsWithWildcard || b.endsWithWildcard
- );
- }
- /**
- * Initialize this instance.
- * @param {Pattern[]} patterns The matchers.
- * @param {string} basePath The base path.
- * @param {boolean} endsWithWildcard If `true` then a pattern ends with `*`.
- */
- constructor(patterns, basePath, endsWithWildcard = false) {
- /** @type {Pattern[]} */
- this.patterns = patterns;
- /** @type {string} */
- this.basePath = basePath;
- /** @type {boolean} */
- this.endsWithWildcard = endsWithWildcard;
- }
- /**
- * Test if a given path is matched or not.
- * @param {string} filePath The absolute path to the target file.
- * @returns {boolean} `true` if the path was matched.
- */
- test(filePath) {
- if (typeof filePath !== "string" || !path__default["default"].isAbsolute(filePath)) {
- throw new Error(`'filePath' should be an absolute path, but got ${filePath}.`);
- }
- const relativePath = path__default["default"].relative(this.basePath, filePath);
- return this.patterns.every(({ includes, excludes }) => (
- (!includes || includes.some(m => m.match(relativePath))) &&
- (!excludes || !excludes.some(m => m.match(relativePath)))
- ));
- }
- // eslint-disable-next-line jsdoc/require-description
- /**
- * @returns {Object} a JSON compatible object.
- */
- toJSON() {
- if (this.patterns.length === 1) {
- return {
- ...patternToJson(this.patterns[0]),
- basePath: this.basePath
- };
- }
- return {
- AND: this.patterns.map(patternToJson),
- basePath: this.basePath
- };
- }
- // eslint-disable-next-line jsdoc/require-description
- /**
- * @returns {Object} an object to display by `console.log()`.
- */
- [util__default["default"].inspect.custom]() {
- return this.toJSON();
- }
- }
- /**
- * @fileoverview `ConfigArray` class.
- * @author Toru Nagashima <https://github.com/mysticatea>
- */
- /**
- * @fileoverview Config file operations. This file must be usable in the browser,
- * so no Node-specific code can be here.
- * @author Nicholas C. Zakas
- */
- //------------------------------------------------------------------------------
- // Private
- //------------------------------------------------------------------------------
- const RULE_SEVERITY_STRINGS = ["off", "warn", "error"],
- RULE_SEVERITY = RULE_SEVERITY_STRINGS.reduce((map, value, index) => {
- map[value] = index;
- return map;
- }, {}),
- VALID_SEVERITIES = [0, 1, 2, "off", "warn", "error"];
- //------------------------------------------------------------------------------
- // Public Interface
- //------------------------------------------------------------------------------
- /**
- * Normalizes the severity value of a rule's configuration to a number
- * @param {(number|string|[number, ...*]|[string, ...*])} ruleConfig A rule's configuration value, generally
- * received from the user. A valid config value is either 0, 1, 2, the string "off" (treated the same as 0),
- * the string "warn" (treated the same as 1), the string "error" (treated the same as 2), or an array
- * whose first element is one of the above values. Strings are matched case-insensitively.
- * @returns {(0|1|2)} The numeric severity value if the config value was valid, otherwise 0.
- */
- function getRuleSeverity(ruleConfig) {
- const severityValue = Array.isArray(ruleConfig) ? ruleConfig[0] : ruleConfig;
- if (severityValue === 0 || severityValue === 1 || severityValue === 2) {
- return severityValue;
- }
- if (typeof severityValue === "string") {
- return RULE_SEVERITY[severityValue.toLowerCase()] || 0;
- }
- return 0;
- }
- /**
- * Converts old-style severity settings (0, 1, 2) into new-style
- * severity settings (off, warn, error) for all rules. Assumption is that severity
- * values have already been validated as correct.
- * @param {Object} config The config object to normalize.
- * @returns {void}
- */
- function normalizeToStrings(config) {
- if (config.rules) {
- Object.keys(config.rules).forEach(ruleId => {
- const ruleConfig = config.rules[ruleId];
- if (typeof ruleConfig === "number") {
- config.rules[ruleId] = RULE_SEVERITY_STRINGS[ruleConfig] || RULE_SEVERITY_STRINGS[0];
- } else if (Array.isArray(ruleConfig) && typeof ruleConfig[0] === "number") {
- ruleConfig[0] = RULE_SEVERITY_STRINGS[ruleConfig[0]] || RULE_SEVERITY_STRINGS[0];
- }
- });
- }
- }
- /**
- * Determines if the severity for the given rule configuration represents an error.
- * @param {int|string|Array} ruleConfig The configuration for an individual rule.
- * @returns {boolean} True if the rule represents an error, false if not.
- */
- function isErrorSeverity(ruleConfig) {
- return getRuleSeverity(ruleConfig) === 2;
- }
- /**
- * Checks whether a given config has valid severity or not.
- * @param {number|string|Array} ruleConfig The configuration for an individual rule.
- * @returns {boolean} `true` if the configuration has valid severity.
- */
- function isValidSeverity(ruleConfig) {
- let severity = Array.isArray(ruleConfig) ? ruleConfig[0] : ruleConfig;
- if (typeof severity === "string") {
- severity = severity.toLowerCase();
- }
- return VALID_SEVERITIES.indexOf(severity) !== -1;
- }
- /**
- * Checks whether every rule of a given config has valid severity or not.
- * @param {Object} config The configuration for rules.
- * @returns {boolean} `true` if the configuration has valid severity.
- */
- function isEverySeverityValid(config) {
- return Object.keys(config).every(ruleId => isValidSeverity(config[ruleId]));
- }
- /**
- * Normalizes a value for a global in a config
- * @param {(boolean|string|null)} configuredValue The value given for a global in configuration or in
- * a global directive comment
- * @returns {("readable"|"writeable"|"off")} The value normalized as a string
- * @throws Error if global value is invalid
- */
- function normalizeConfigGlobal(configuredValue) {
- switch (configuredValue) {
- case "off":
- return "off";
- case true:
- case "true":
- case "writeable":
- case "writable":
- return "writable";
- case null:
- case false:
- case "false":
- case "readable":
- case "readonly":
- return "readonly";
- default:
- throw new Error(`'${configuredValue}' is not a valid configuration for a global (use 'readonly', 'writable', or 'off')`);
- }
- }
- var ConfigOps = {
- __proto__: null,
- getRuleSeverity: getRuleSeverity,
- normalizeToStrings: normalizeToStrings,
- isErrorSeverity: isErrorSeverity,
- isValidSeverity: isValidSeverity,
- isEverySeverityValid: isEverySeverityValid,
- normalizeConfigGlobal: normalizeConfigGlobal
- };
- /**
- * @fileoverview Provide the function that emits deprecation warnings.
- * @author Toru Nagashima <http://github.com/mysticatea>
- */
- //------------------------------------------------------------------------------
- // Private
- //------------------------------------------------------------------------------
- // Defitions for deprecation warnings.
- const deprecationWarningMessages = {
- ESLINT_LEGACY_ECMAFEATURES:
- "The 'ecmaFeatures' config file property is deprecated and has no effect.",
- ESLINT_PERSONAL_CONFIG_LOAD:
- "'~/.eslintrc.*' config files have been deprecated. " +
- "Please use a config file per project or the '--config' option.",
- ESLINT_PERSONAL_CONFIG_SUPPRESS:
- "'~/.eslintrc.*' config files have been deprecated. " +
- "Please remove it or add 'root:true' to the config files in your " +
- "projects in order to avoid loading '~/.eslintrc.*' accidentally."
- };
- const sourceFileErrorCache = new Set();
- /**
- * Emits a deprecation warning containing a given filepath. A new deprecation warning is emitted
- * for each unique file path, but repeated invocations with the same file path have no effect.
- * No warnings are emitted if the `--no-deprecation` or `--no-warnings` Node runtime flags are active.
- * @param {string} source The name of the configuration source to report the warning for.
- * @param {string} errorCode The warning message to show.
- * @returns {void}
- */
- function emitDeprecationWarning(source, errorCode) {
- const cacheKey = JSON.stringify({ source, errorCode });
- if (sourceFileErrorCache.has(cacheKey)) {
- return;
- }
- sourceFileErrorCache.add(cacheKey);
- const rel = path__default["default"].relative(process.cwd(), source);
- const message = deprecationWarningMessages[errorCode];
- process.emitWarning(
- `${message} (found in "${rel}")`,
- "DeprecationWarning",
- errorCode
- );
- }
- /**
- * @fileoverview The instance of Ajv validator.
- * @author Evgeny Poberezkin
- */
- //-----------------------------------------------------------------------------
- // Helpers
- //-----------------------------------------------------------------------------
- /*
- * Copied from ajv/lib/refs/json-schema-draft-04.json
- * The MIT License (MIT)
- * Copyright (c) 2015-2017 Evgeny Poberezkin
- */
- const metaSchema = {
- id: "http://json-schema.org/draft-04/schema#",
- $schema: "http://json-schema.org/draft-04/schema#",
- description: "Core schema meta-schema",
- definitions: {
- schemaArray: {
- type: "array",
- minItems: 1,
- items: { $ref: "#" }
- },
- positiveInteger: {
- type: "integer",
- minimum: 0
- },
- positiveIntegerDefault0: {
- allOf: [{ $ref: "#/definitions/positiveInteger" }, { default: 0 }]
- },
- simpleTypes: {
- enum: ["array", "boolean", "integer", "null", "number", "object", "string"]
- },
- stringArray: {
- type: "array",
- items: { type: "string" },
- minItems: 1,
- uniqueItems: true
- }
- },
- type: "object",
- properties: {
- id: {
- type: "string"
- },
- $schema: {
- type: "string"
- },
- title: {
- type: "string"
- },
- description: {
- type: "string"
- },
- default: { },
- multipleOf: {
- type: "number",
- minimum: 0,
- exclusiveMinimum: true
- },
- maximum: {
- type: "number"
- },
- exclusiveMaximum: {
- type: "boolean",
- default: false
- },
- minimum: {
- type: "number"
- },
- exclusiveMinimum: {
- type: "boolean",
- default: false
- },
- maxLength: { $ref: "#/definitions/positiveInteger" },
- minLength: { $ref: "#/definitions/positiveIntegerDefault0" },
- pattern: {
- type: "string",
- format: "regex"
- },
- additionalItems: {
- anyOf: [
- { type: "boolean" },
- { $ref: "#" }
- ],
- default: { }
- },
- items: {
- anyOf: [
- { $ref: "#" },
- { $ref: "#/definitions/schemaArray" }
- ],
- default: { }
- },
- maxItems: { $ref: "#/definitions/positiveInteger" },
- minItems: { $ref: "#/definitions/positiveIntegerDefault0" },
- uniqueItems: {
- type: "boolean",
- default: false
- },
- maxProperties: { $ref: "#/definitions/positiveInteger" },
- minProperties: { $ref: "#/definitions/positiveIntegerDefault0" },
- required: { $ref: "#/definitions/stringArray" },
- additionalProperties: {
- anyOf: [
- { type: "boolean" },
- { $ref: "#" }
- ],
- default: { }
- },
- definitions: {
- type: "object",
- additionalProperties: { $ref: "#" },
- default: { }
- },
- properties: {
- type: "object",
- additionalProperties: { $ref: "#" },
- default: { }
- },
- patternProperties: {
- type: "object",
- additionalProperties: { $ref: "#" },
- default: { }
- },
- dependencies: {
- type: "object",
- additionalProperties: {
- anyOf: [
- { $ref: "#" },
- { $ref: "#/definitions/stringArray" }
- ]
- }
- },
- enum: {
- type: "array",
- minItems: 1,
- uniqueItems: true
- },
- type: {
- anyOf: [
- { $ref: "#/definitions/simpleTypes" },
- {
- type: "array",
- items: { $ref: "#/definitions/simpleTypes" },
- minItems: 1,
- uniqueItems: true
- }
- ]
- },
- format: { type: "string" },
- allOf: { $ref: "#/definitions/schemaArray" },
- anyOf: { $ref: "#/definitions/schemaArray" },
- oneOf: { $ref: "#/definitions/schemaArray" },
- not: { $ref: "#" }
- },
- dependencies: {
- exclusiveMaximum: ["maximum"],
- exclusiveMinimum: ["minimum"]
- },
- default: { }
- };
- //------------------------------------------------------------------------------
- // Public Interface
- //------------------------------------------------------------------------------
- var ajvOrig = (additionalOptions = {}) => {
- const ajv = new Ajv__default["default"]({
- meta: false,
- useDefaults: true,
- validateSchema: false,
- missingRefs: "ignore",
- verbose: true,
- schemaId: "auto",
- ...additionalOptions
- });
- ajv.addMetaSchema(metaSchema);
- // eslint-disable-next-line no-underscore-dangle
- ajv._opts.defaultMeta = metaSchema.id;
- return ajv;
- };
- /**
- * @fileoverview Defines a schema for configs.
- * @author Sylvan Mably
- */
- const baseConfigProperties = {
- $schema: { type: "string" },
- env: { type: "object" },
- extends: { $ref: "#/definitions/stringOrStrings" },
- globals: { type: "object" },
- overrides: {
- type: "array",
- items: { $ref: "#/definitions/overrideConfig" },
- additionalItems: false
- },
- parser: { type: ["string", "null"] },
- parserOptions: { type: "object" },
- plugins: { type: "array" },
- processor: { type: "string" },
- rules: { type: "object" },
- settings: { type: "object" },
- noInlineConfig: { type: "boolean" },
- reportUnusedDisableDirectives: { type: "boolean" },
- ecmaFeatures: { type: "object" } // deprecated; logs a warning when used
- };
- const configSchema = {
- definitions: {
- stringOrStrings: {
- oneOf: [
- { type: "string" },
- {
- type: "array",
- items: { type: "string" },
- additionalItems: false
- }
- ]
- },
- stringOrStringsRequired: {
- oneOf: [
- { type: "string" },
- {
- type: "array",
- items: { type: "string" },
- additionalItems: false,
- minItems: 1
- }
- ]
- },
- // Config at top-level.
- objectConfig: {
- type: "object",
- properties: {
- root: { type: "boolean" },
- ignorePatterns: { $ref: "#/definitions/stringOrStrings" },
- ...baseConfigProperties
- },
- additionalProperties: false
- },
- // Config in `overrides`.
- overrideConfig: {
- type: "object",
- properties: {
- excludedFiles: { $ref: "#/definitions/stringOrStrings" },
- files: { $ref: "#/definitions/stringOrStringsRequired" },
- ...baseConfigProperties
- },
- required: ["files"],
- additionalProperties: false
- }
- },
- $ref: "#/definitions/objectConfig"
- };
- /**
- * @fileoverview Defines environment settings and globals.
- * @author Elan Shanker
- */
- //------------------------------------------------------------------------------
- // Helpers
- //------------------------------------------------------------------------------
- /**
- * Get the object that has difference.
- * @param {Record<string,boolean>} current The newer object.
- * @param {Record<string,boolean>} prev The older object.
- * @returns {Record<string,boolean>} The difference object.
- */
- function getDiff(current, prev) {
- const retv = {};
- for (const [key, value] of Object.entries(current)) {
- if (!Object.hasOwnProperty.call(prev, key)) {
- retv[key] = value;
- }
- }
- return retv;
- }
- const newGlobals2015 = getDiff(globals__default["default"].es2015, globals__default["default"].es5); // 19 variables such as Promise, Map, ...
- const newGlobals2017 = {
- Atomics: false,
- SharedArrayBuffer: false
- };
- const newGlobals2020 = {
- BigInt: false,
- BigInt64Array: false,
- BigUint64Array: false,
- globalThis: false
- };
- const newGlobals2021 = {
- AggregateError: false,
- FinalizationRegistry: false,
- WeakRef: false
- };
- //------------------------------------------------------------------------------
- // Public Interface
- //------------------------------------------------------------------------------
- /** @type {Map<string, import("../lib/shared/types").Environment>} */
- var environments = new Map(Object.entries({
- // Language
- builtin: {
- globals: globals__default["default"].es5
- },
- es6: {
- globals: newGlobals2015,
- parserOptions: {
- ecmaVersion: 6
- }
- },
- es2015: {
- globals: newGlobals2015,
- parserOptions: {
- ecmaVersion: 6
- }
- },
- es2016: {
- globals: newGlobals2015,
- parserOptions: {
- ecmaVersion: 7
- }
- },
- es2017: {
- globals: { ...newGlobals2015, ...newGlobals2017 },
- parserOptions: {
- ecmaVersion: 8
- }
- },
- es2018: {
- globals: { ...newGlobals2015, ...newGlobals2017 },
- parserOptions: {
- ecmaVersion: 9
- }
- },
- es2019: {
- globals: { ...newGlobals2015, ...newGlobals2017 },
- parserOptions: {
- ecmaVersion: 10
- }
- },
- es2020: {
- globals: { ...newGlobals2015, ...newGlobals2017, ...newGlobals2020 },
- parserOptions: {
- ecmaVersion: 11
- }
- },
- es2021: {
- globals: { ...newGlobals2015, ...newGlobals2017, ...newGlobals2020, ...newGlobals2021 },
- parserOptions: {
- ecmaVersion: 12
- }
- },
- es2022: {
- globals: { ...newGlobals2015, ...newGlobals2017, ...newGlobals2020, ...newGlobals2021 },
- parserOptions: {
- ecmaVersion: 13
- }
- },
- // Platforms
- browser: {
- globals: globals__default["default"].browser
- },
- node: {
- globals: globals__default["default"].node,
- parserOptions: {
- ecmaFeatures: {
- globalReturn: true
- }
- }
- },
- "shared-node-browser": {
- globals: globals__default["default"]["shared-node-browser"]
- },
- worker: {
- globals: globals__default["default"].worker
- },
- serviceworker: {
- globals: globals__default["default"].serviceworker
- },
- // Frameworks
- commonjs: {
- globals: globals__default["default"].commonjs,
- parserOptions: {
- ecmaFeatures: {
- globalReturn: true
- }
- }
- },
- amd: {
- globals: globals__default["default"].amd
- },
- mocha: {
- globals: globals__default["default"].mocha
- },
- jasmine: {
- globals: globals__default["default"].jasmine
- },
- jest: {
- globals: globals__default["default"].jest
- },
- phantomjs: {
- globals: globals__default["default"].phantomjs
- },
- jquery: {
- globals: globals__default["default"].jquery
- },
- qunit: {
- globals: globals__default["default"].qunit
- },
- prototypejs: {
- globals: globals__default["default"].prototypejs
- },
- shelljs: {
- globals: globals__default["default"].shelljs
- },
- meteor: {
- globals: globals__default["default"].meteor
- },
- mongo: {
- globals: globals__default["default"].mongo
- },
- protractor: {
- globals: globals__default["default"].protractor
- },
- applescript: {
- globals: globals__default["default"].applescript
- },
- nashorn: {
- globals: globals__default["default"].nashorn
- },
- atomtest: {
- globals: globals__default["default"].atomtest
- },
- embertest: {
- globals: globals__default["default"].embertest
- },
- webextensions: {
- globals: globals__default["default"].webextensions
- },
- greasemonkey: {
- globals: globals__default["default"].greasemonkey
- }
- }));
- /**
- * @fileoverview Validates configs.
- * @author Brandon Mills
- */
- const ajv = ajvOrig();
- const ruleValidators = new WeakMap();
- const noop = Function.prototype;
- //------------------------------------------------------------------------------
- // Private
- //------------------------------------------------------------------------------
- let validateSchema;
- const severityMap = {
- error: 2,
- warn: 1,
- off: 0
- };
- const validated = new WeakSet();
- //-----------------------------------------------------------------------------
- // Exports
- //-----------------------------------------------------------------------------
- class ConfigValidator {
- constructor({ builtInRules = new Map() } = {}) {
- this.builtInRules = builtInRules;
- }
- /**
- * Gets a complete options schema for a rule.
- * @param {{create: Function, schema: (Array|null)}} rule A new-style rule object
- * @returns {Object} JSON Schema for the rule's options.
- */
- getRuleOptionsSchema(rule) {
- if (!rule) {
- return null;
- }
- const schema = rule.schema || rule.meta && rule.meta.schema;
- // Given a tuple of schemas, insert warning level at the beginning
- if (Array.isArray(schema)) {
- if (schema.length) {
- return {
- type: "array",
- items: schema,
- minItems: 0,
- maxItems: schema.length
- };
- }
- return {
- type: "array",
- minItems: 0,
- maxItems: 0
- };
- }
- // Given a full schema, leave it alone
- return schema || null;
- }
- /**
- * Validates a rule's severity and returns the severity value. Throws an error if the severity is invalid.
- * @param {options} options The given options for the rule.
- * @returns {number|string} The rule's severity value
- */
- validateRuleSeverity(options) {
- const severity = Array.isArray(options) ? options[0] : options;
- const normSeverity = typeof severity === "string" ? severityMap[severity.toLowerCase()] : severity;
- if (normSeverity === 0 || normSeverity === 1 || normSeverity === 2) {
- return normSeverity;
- }
- 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`);
- }
- /**
- * Validates the non-severity options passed to a rule, based on its schema.
- * @param {{create: Function}} rule The rule to validate
- * @param {Array} localOptions The options for the rule, excluding severity
- * @returns {void}
- */
- validateRuleSchema(rule, localOptions) {
- if (!ruleValidators.has(rule)) {
- const schema = this.getRuleOptionsSchema(rule);
- if (schema) {
- ruleValidators.set(rule, ajv.compile(schema));
- }
- }
- const validateRule = ruleValidators.get(rule);
- if (validateRule) {
- validateRule(localOptions);
- if (validateRule.errors) {
- throw new Error(validateRule.errors.map(
- error => `\tValue ${JSON.stringify(error.data)} ${error.message}.\n`
- ).join(""));
- }
- }
- }
- /**
- * Validates a rule's options against its schema.
- * @param {{create: Function}|null} rule The rule that the config is being validated for
- * @param {string} ruleId The rule's unique name.
- * @param {Array|number} options The given options for the rule.
- * @param {string|null} source The name of the configuration source to report in any errors. If null or undefined,
- * no source is prepended to the message.
- * @returns {void}
- */
- validateRuleOptions(rule, ruleId, options, source = null) {
- try {
- const severity = this.validateRuleSeverity(options);
- if (severity !== 0) {
- this.validateRuleSchema(rule, Array.isArray(options) ? options.slice(1) : []);
- }
- } catch (err) {
- const enhancedMessage = `Configuration for rule "${ruleId}" is invalid:\n${err.message}`;
- if (typeof source === "string") {
- throw new Error(`${source}:\n\t${enhancedMessage}`);
- } else {
- throw new Error(enhancedMessage);
- }
- }
- }
- /**
- * Validates an environment object
- * @param {Object} environment The environment config object to validate.
- * @param {string} source The name of the configuration source to report in any errors.
- * @param {function(envId:string): Object} [getAdditionalEnv] A map from strings to loaded environments.
- * @returns {void}
- */
- validateEnvironment(
- environment,
- source,
- getAdditionalEnv = noop
- ) {
- // not having an environment is ok
- if (!environment) {
- return;
- }
- Object.keys(environment).forEach(id => {
- const env = getAdditionalEnv(id) || environments.get(id) || null;
- if (!env) {
- const message = `${source}:\n\tEnvironment key "${id}" is unknown\n`;
- throw new Error(message);
- }
- });
- }
- /**
- * Validates a rules config object
- * @param {Object} rulesConfig The rules config object to validate.
- * @param {string} source The name of the configuration source to report in any errors.
- * @param {function(ruleId:string): Object} getAdditionalRule A map from strings to loaded rules
- * @returns {void}
- */
- validateRules(
- rulesConfig,
- source,
- getAdditionalRule = noop
- ) {
- if (!rulesConfig) {
- return;
- }
- Object.keys(rulesConfig).forEach(id => {
- const rule = getAdditionalRule(id) || this.builtInRules.get(id) || null;
- this.validateRuleOptions(rule, id, rulesConfig[id], source);
- });
- }
- /**
- * Validates a `globals` section of a config file
- * @param {Object} globalsConfig The `globals` section
- * @param {string|null} source The name of the configuration source to report in the event of an error.
- * @returns {void}
- */
- validateGlobals(globalsConfig, source = null) {
- if (!globalsConfig) {
- return;
- }
- Object.entries(globalsConfig)
- .forEach(([configuredGlobal, configuredValue]) => {
- try {
- normalizeConfigGlobal(configuredValue);
- } catch (err) {
- throw new Error(`ESLint configuration of global '${configuredGlobal}' in ${source} is invalid:\n${err.message}`);
- }
- });
- }
- /**
- * Validate `processor` configuration.
- * @param {string|undefined} processorName The processor name.
- * @param {string} source The name of config file.
- * @param {function(id:string): Processor} getProcessor The getter of defined processors.
- * @returns {void}
- */
- validateProcessor(processorName, source, getProcessor) {
- if (processorName && !getProcessor(processorName)) {
- throw new Error(`ESLint configuration of processor in '${source}' is invalid: '${processorName}' was not found.`);
- }
- }
- /**
- * Formats an array of schema validation errors.
- * @param {Array} errors An array of error messages to format.
- * @returns {string} Formatted error message
- */
- formatErrors(errors) {
- return errors.map(error => {
- if (error.keyword === "additionalProperties") {
- const formattedPropertyPath = error.dataPath.length ? `${error.dataPath.slice(1)}.${error.params.additionalProperty}` : error.params.additionalProperty;
- return `Unexpected top-level property "${formattedPropertyPath}"`;
- }
- if (error.keyword === "type") {
- const formattedField = error.dataPath.slice(1);
- const formattedExpectedType = Array.isArray(error.schema) ? error.schema.join("/") : error.schema;
- const formattedValue = JSON.stringify(error.data);
- return `Property "${formattedField}" is the wrong type (expected ${formattedExpectedType} but got \`${formattedValue}\`)`;
- }
- const field = error.dataPath[0] === "." ? error.dataPath.slice(1) : error.dataPath;
- return `"${field}" ${error.message}. Value: ${JSON.stringify(error.data)}`;
- }).map(message => `\t- ${message}.\n`).join("");
- }
- /**
- * Validates the top level properties of the config object.
- * @param {Object} config The config object to validate.
- * @param {string} source The name of the configuration source to report in any errors.
- * @returns {void}
- */
- validateConfigSchema(config, source = null) {
- validateSchema = validateSchema || ajv.compile(configSchema);
- if (!validateSchema(config)) {
- throw new Error(`ESLint configuration in ${source} is invalid:\n${this.formatErrors(validateSchema.errors)}`);
- }
- if (Object.hasOwnProperty.call(config, "ecmaFeatures")) {
- emitDeprecationWarning(source, "ESLINT_LEGACY_ECMAFEATURES");
- }
- }
- /**
- * Validates an entire config object.
- * @param {Object} config The config object to validate.
- * @param {string} source The name of the configuration source to report in any errors.
- * @param {function(ruleId:string): Object} [getAdditionalRule] A map from strings to loaded rules.
- * @param {function(envId:string): Object} [getAdditionalEnv] A map from strings to loaded envs.
- * @returns {void}
- */
- validate(config, source, getAdditionalRule, getAdditionalEnv) {
- this.validateConfigSchema(config, source);
- this.validateRules(config.rules, source, getAdditionalRule);
- this.validateEnvironment(config.env, source, getAdditionalEnv);
- this.validateGlobals(config.globals, source);
- for (const override of config.overrides || []) {
- this.validateRules(override.rules, source, getAdditionalRule);
- this.validateEnvironment(override.env, source, getAdditionalEnv);
- this.validateGlobals(config.globals, source);
- }
- }
- /**
- * Validate config array object.
- * @param {ConfigArray} configArray The config array to validate.
- * @returns {void}
- */
- validateConfigArray(configArray) {
- const getPluginEnv = Map.prototype.get.bind(configArray.pluginEnvironments);
- const getPluginProcessor = Map.prototype.get.bind(configArray.pluginProcessors);
- const getPluginRule = Map.prototype.get.bind(configArray.pluginRules);
- // Validate.
- for (const element of configArray) {
- if (validated.has(element)) {
- continue;
- }
- validated.add(element);
- this.validateEnvironment(element.env, element.name, getPluginEnv);
- this.validateGlobals(element.globals, element.name);
- this.validateProcessor(element.processor, element.name, getPluginProcessor);
- this.validateRules(element.rules, element.name, getPluginRule);
- }
- }
- }
- /**
- * @fileoverview Common helpers for naming of plugins, formatters and configs
- */
- const NAMESPACE_REGEX = /^@.*\//iu;
- /**
- * Brings package name to correct format based on prefix
- * @param {string} name The name of the package.
- * @param {string} prefix Can be either "eslint-plugin", "eslint-config" or "eslint-formatter"
- * @returns {string} Normalized name of the package
- * @private
- */
- function normalizePackageName(name, prefix) {
- let normalizedName = name;
- /**
- * On Windows, name can come in with Windows slashes instead of Unix slashes.
- * Normalize to Unix first to avoid errors later on.
- * https://github.com/eslint/eslint/issues/5644
- */
- if (normalizedName.includes("\\")) {
- normalizedName = normalizedName.replace(/\\/gu, "/");
- }
- if (normalizedName.charAt(0) === "@") {
- /**
- * it's a scoped package
- * package name is the prefix, or just a username
- */
- const scopedPackageShortcutRegex = new RegExp(`^(@[^/]+)(?:/(?:${prefix})?)?$`, "u"),
- scopedPackageNameRegex = new RegExp(`^${prefix}(-|$)`, "u");
- if (scopedPackageShortcutRegex.test(normalizedName)) {
- normalizedName = normalizedName.replace(scopedPackageShortcutRegex, `$1/${prefix}`);
- } else if (!scopedPackageNameRegex.test(normalizedName.split("/")[1])) {
- /**
- * for scoped packages, insert the prefix after the first / unless
- * the path is already @scope/eslint or @scope/eslint-xxx-yyy
- */
- normalizedName = normalizedName.replace(/^@([^/]+)\/(.*)$/u, `@$1/${prefix}-$2`);
- }
- } else if (!normalizedName.startsWith(`${prefix}-`)) {
- normalizedName = `${prefix}-${normalizedName}`;
- }
- return normalizedName;
- }
- /**
- * Removes the prefix from a fullname.
- * @param {string} fullname The term which may have the prefix.
- * @param {string} prefix The prefix to remove.
- * @returns {string} The term without prefix.
- */
- function getShorthandName(fullname, prefix) {
- if (fullname[0] === "@") {
- let matchResult = new RegExp(`^(@[^/]+)/${prefix}$`, "u").exec(fullname);
- if (matchResult) {
- return matchResult[1];
- }
- matchResult = new RegExp(`^(@[^/]+)/${prefix}-(.+)$`, "u").exec(fullname);
- if (matchResult) {
- return `${matchResult[1]}/${matchResult[2]}`;
- }
- } else if (fullname.startsWith(`${prefix}-`)) {
- return fullname.slice(prefix.length + 1);
- }
- return fullname;
- }
- /**
- * Gets the scope (namespace) of a term.
- * @param {string} term The term which may have the namespace.
- * @returns {string} The namespace of the term if it has one.
- */
- function getNamespaceFromTerm(term) {
- const match = term.match(NAMESPACE_REGEX);
- return match ? match[0] : "";
- }
- var naming = {
- __proto__: null,
- normalizePackageName: normalizePackageName,
- getShorthandName: getShorthandName,
- getNamespaceFromTerm: getNamespaceFromTerm
- };
- /**
- * Utility for resolving a module relative to another module
- * @author Teddy Katz
- */
- /*
- * `Module.createRequire` is added in v12.2.0. It supports URL as well.
- * We only support the case where the argument is a filepath, not a URL.
- */
- const createRequire = Module__default["default"].createRequire;
- /**
- * Resolves a Node module relative to another module
- * @param {string} moduleName The name of a Node module, or a path to a Node module.
- * @param {string} relativeToPath An absolute path indicating the module that `moduleName` should be resolved relative to. This must be
- * a file rather than a directory, but the file need not actually exist.
- * @returns {string} The absolute path that would result from calling `require.resolve(moduleName)` in a file located at `relativeToPath`
- */
- function resolve(moduleName, relativeToPath) {
- try {
- return createRequire(relativeToPath).resolve(moduleName);
- } catch (error) {
- // This `if` block is for older Node.js than 12.0.0. We can remove this block in the future.
- if (
- typeof error === "object" &&
- error !== null &&
- error.code === "MODULE_NOT_FOUND" &&
- !error.requireStack &&
- error.message.includes(moduleName)
- ) {
- error.message += `\nRequire stack:\n- ${relativeToPath}`;
- }
- throw error;
- }
- }
- var ModuleResolver = {
- __proto__: null,
- resolve: resolve
- };
- /**
- * @fileoverview The factory of `ConfigArray` objects.
- *
- * This class provides methods to create `ConfigArray` instance.
- *
- * - `create(configData, options)`
- * Create a `ConfigArray` instance from a config data. This is to handle CLI
- * options except `--config`.
- * - `loadFile(filePath, options)`
- * Create a `ConfigArray` instance from a config file. This is to handle
- * `--config` option. If the file was not found, throws the following error:
- * - If the filename was `*.js`, a `MODULE_NOT_FOUND` error.
- * - If the filename was `package.json`, an IO error or an
- * `ESLINT_CONFIG_FIELD_NOT_FOUND` error.
- * - Otherwise, an IO error such as `ENOENT`.
- * - `loadInDirectory(directoryPath, options)`
- * Create a `ConfigArray` instance from a config file which is on a given
- * directory. This tries to load `.eslintrc.*` or `package.json`. If not
- * found, returns an empty `ConfigArray`.
- * - `loadESLintIgnore(filePath)`
- * Create a `ConfigArray` instance from a config file that is `.eslintignore`
- * format. This is to handle `--ignore-path` option.
- * - `loadDefaultESLintIgnore()`
- * Create a `ConfigArray` instance from `.eslintignore` or `package.json` in
- * the current working directory.
- *
- * `ConfigArrayFactory` class has the responsibility that loads configuration
- * files, including loading `extends`, `parser`, and `plugins`. The created
- * `ConfigArray` instance has the loaded `extends`, `parser`, and `plugins`.
- *
- * But this class doesn't handle cascading. `CascadingConfigArrayFactory` class
- * handles cascading and hierarchy.
- *
- * @author Toru Nagashima <https://github.com/mysticatea>
- */
- const require$1 = Module.createRequire(require('url').pathToFileURL(__filename).toString());
- const debug$2 = debugOrig__default["default"]("eslintrc:config-array-factory");
- //------------------------------------------------------------------------------
- // Helpers
- //------------------------------------------------------------------------------
- const configFilenames = [
- ".eslintrc.js",
- ".eslintrc.cjs",
- ".eslintrc.yaml",
- ".eslintrc.yml",
- ".eslintrc.json",
- ".eslintrc",
- "package.json"
- ];
- // Define types for VSCode IntelliSense.
- /** @typedef {import("./shared/types").ConfigData} ConfigData */
- /** @typedef {import("./shared/types").OverrideConfigData} OverrideConfigData */
- /** @typedef {import("./shared/types").Parser} Parser */
- /** @typedef {import("./shared/types").Plugin} Plugin */
- /** @typedef {import("./shared/types").Rule} Rule */
- /** @typedef {import("./config-array/config-dependency").DependentParser} DependentParser */
- /** @typedef {import("./config-array/config-dependency").DependentPlugin} DependentPlugin */
- /** @typedef {ConfigArray[0]} ConfigArrayElement */
- /**
- * @typedef {Object} ConfigArrayFactoryOptions
- * @property {Map<string,Plugin>} [additionalPluginPool] The map for additional plugins.
- * @property {string} [cwd] The path to the current working directory.
- * @property {string} [resolvePluginsRelativeTo] A path to the directory that plugins should be resolved from. Defaults to `cwd`.
- * @property {Map<string,Rule>} builtInRules The rules that are built in to ESLint.
- * @property {Object} [resolver=ModuleResolver] The module resolver object.
- * @property {string} eslintAllPath The path to the definitions for eslint:all.
- * @property {Function} getEslintAllConfig Returns the config data for eslint:all.
- * @property {string} eslintRecommendedPath The path to the definitions for eslint:recommended.
- * @property {Function} getEslintRecommendedConfig Returns the config data for eslint:recommended.
- */
- /**
- * @typedef {Object} ConfigArrayFactoryInternalSlots
- * @property {Map<string,Plugin>} additionalPluginPool The map for additional plugins.
- * @property {string} cwd The path to the current working directory.
- * @property {string | undefined} resolvePluginsRelativeTo An absolute path the the directory that plugins should be resolved from.
- * @property {Map<string,Rule>} builtInRules The rules that are built in to ESLint.
- * @property {Object} [resolver=ModuleResolver] The module resolver object.
- * @property {string} eslintAllPath The path to the definitions for eslint:all.
- * @property {Function} getEslintAllConfig Returns the config data for eslint:all.
- * @property {string} eslintRecommendedPath The path to the definitions for eslint:recommended.
- * @property {Function} getEslintRecommendedConfig Returns the config data for eslint:recommended.
- */
- /**
- * @typedef {Object} ConfigArrayFactoryLoadingContext
- * @property {string} filePath The path to the current configuration.
- * @property {string} matchBasePath The base path to resolve relative paths in `overrides[].files`, `overrides[].excludedFiles`, and `ignorePatterns`.
- * @property {string} name The name of the current configuration.
- * @property {string} pluginBasePath The base path to resolve plugins.
- * @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.
- */
- /**
- * @typedef {Object} ConfigArrayFactoryLoadingContext
- * @property {string} filePath The path to the current configuration.
- * @property {string} matchBasePath The base path to resolve relative paths in `overrides[].files`, `overrides[].excludedFiles`, and `ignorePatterns`.
- * @property {string} name The name of the current configuration.
- * @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.
- */
- /** @type {WeakMap<ConfigArrayFactory, ConfigArrayFactoryInternalSlots>} */
- const internalSlotsMap$1 = new WeakMap();
- /** @type {WeakMap<object, Plugin>} */
- const normalizedPlugins = new WeakMap();
- /**
- * Check if a given string is a file path.
- * @param {string} nameOrPath A module name or file path.
- * @returns {boolean} `true` if the `nameOrPath` is a file path.
- */
- function isFilePath(nameOrPath) {
- return (
- /^\.{1,2}[/\\]/u.test(nameOrPath) ||
- path__default["default"].isAbsolute(nameOrPath)
- );
- }
- /**
- * Convenience wrapper for synchronously reading file contents.
- * @param {string} filePath The filename to read.
- * @returns {string} The file contents, with the BOM removed.
- * @private
- */
- function readFile(filePath) {
- return fs__default["default"].readFileSync(filePath, "utf8").replace(/^\ufeff/u, "");
- }
- /**
- * Loads a YAML configuration from a file.
- * @param {string} filePath The filename to load.
- * @returns {ConfigData} The configuration object from the file.
- * @throws {Error} If the file cannot be read.
- * @private
- */
- function loadYAMLConfigFile(filePath) {
- debug$2(`Loading YAML config file: ${filePath}`);
- // lazy load YAML to improve performance when not used
- const yaml = require$1("js-yaml");
- try {
- // empty YAML file can be null, so always use
- return yaml.load(readFile(filePath)) || {};
- } catch (e) {
- debug$2(`Error reading YAML file: ${filePath}`);
- e.message = `Cannot read config file: ${filePath}\nError: ${e.message}`;
- throw e;
- }
- }
- /**
- * Loads a JSON configuration from a file.
- * @param {string} filePath The filename to load.
- * @returns {ConfigData} The configuration object from the file.
- * @throws {Error} If the file cannot be read.
- * @private
- */
- function loadJSONConfigFile(filePath) {
- debug$2(`Loading JSON config file: ${filePath}`);
- try {
- return JSON.parse(stripComments__default["default"](readFile(filePath)));
- } catch (e) {
- debug$2(`Error reading JSON file: ${filePath}`);
- e.message = `Cannot read config file: ${filePath}\nError: ${e.message}`;
- e.messageTemplate = "failed-to-read-json";
- e.messageData = {
- path: filePath,
- message: e.message
- };
- throw e;
- }
- }
- /**
- * Loads a legacy (.eslintrc) configuration from a file.
- * @param {string} filePath The filename to load.
- * @returns {ConfigData} The configuration object from the file.
- * @throws {Error} If the file cannot be read.
- * @private
- */
- function loadLegacyConfigFile(filePath) {
- debug$2(`Loading legacy config file: ${filePath}`);
- // lazy load YAML to improve performance when not used
- const yaml = require$1("js-yaml");
- try {
- return yaml.load(stripComments__default["default"](readFile(filePath))) || /* istanbul ignore next */ {};
- } catch (e) {
- debug$2("Error reading YAML file: %s\n%o", filePath, e);
- e.message = `Cannot read config file: ${filePath}\nError: ${e.message}`;
- throw e;
- }
- }
- /**
- * Loads a JavaScript configuration from a file.
- * @param {string} filePath The filename to load.
- * @returns {ConfigData} The configuration object from the file.
- * @throws {Error} If the file cannot be read.
- * @private
- */
- function loadJSConfigFile(filePath) {
- debug$2(`Loading JS config file: ${filePath}`);
- try {
- return importFresh__default["default"](filePath);
- } catch (e) {
- debug$2(`Error reading JavaScript file: ${filePath}`);
- e.message = `Cannot read config file: ${filePath}\nError: ${e.message}`;
- throw e;
- }
- }
- /**
- * Loads a configuration from a package.json file.
- * @param {string} filePath The filename to load.
- * @returns {ConfigData} The configuration object from the file.
- * @throws {Error} If the file cannot be read.
- * @private
- */
- function loadPackageJSONConfigFile(filePath) {
- debug$2(`Loading package.json config file: ${filePath}`);
- try {
- const packageData = loadJSONConfigFile(filePath);
- if (!Object.hasOwnProperty.call(packageData, "eslintConfig")) {
- throw Object.assign(
- new Error("package.json file doesn't have 'eslintConfig' field."),
- { code: "ESLINT_CONFIG_FIELD_NOT_FOUND" }
- );
- }
- return packageData.eslintConfig;
- } catch (e) {
- debug$2(`Error reading package.json file: ${filePath}`);
- e.message = `Cannot read config file: ${filePath}\nError: ${e.message}`;
- throw e;
- }
- }
- /**
- * Loads a `.eslintignore` from a file.
- * @param {string} filePath The filename to load.
- * @returns {string[]} The ignore patterns from the file.
- * @private
- */
- function loadESLintIgnoreFile(filePath) {
- debug$2(`Loading .eslintignore file: ${filePath}`);
- try {
- return readFile(filePath)
- .split(/\r?\n/gu)
- .filter(line => line.trim() !== "" && !line.startsWith("#"));
- } catch (e) {
- debug$2(`Error reading .eslintignore file: ${filePath}`);
- e.message = `Cannot read .eslintignore file: ${filePath}\nError: ${e.message}`;
- throw e;
- }
- }
- /**
- * Creates an error to notify about a missing config to extend from.
- * @param {string} configName The name of the missing config.
- * @param {string} importerName The name of the config that imported the missing config
- * @param {string} messageTemplate The text template to source error strings from.
- * @returns {Error} The error object to throw
- * @private
- */
- function configInvalidError(configName, importerName, messageTemplate) {
- return Object.assign(
- new Error(`Failed to load config "${configName}" to extend from.`),
- {
- messageTemplate,
- messageData: { configName, importerName }
- }
- );
- }
- /**
- * Loads a configuration file regardless of the source. Inspects the file path
- * to determine the correctly way to load the config file.
- * @param {string} filePath The path to the configuration.
- * @returns {ConfigData|null} The configuration information.
- * @private
- */
- function loadConfigFile(filePath) {
- switch (path__default["default"].extname(filePath)) {
- case ".js":
- case ".cjs":
- return loadJSConfigFile(filePath);
- case ".json":
- if (path__default["default"].basename(filePath) === "package.json") {
- return loadPackageJSONConfigFile(filePath);
- }
- return loadJSONConfigFile(filePath);
- case ".yaml":
- case ".yml":
- return loadYAMLConfigFile(filePath);
- default:
- return loadLegacyConfigFile(filePath);
- }
- }
- /**
- * Write debug log.
- * @param {string} request The requested module name.
- * @param {string} relativeTo The file path to resolve the request relative to.
- * @param {string} filePath The resolved file path.
- * @returns {void}
- */
- function writeDebugLogForLoading(request, relativeTo, filePath) {
- /* istanbul ignore next */
- if (debug$2.enabled) {
- let nameAndVersion = null;
- try {
- const packageJsonPath = resolve(
- `${request}/package.json`,
- relativeTo
- );
- const { version = "unknown" } = require$1(packageJsonPath);
- nameAndVersion = `${request}@${version}`;
- } catch (error) {
- debug$2("package.json was not found:", error.message);
- nameAndVersion = request;
- }
- debug$2("Loaded: %s (%s)", nameAndVersion, filePath);
- }
- }
- /**
- * Create a new context with default values.
- * @param {ConfigArrayFactoryInternalSlots} slots The internal slots.
- * @param {"config" | "ignore" | "implicit-processor" | undefined} providedType The type of the current configuration. Default is `"config"`.
- * @param {string | undefined} providedName The name of the current configuration. Default is the relative path from `cwd` to `filePath`.
- * @param {string | undefined} providedFilePath The path to the current configuration. Default is empty string.
- * @param {string | undefined} providedMatchBasePath The type of the current configuration. Default is the directory of `filePath` or `cwd`.
- * @returns {ConfigArrayFactoryLoadingContext} The created context.
- */
- function createContext(
- { cwd, resolvePluginsRelativeTo },
- providedType,
- providedName,
- providedFilePath,
- providedMatchBasePath
- ) {
- const filePath = providedFilePath
- ? path__default["default"].resolve(cwd, providedFilePath)
- : "";
- const matchBasePath =
- (providedMatchBasePath && path__default["default"].resolve(cwd, providedMatchBasePath)) ||
- (filePath && path__default["default"].dirname(filePath)) ||
- cwd;
- const name =
- providedName ||
- (filePath && path__default["default"].relative(cwd, filePath)) ||
- "";
- const pluginBasePath =
- resolvePluginsRelativeTo ||
- (filePath && path__default["default"].dirname(filePath)) ||
- cwd;
- const type = providedType || "config";
- return { filePath, matchBasePath, name, pluginBasePath, type };
- }
- /**
- * Normalize a given plugin.
- * - Ensure the object to have four properties: configs, environments, processors, and rules.
- * - Ensure the object to not have other properties.
- * @param {Plugin} plugin The plugin to normalize.
- * @returns {Plugin} The normalized plugin.
- */
- function normalizePlugin(plugin) {
- // first check the cache
- let normalizedPlugin = normalizedPlugins.get(plugin);
- if (normalizedPlugin) {
- return normalizedPlugin;
- }
- normalizedPlugin = {
- configs: plugin.configs || {},
- environments: plugin.environments || {},
- processors: plugin.processors || {},
- rules: plugin.rules || {}
- };
- // save the reference for later
- normalizedPlugins.set(plugin, normalizedPlugin);
- return normalizedPlugin;
- }
- //------------------------------------------------------------------------------
- // Public Interface
- //------------------------------------------------------------------------------
- /**
- * The factory of `ConfigArray` objects.
- */
- class ConfigArrayFactory {
- /**
- * Initialize this instance.
- * @param {ConfigArrayFactoryOptions} [options] The map for additional plugins.
- */
- constructor({
- additionalPluginPool = new Map(),
- cwd = process.cwd(),
- resolvePluginsRelativeTo,
- builtInRules,
- resolver = ModuleResolver,
- eslintAllPath,
- getEslintAllConfig,
- eslintRecommendedPath,
- getEslintRecommendedConfig
- } = {}) {
- internalSlotsMap$1.set(this, {
- additionalPluginPool,
- cwd,
- resolvePluginsRelativeTo:
- resolvePluginsRelativeTo &&
- path__default["default"].resolve(cwd, resolvePluginsRelativeTo),
- builtInRules,
- resolver,
- eslintAllPath,
- getEslintAllConfig,
- eslintRecommendedPath,
- getEslintRecommendedConfig
- });
- }
- /**
- * Create `ConfigArray` instance from a config data.
- * @param {ConfigData|null} configData The config data to create.
- * @param {Object} [options] The options.
- * @param {string} [options.basePath] The base path to resolve relative paths in `overrides[].files`, `overrides[].excludedFiles`, and `ignorePatterns`.
- * @param {string} [options.filePath] The path to this config data.
- * @param {string} [options.name] The config name.
- * @returns {ConfigArray} Loaded config.
- */
- create(configData, { basePath, filePath, name } = {}) {
- if (!configData) {
- return new ConfigArray();
- }
- const slots = internalSlotsMap$1.get(this);
- const ctx = createContext(slots, "config", name, filePath, basePath);
- const elements = this._normalizeConfigData(configData, ctx);
- return new ConfigArray(...elements);
- }
- /**
- * Load a config file.
- * @param {string} filePath The path to a config file.
- * @param {Object} [options] The options.
- * @param {string} [options.basePath] The base path to resolve relative paths in `overrides[].files`, `overrides[].excludedFiles`, and `ignorePatterns`.
- * @param {string} [options.name] The config name.
- * @returns {ConfigArray} Loaded config.
- */
- loadFile(filePath, { basePath, name } = {}) {
- const slots = internalSlotsMap$1.get(this);
- const ctx = createContext(slots, "config", name, filePath, basePath);
- return new ConfigArray(...this._loadConfigData(ctx));
- }
- /**
- * Load the config file on a given directory if exists.
- * @param {string} directoryPath The path to a directory.
- * @param {Object} [options] The options.
- * @param {string} [options.basePath] The base path to resolve relative paths in `overrides[].files`, `overrides[].excludedFiles`, and `ignorePatterns`.
- * @param {string} [options.name] The config name.
- * @returns {ConfigArray} Loaded config. An empty `ConfigArray` if any config doesn't exist.
- */
- loadInDirectory(directoryPath, { basePath, name } = {}) {
- const slots = internalSlotsMap$1.get(this);
- for (const filename of configFilenames) {
- const ctx = createContext(
- slots,
- "config",
- name,
- path__default["default"].join(directoryPath, filename),
- basePath
- );
- if (fs__default["default"].existsSync(ctx.filePath) && fs__default["default"].statSync(ctx.filePath).isFile()) {
- let configData;
- try {
- configData = loadConfigFile(ctx.filePath);
- } catch (error) {
- if (!error || error.code !== "ESLINT_CONFIG_FIELD_NOT_FOUND") {
- throw error;
- }
- }
- if (configData) {
- debug$2(`Config file found: ${ctx.filePath}`);
- return new ConfigArray(
- ...this._normalizeConfigData(configData, ctx)
- );
- }
- }
- }
- debug$2(`Config file not found on ${directoryPath}`);
- return new ConfigArray();
- }
- /**
- * Check if a config file on a given directory exists or not.
- * @param {string} directoryPath The path to a directory.
- * @returns {string | null} The path to the found config file. If not found then null.
- */
- static getPathToConfigFileInDirectory(directoryPath) {
- for (const filename of configFilenames) {
- const filePath = path__default["default"].join(directoryPath, filename);
- if (fs__default["default"].existsSync(filePath)) {
- if (filename === "package.json") {
- try {
- loadPackageJSONConfigFile(filePath);
- return filePath;
- } catch { /* ignore */ }
- } else {
- return filePath;
- }
- }
- }
- return null;
- }
- /**
- * Load `.eslintignore` file.
- * @param {string} filePath The path to a `.eslintignore` file to load.
- * @returns {ConfigArray} Loaded config. An empty `ConfigArray` if any config doesn't exist.
- */
- loadESLintIgnore(filePath) {
- const slots = internalSlotsMap$1.get(this);
- const ctx = createContext(
- slots,
- "ignore",
- void 0,
- filePath,
- slots.cwd
- );
- const ignorePatterns = loadESLintIgnoreFile(ctx.filePath);
- return new ConfigArray(
- ...this._normalizeESLintIgnoreData(ignorePatterns, ctx)
- );
- }
- /**
- * Load `.eslintignore` file in the current working directory.
- * @returns {ConfigArray} Loaded config. An empty `ConfigArray` if any config doesn't exist.
- */
- loadDefaultESLintIgnore() {
- const slots = internalSlotsMap$1.get(this);
- const eslintIgnorePath = path__default["default"].resolve(slots.cwd, ".eslintignore");
- const packageJsonPath = path__default["default"].resolve(slots.cwd, "package.json");
- if (fs__default["default"].existsSync(eslintIgnorePath)) {
- return this.loadESLintIgnore(eslintIgnorePath);
- }
- if (fs__default["default"].existsSync(packageJsonPath)) {
- const data = loadJSONConfigFile(packageJsonPath);
- if (Object.hasOwnProperty.call(data, "eslintIgnore")) {
- if (!Array.isArray(data.eslintIgnore)) {
- throw new Error("Package.json eslintIgnore property requires an array of paths");
- }
- const ctx = createContext(
- slots,
- "ignore",
- "eslintIgnore in package.json",
- packageJsonPath,
- slots.cwd
- );
- return new ConfigArray(
- ...this._normalizeESLintIgnoreData(data.eslintIgnore, ctx)
- );
- }
- }
- return new ConfigArray();
- }
- /**
- * Load a given config file.
- * @param {ConfigArrayFactoryLoadingContext} ctx The loading context.
- * @returns {IterableIterator<ConfigArrayElement>} Loaded config.
- * @private
- */
- _loadConfigData(ctx) {
- return this._normalizeConfigData(loadConfigFile(ctx.filePath), ctx);
- }
- /**
- * Normalize a given `.eslintignore` data to config array elements.
- * @param {string[]} ignorePatterns The patterns to ignore files.
- * @param {ConfigArrayFactoryLoadingContext} ctx The loading context.
- * @returns {IterableIterator<ConfigArrayElement>} The normalized config.
- * @private
- */
- *_normalizeESLintIgnoreData(ignorePatterns, ctx) {
- const elements = this._normalizeObjectConfigData(
- { ignorePatterns },
- ctx
- );
- // Set `ignorePattern.loose` flag for backward compatibility.
- for (const element of elements) {
- if (element.ignorePattern) {
- element.ignorePattern.loose = true;
- }
- yield element;
- }
- }
- /**
- * Normalize a given config to an array.
- * @param {ConfigData} configData The config data to normalize.
- * @param {ConfigArrayFactoryLoadingContext} ctx The loading context.
- * @returns {IterableIterator<ConfigArrayElement>} The normalized config.
- * @private
- */
- _normalizeConfigData(configData, ctx) {
- const validator = new ConfigValidator();
- validator.validateConfigSchema(configData, ctx.name || ctx.filePath);
- return this._normalizeObjectConfigData(configData, ctx);
- }
- /**
- * Normalize a given config to an array.
- * @param {ConfigData|OverrideConfigData} configData The config data to normalize.
- * @param {ConfigArrayFactoryLoadingContext} ctx The loading context.
- * @returns {IterableIterator<ConfigArrayElement>} The normalized config.
- * @private
- */
- *_normalizeObjectConfigData(configData, ctx) {
- const { files, excludedFiles, ...configBody } = configData;
- const criteria = OverrideTester.create(
- files,
- excludedFiles,
- ctx.matchBasePath
- );
- const elements = this._normalizeObjectConfigDataBody(configBody, ctx);
- // Apply the criteria to every element.
- for (const element of elements) {
- /*
- * Merge the criteria.
- * This is for the `overrides` entries that came from the
- * configurations of `overrides[].extends`.
- */
- element.criteria = OverrideTester.and(criteria, element.criteria);
- /*
- * Remove `root` property to ignore `root` settings which came from
- * `extends` in `overrides`.
- */
- if (element.criteria) {
- element.root = void 0;
- }
- yield element;
- }
- }
- /**
- * Normalize a given config to an array.
- * @param {ConfigData} configData The config data to normalize.
- * @param {ConfigArrayFactoryLoadingContext} ctx The loading context.
- * @returns {IterableIterator<ConfigArrayElement>} The normalized config.
- * @private
- */
- *_normalizeObjectConfigDataBody(
- {
- env,
- extends: extend,
- globals,
- ignorePatterns,
- noInlineConfig,
- parser: parserName,
- parserOptions,
- plugins: pluginList,
- processor,
- reportUnusedDisableDirectives,
- root,
- rules,
- settings,
- overrides: overrideList = []
- },
- ctx
- ) {
- const extendList = Array.isArray(extend) ? extend : [extend];
- const ignorePattern = ignorePatterns && new IgnorePattern(
- Array.isArray(ignorePatterns) ? ignorePatterns : [ignorePatterns],
- ctx.matchBasePath
- );
- // Flatten `extends`.
- for (const extendName of extendList.filter(Boolean)) {
- yield* this._loadExtends(extendName, ctx);
- }
- // Load parser & plugins.
- const parser = parserName && this._loadParser(parserName, ctx);
- const plugins = pluginList && this._loadPlugins(pluginList, ctx);
- // Yield pseudo config data for file extension processors.
- if (plugins) {
- yield* this._takeFileExtensionProcessors(plugins, ctx);
- }
- // Yield the config data except `extends` and `overrides`.
- yield {
- // Debug information.
- type: ctx.type,
- name: ctx.name,
- filePath: ctx.filePath,
- // Config data.
- criteria: null,
- env,
- globals,
- ignorePattern,
- noInlineConfig,
- parser,
- parserOptions,
- plugins,
- processor,
- reportUnusedDisableDirectives,
- root,
- rules,
- settings
- };
- // Flatten `overries`.
- for (let i = 0; i < overrideList.length; ++i) {
- yield* this._normalizeObjectConfigData(
- overrideList[i],
- { ...ctx, name: `${ctx.name}#overrides[${i}]` }
- );
- }
- }
- /**
- * Load configs of an element in `extends`.
- * @param {string} extendName The name of a base config.
- * @param {ConfigArrayFactoryLoadingContext} ctx The loading context.
- * @returns {IterableIterator<ConfigArrayElement>} The normalized config.
- * @private
- */
- _loadExtends(extendName, ctx) {
- debug$2("Loading {extends:%j} relative to %s", extendName, ctx.filePath);
- try {
- if (extendName.startsWith("eslint:")) {
- return this._loadExtendedBuiltInConfig(extendName, ctx);
- }
- if (extendName.startsWith("plugin:")) {
- return this._loadExtendedPluginConfig(extendName, ctx);
- }
- return this._loadExtendedShareableConfig(extendName, ctx);
- } catch (error) {
- error.message += `\nReferenced from: ${ctx.filePath || ctx.name}`;
- throw error;
- }
- }
- /**
- * Load configs of an element in `extends`.
- * @param {string} extendName The name of a base config.
- * @param {ConfigArrayFactoryLoadingContext} ctx The loading context.
- * @returns {IterableIterator<ConfigArrayElement>} The normalized config.
- * @private
- */
- _loadExtendedBuiltInConfig(extendName, ctx) {
- const {
- eslintAllPath,
- getEslintAllConfig,
- eslintRecommendedPath,
- getEslintRecommendedConfig
- } = internalSlotsMap$1.get(this);
- if (extendName === "eslint:recommended") {
- const name = `${ctx.name} » ${extendName}`;
- if (getEslintRecommendedConfig) {
- if (typeof getEslintRecommendedConfig !== "function") {
- throw new Error(`getEslintRecommendedConfig must be a function instead of '${getEslintRecommendedConfig}'`);
- }
- return this._normalizeConfigData(getEslintRecommendedConfig(), { ...ctx, name, filePath: "" });
- }
- return this._loadConfigData({
- ...ctx,
- name,
- filePath: eslintRecommendedPath
- });
- }
- if (extendName === "eslint:all") {
- const name = `${ctx.name} » ${extendName}`;
- if (getEslintAllConfig) {
- if (typeof getEslintAllConfig !== "function") {
- throw new Error(`getEslintAllConfig must be a function instead of '${getEslintAllConfig}'`);
- }
- return this._normalizeConfigData(getEslintAllConfig(), { ...ctx, name, filePath: "" });
- }
- return this._loadConfigData({
- ...ctx,
- name,
- filePath: eslintAllPath
- });
- }
- throw configInvalidError(extendName, ctx.name, "extend-config-missing");
- }
- /**
- * Load configs of an element in `extends`.
- * @param {string} extendName The name of a base config.
- * @param {ConfigArrayFactoryLoadingContext} ctx The loading context.
- * @returns {IterableIterator<ConfigArrayElement>} The normalized config.
- * @private
- */
- _loadExtendedPluginConfig(extendName, ctx) {
- const slashIndex = extendName.lastIndexOf("/");
- if (slashIndex === -1) {
- throw configInvalidError(extendName, ctx.filePath, "plugin-invalid");
- }
- const pluginName = extendName.slice("plugin:".length, slashIndex);
- const configName = extendName.slice(slashIndex + 1);
- if (isFilePath(pluginName)) {
- throw new Error("'extends' cannot use a file path for plugins.");
- }
- const plugin = this._loadPlugin(pluginName, ctx);
- const configData =
- plugin.definition &&
- plugin.definition.configs[configName];
- if (configData) {
- return this._normalizeConfigData(configData, {
- ...ctx,
- filePath: plugin.filePath || ctx.filePath,
- name: `${ctx.name} » plugin:${plugin.id}/${configName}`
- });
- }
- throw plugin.error || configInvalidError(extendName, ctx.filePath, "extend-config-missing");
- }
- /**
- * Load configs of an element in `extends`.
- * @param {string} extendName The name of a base config.
- * @param {ConfigArrayFactoryLoadingContext} ctx The loading context.
- * @returns {IterableIterator<ConfigArrayElement>} The normalized config.
- * @private
- */
- _loadExtendedShareableConfig(extendName, ctx) {
- const { cwd, resolver } = internalSlotsMap$1.get(this);
- const relativeTo = ctx.filePath || path__default["default"].join(cwd, "__placeholder__.js");
- let request;
- if (isFilePath(extendName)) {
- request = extendName;
- } else if (extendName.startsWith(".")) {
- request = `./${extendName}`; // For backward compatibility. A ton of tests depended on this behavior.
- } else {
- request = normalizePackageName(
- extendName,
- "eslint-config"
- );
- }
- let filePath;
- try {
- filePath = resolver.resolve(request, relativeTo);
- } catch (error) {
- /* istanbul ignore else */
- if (error && error.code === "MODULE_NOT_FOUND") {
- throw configInvalidError(extendName, ctx.filePath, "extend-config-missing");
- }
- throw error;
- }
- writeDebugLogForLoading(request, relativeTo, filePath);
- return this._loadConfigData({
- ...ctx,
- filePath,
- name: `${ctx.name} » ${request}`
- });
- }
- /**
- * Load given plugins.
- * @param {string[]} names The plugin names to load.
- * @param {ConfigArrayFactoryLoadingContext} ctx The loading context.
- * @returns {Record<string,DependentPlugin>} The loaded parser.
- * @private
- */
- _loadPlugins(names, ctx) {
- return names.reduce((map, name) => {
- if (isFilePath(name)) {
- throw new Error("Plugins array cannot includes file paths.");
- }
- const plugin = this._loadPlugin(name, ctx);
- map[plugin.id] = plugin;
- return map;
- }, {});
- }
- /**
- * Load a given parser.
- * @param {string} nameOrPath The package name or the path to a parser file.
- * @param {ConfigArrayFactoryLoadingContext} ctx The loading context.
- * @returns {DependentParser} The loaded parser.
- */
- _loadParser(nameOrPath, ctx) {
- debug$2("Loading parser %j from %s", nameOrPath, ctx.filePath);
- const { cwd, resolver } = internalSlotsMap$1.get(this);
- const relativeTo = ctx.filePath || path__default["default"].join(cwd, "__placeholder__.js");
- try {
- const filePath = resolver.resolve(nameOrPath, relativeTo);
- writeDebugLogForLoading(nameOrPath, relativeTo, filePath);
- return new ConfigDependency({
- definition: require$1(filePath),
- filePath,
- id: nameOrPath,
- importerName: ctx.name,
- importerPath: ctx.filePath
- });
- } catch (error) {
- // If the parser name is "espree", load the espree of ESLint.
- if (nameOrPath === "espree") {
- debug$2("Fallback espree.");
- return new ConfigDependency({
- definition: require$1("espree"),
- filePath: require$1.resolve("espree"),
- id: nameOrPath,
- importerName: ctx.name,
- importerPath: ctx.filePath
- });
- }
- debug$2("Failed to load parser '%s' declared in '%s'.", nameOrPath, ctx.name);
- error.message = `Failed to load parser '${nameOrPath}' declared in '${ctx.name}': ${error.message}`;
- return new ConfigDependency({
- error,
- id: nameOrPath,
- importerName: ctx.name,
- importerPath: ctx.filePath
- });
- }
- }
- /**
- * Load a given plugin.
- * @param {string} name The plugin name to load.
- * @param {ConfigArrayFactoryLoadingContext} ctx The loading context.
- * @returns {DependentPlugin} The loaded plugin.
- * @private
- */
- _loadPlugin(name, ctx) {
- debug$2("Loading plugin %j from %s", name, ctx.filePath);
- const { additionalPluginPool, resolver } = internalSlotsMap$1.get(this);
- const request = normalizePackageName(name, "eslint-plugin");
- const id = getShorthandName(request, "eslint-plugin");
- const relativeTo = path__default["default"].join(ctx.pluginBasePath, "__placeholder__.js");
- if (name.match(/\s+/u)) {
- const error = Object.assign(
- new Error(`Whitespace found in plugin name '${name}'`),
- {
- messageTemplate: "whitespace-found",
- messageData: { pluginName: request }
- }
- );
- return new ConfigDependency({
- error,
- id,
- importerName: ctx.name,
- importerPath: ctx.filePath
- });
- }
- // Check for additional pool.
- const plugin =
- additionalPluginPool.get(request) ||
- additionalPluginPool.get(id);
- if (plugin) {
- return new ConfigDependency({
- definition: normalizePlugin(plugin),
- filePath: "", // It's unknown where the plugin came from.
- id,
- importerName: ctx.name,
- importerPath: ctx.filePath
- });
- }
- let filePath;
- let error;
- try {
- filePath = resolver.resolve(request, relativeTo);
- } catch (resolveError) {
- error = resolveError;
- /* istanbul ignore else */
- if (error && error.code === "MODULE_NOT_FOUND") {
- error.messageTemplate = "plugin-missing";
- error.messageData = {
- pluginName: request,
- resolvePluginsRelativeTo: ctx.pluginBasePath,
- importerName: ctx.name
- };
- }
- }
- if (filePath) {
- try {
- writeDebugLogForLoading(request, relativeTo, filePath);
- const startTime = Date.now();
- const pluginDefinition = require$1(filePath);
- debug$2(`Plugin ${filePath} loaded in: ${Date.now() - startTime}ms`);
- return new ConfigDependency({
- definition: normalizePlugin(pluginDefinition),
- filePath,
- id,
- importerName: ctx.name,
- importerPath: ctx.filePath
- });
- } catch (loadError) {
- error = loadError;
- }
- }
- debug$2("Failed to load plugin '%s' declared in '%s'.", name, ctx.name);
- error.message = `Failed to load plugin '${name}' declared in '${ctx.name}': ${error.message}`;
- return new ConfigDependency({
- error,
- id,
- importerName: ctx.name,
- importerPath: ctx.filePath
- });
- }
- /**
- * Take file expression processors as config array elements.
- * @param {Record<string,DependentPlugin>} plugins The plugin definitions.
- * @param {ConfigArrayFactoryLoadingContext} ctx The loading context.
- * @returns {IterableIterator<ConfigArrayElement>} The config array elements of file expression processors.
- * @private
- */
- *_takeFileExtensionProcessors(plugins, ctx) {
- for (const pluginId of Object.keys(plugins)) {
- const processors =
- plugins[pluginId] &&
- plugins[pluginId].definition &&
- plugins[pluginId].definition.processors;
- if (!processors) {
- continue;
- }
- for (const processorId of Object.keys(processors)) {
- if (processorId.startsWith(".")) {
- yield* this._normalizeObjectConfigData(
- {
- files: [`*${processorId}`],
- processor: `${pluginId}/${processorId}`
- },
- {
- ...ctx,
- type: "implicit-processor",
- name: `${ctx.name}#processors["${pluginId}/${processorId}"]`
- }
- );
- }
- }
- }
- }
- }
- /**
- * @fileoverview `CascadingConfigArrayFactory` class.
- *
- * `CascadingConfigArrayFactory` class has a responsibility:
- *
- * 1. Handles cascading of config files.
- *
- * It provides two methods:
- *
- * - `getConfigArrayForFile(filePath)`
- * Get the corresponded configuration of a given file. This method doesn't
- * throw even if the given file didn't exist.
- * - `clearCache()`
- * Clear the internal cache. You have to call this method when
- * `additionalPluginPool` was updated if `baseConfig` or `cliConfig` depends
- * on the additional plugins. (`CLIEngine#addPlugin()` method calls this.)
- *
- * @author Toru Nagashima <https://github.com/mysticatea>
- */
- const debug$1 = debugOrig__default["default"]("eslintrc:cascading-config-array-factory");
- //------------------------------------------------------------------------------
- // Helpers
- //------------------------------------------------------------------------------
- // Define types for VSCode IntelliSense.
- /** @typedef {import("./shared/types").ConfigData} ConfigData */
- /** @typedef {import("./shared/types").Parser} Parser */
- /** @typedef {import("./shared/types").Plugin} Plugin */
- /** @typedef {import("./shared/types").Rule} Rule */
- /** @typedef {ReturnType<ConfigArrayFactory["create"]>} ConfigArray */
- /**
- * @typedef {Object} CascadingConfigArrayFactoryOptions
- * @property {Map<string,Plugin>} [additionalPluginPool] The map for additional plugins.
- * @property {ConfigData} [baseConfig] The config by `baseConfig` option.
- * @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.
- * @property {string} [cwd] The base directory to start lookup.
- * @property {string} [ignorePath] The path to the alternative file of `.eslintignore`.
- * @property {string[]} [rulePaths] The value of `--rulesdir` option.
- * @property {string} [specificConfigPath] The value of `--config` option.
- * @property {boolean} [useEslintrc] if `false` then it doesn't load config files.
- * @property {Function} loadRules The function to use to load rules.
- * @property {Map<string,Rule>} builtInRules The rules that are built in to ESLint.
- * @property {Object} [resolver=ModuleResolver] The module resolver object.
- * @property {string} eslintAllPath The path to the definitions for eslint:all.
- * @property {Function} getEslintAllConfig Returns the config data for eslint:all.
- * @property {string} eslintRecommendedPath The path to the definitions for eslint:recommended.
- * @property {Function} getEslintRecommendedConfig Returns the config data for eslint:recommended.
- */
- /**
- * @typedef {Object} CascadingConfigArrayFactoryInternalSlots
- * @property {ConfigArray} baseConfigArray The config array of `baseConfig` option.
- * @property {ConfigData} baseConfigData The config data of `baseConfig` option. This is used to reset `baseConfigArray`.
- * @property {ConfigArray} cliConfigArray The config array of CLI options.
- * @property {ConfigData} cliConfigData The config data of CLI options. This is used to reset `cliConfigArray`.
- * @property {ConfigArrayFactory} configArrayFactory The factory for config arrays.
- * @property {Map<string, ConfigArray>} configCache The cache from directory paths to config arrays.
- * @property {string} cwd The base directory to start lookup.
- * @property {WeakMap<ConfigArray, ConfigArray>} finalizeCache The cache from config arrays to finalized config arrays.
- * @property {string} [ignorePath] The path to the alternative file of `.eslintignore`.
- * @property {string[]|null} rulePaths The value of `--rulesdir` option. This is used to reset `baseConfigArray`.
- * @property {string|null} specificConfigPath The value of `--config` option. This is used to reset `cliConfigArray`.
- * @property {boolean} useEslintrc if `false` then it doesn't load config files.
- * @property {Function} loadRules The function to use to load rules.
- * @property {Map<string,Rule>} builtInRules The rules that are built in to ESLint.
- * @property {Object} [resolver=ModuleResolver] The module resolver object.
- * @property {string} eslintAllPath The path to the definitions for eslint:all.
- * @property {Function} getEslintAllConfig Returns the config data for eslint:all.
- * @property {string} eslintRecommendedPath The path to the definitions for eslint:recommended.
- * @property {Function} getEslintRecommendedConfig Returns the config data for eslint:recommended.
- */
- /** @type {WeakMap<CascadingConfigArrayFactory, CascadingConfigArrayFactoryInternalSlots>} */
- const internalSlotsMap = new WeakMap();
- /**
- * Create the config array from `baseConfig` and `rulePaths`.
- * @param {CascadingConfigArrayFactoryInternalSlots} slots The slots.
- * @returns {ConfigArray} The config array of the base configs.
- */
- function createBaseConfigArray({
- configArrayFactory,
- baseConfigData,
- rulePaths,
- cwd,
- loadRules
- }) {
- const baseConfigArray = configArrayFactory.create(
- baseConfigData,
- { name: "BaseConfig" }
- );
- /*
- * Create the config array element for the default ignore patterns.
- * This element has `ignorePattern` property that ignores the default
- * patterns in the current working directory.
- */
- baseConfigArray.unshift(configArrayFactory.create(
- { ignorePatterns: IgnorePattern.DefaultPatterns },
- { name: "DefaultIgnorePattern" }
- )[0]);
- /*
- * Load rules `--rulesdir` option as a pseudo plugin.
- * Use a pseudo plugin to define rules of `--rulesdir`, so we can validate
- * the rule's options with only information in the config array.
- */
- if (rulePaths && rulePaths.length > 0) {
- baseConfigArray.push({
- type: "config",
- name: "--rulesdir",
- filePath: "",
- plugins: {
- "": new ConfigDependency({
- definition: {
- rules: rulePaths.reduce(
- (map, rulesPath) => Object.assign(
- map,
- loadRules(rulesPath, cwd)
- ),
- {}
- )
- },
- filePath: "",
- id: "",
- importerName: "--rulesdir",
- importerPath: ""
- })
- }
- });
- }
- return baseConfigArray;
- }
- /**
- * Create the config array from CLI options.
- * @param {CascadingConfigArrayFactoryInternalSlots} slots The slots.
- * @returns {ConfigArray} The config array of the base configs.
- */
- function createCLIConfigArray({
- cliConfigData,
- configArrayFactory,
- cwd,
- ignorePath,
- specificConfigPath
- }) {
- const cliConfigArray = configArrayFactory.create(
- cliConfigData,
- { name: "CLIOptions" }
- );
- cliConfigArray.unshift(
- ...(ignorePath
- ? configArrayFactory.loadESLintIgnore(ignorePath)
- : configArrayFactory.loadDefaultESLintIgnore())
- );
- if (specificConfigPath) {
- cliConfigArray.unshift(
- ...configArrayFactory.loadFile(
- specificConfigPath,
- { name: "--config", basePath: cwd }
- )
- );
- }
- return cliConfigArray;
- }
- /**
- * The error type when there are files matched by a glob, but all of them have been ignored.
- */
- class ConfigurationNotFoundError extends Error {
- // eslint-disable-next-line jsdoc/require-description
- /**
- * @param {string} directoryPath The directory path.
- */
- constructor(directoryPath) {
- super(`No ESLint configuration found in ${directoryPath}.`);
- this.messageTemplate = "no-config-found";
- this.messageData = { directoryPath };
- }
- }
- /**
- * This class provides the functionality that enumerates every file which is
- * matched by given glob patterns and that configuration.
- */
- class CascadingConfigArrayFactory {
- /**
- * Initialize this enumerator.
- * @param {CascadingConfigArrayFactoryOptions} options The options.
- */
- constructor({
- additionalPluginPool = new Map(),
- baseConfig: baseConfigData = null,
- cliConfig: cliConfigData = null,
- cwd = process.cwd(),
- ignorePath,
- resolvePluginsRelativeTo,
- rulePaths = [],
- specificConfigPath = null,
- useEslintrc = true,
- builtInRules = new Map(),
- loadRules,
- resolver,
- eslintRecommendedPath,
- getEslintRecommendedConfig,
- eslintAllPath,
- getEslintAllConfig
- } = {}) {
- const configArrayFactory = new ConfigArrayFactory({
- additionalPluginPool,
- cwd,
- resolvePluginsRelativeTo,
- builtInRules,
- resolver,
- eslintRecommendedPath,
- getEslintRecommendedConfig,
- eslintAllPath,
- getEslintAllConfig
- });
- internalSlotsMap.set(this, {
- baseConfigArray: createBaseConfigArray({
- baseConfigData,
- configArrayFactory,
- cwd,
- rulePaths,
- loadRules
- }),
- baseConfigData,
- cliConfigArray: createCLIConfigArray({
- cliConfigData,
- configArrayFactory,
- cwd,
- ignorePath,
- specificConfigPath
- }),
- cliConfigData,
- configArrayFactory,
- configCache: new Map(),
- cwd,
- finalizeCache: new WeakMap(),
- ignorePath,
- rulePaths,
- specificConfigPath,
- useEslintrc,
- builtInRules,
- loadRules
- });
- }
- /**
- * The path to the current working directory.
- * This is used by tests.
- * @type {string}
- */
- get cwd() {
- const { cwd } = internalSlotsMap.get(this);
- return cwd;
- }
- /**
- * Get the config array of a given file.
- * If `filePath` was not given, it returns the config which contains only
- * `baseConfigData` and `cliConfigData`.
- * @param {string} [filePath] The file path to a file.
- * @param {Object} [options] The options.
- * @param {boolean} [options.ignoreNotFoundError] If `true` then it doesn't throw `ConfigurationNotFoundError`.
- * @returns {ConfigArray} The config array of the file.
- */
- getConfigArrayForFile(filePath, { ignoreNotFoundError = false } = {}) {
- const {
- baseConfigArray,
- cliConfigArray,
- cwd
- } = internalSlotsMap.get(this);
- if (!filePath) {
- return new ConfigArray(...baseConfigArray, ...cliConfigArray);
- }
- const directoryPath = path__default["default"].dirname(path__default["default"].resolve(cwd, filePath));
- debug$1(`Load config files for ${directoryPath}.`);
- return this._finalizeConfigArray(
- this._loadConfigInAncestors(directoryPath),
- directoryPath,
- ignoreNotFoundError
- );
- }
- /**
- * Set the config data to override all configs.
- * Require to call `clearCache()` method after this method is called.
- * @param {ConfigData} configData The config data to override all configs.
- * @returns {void}
- */
- setOverrideConfig(configData) {
- const slots = internalSlotsMap.get(this);
- slots.cliConfigData = configData;
- }
- /**
- * Clear config cache.
- * @returns {void}
- */
- clearCache() {
- const slots = internalSlotsMap.get(this);
- slots.baseConfigArray = createBaseConfigArray(slots);
- slots.cliConfigArray = createCLIConfigArray(slots);
- slots.configCache.clear();
- }
- /**
- * Load and normalize config files from the ancestor directories.
- * @param {string} directoryPath The path to a leaf directory.
- * @param {boolean} configsExistInSubdirs `true` if configurations exist in subdirectories.
- * @returns {ConfigArray} The loaded config.
- * @private
- */
- _loadConfigInAncestors(directoryPath, configsExistInSubdirs = false) {
- const {
- baseConfigArray,
- configArrayFactory,
- configCache,
- cwd,
- useEslintrc
- } = internalSlotsMap.get(this);
- if (!useEslintrc) {
- return baseConfigArray;
- }
- let configArray = configCache.get(directoryPath);
- // Hit cache.
- if (configArray) {
- debug$1(`Cache hit: ${directoryPath}.`);
- return configArray;
- }
- debug$1(`No cache found: ${directoryPath}.`);
- const homePath = os__default["default"].homedir();
- // Consider this is root.
- if (directoryPath === homePath && cwd !== homePath) {
- debug$1("Stop traversing because of considered root.");
- if (configsExistInSubdirs) {
- const filePath = ConfigArrayFactory.getPathToConfigFileInDirectory(directoryPath);
- if (filePath) {
- emitDeprecationWarning(
- filePath,
- "ESLINT_PERSONAL_CONFIG_SUPPRESS"
- );
- }
- }
- return this._cacheConfig(directoryPath, baseConfigArray);
- }
- // Load the config on this directory.
- try {
- configArray = configArrayFactory.loadInDirectory(directoryPath);
- } catch (error) {
- /* istanbul ignore next */
- if (error.code === "EACCES") {
- debug$1("Stop traversing because of 'EACCES' error.");
- return this._cacheConfig(directoryPath, baseConfigArray);
- }
- throw error;
- }
- if (configArray.length > 0 && configArray.isRoot()) {
- debug$1("Stop traversing because of 'root:true'.");
- configArray.unshift(...baseConfigArray);
- return this._cacheConfig(directoryPath, configArray);
- }
- // Load from the ancestors and merge it.
- const parentPath = path__default["default"].dirname(directoryPath);
- const parentConfigArray = parentPath && parentPath !== directoryPath
- ? this._loadConfigInAncestors(
- parentPath,
- configsExistInSubdirs || configArray.length > 0
- )
- : baseConfigArray;
- if (configArray.length > 0) {
- configArray.unshift(...parentConfigArray);
- } else {
- configArray = parentConfigArray;
- }
- // Cache and return.
- return this._cacheConfig(directoryPath, configArray);
- }
- /**
- * Freeze and cache a given config.
- * @param {string} directoryPath The path to a directory as a cache key.
- * @param {ConfigArray} configArray The config array as a cache value.
- * @returns {ConfigArray} The `configArray` (frozen).
- */
- _cacheConfig(directoryPath, configArray) {
- const { configCache } = internalSlotsMap.get(this);
- Object.freeze(configArray);
- configCache.set(directoryPath, configArray);
- return configArray;
- }
- /**
- * Finalize a given config array.
- * Concatenate `--config` and other CLI options.
- * @param {ConfigArray} configArray The parent config array.
- * @param {string} directoryPath The path to the leaf directory to find config files.
- * @param {boolean} ignoreNotFoundError If `true` then it doesn't throw `ConfigurationNotFoundError`.
- * @returns {ConfigArray} The loaded config.
- * @private
- */
- _finalizeConfigArray(configArray, directoryPath, ignoreNotFoundError) {
- const {
- cliConfigArray,
- configArrayFactory,
- finalizeCache,
- useEslintrc,
- builtInRules
- } = internalSlotsMap.get(this);
- let finalConfigArray = finalizeCache.get(configArray);
- if (!finalConfigArray) {
- finalConfigArray = configArray;
- // Load the personal config if there are no regular config files.
- if (
- useEslintrc &&
- configArray.every(c => !c.filePath) &&
- cliConfigArray.every(c => !c.filePath) // `--config` option can be a file.
- ) {
- const homePath = os__default["default"].homedir();
- debug$1("Loading the config file of the home directory:", homePath);
- const personalConfigArray = configArrayFactory.loadInDirectory(
- homePath,
- { name: "PersonalConfig" }
- );
- if (
- personalConfigArray.length > 0 &&
- !directoryPath.startsWith(homePath)
- ) {
- const lastElement =
- personalConfigArray[personalConfigArray.length - 1];
- emitDeprecationWarning(
- lastElement.filePath,
- "ESLINT_PERSONAL_CONFIG_LOAD"
- );
- }
- finalConfigArray = finalConfigArray.concat(personalConfigArray);
- }
- // Apply CLI options.
- if (cliConfigArray.length > 0) {
- finalConfigArray = finalConfigArray.concat(cliConfigArray);
- }
- // Validate rule settings and environments.
- const validator = new ConfigValidator({
- builtInRules
- });
- validator.validateConfigArray(finalConfigArray);
- // Cache it.
- Object.freeze(finalConfigArray);
- finalizeCache.set(configArray, finalConfigArray);
- debug$1(
- "Configuration was determined: %o on %s",
- finalConfigArray,
- directoryPath
- );
- }
- // At least one element (the default ignore patterns) exists.
- if (!ignoreNotFoundError && useEslintrc && finalConfigArray.length <= 1) {
- throw new ConfigurationNotFoundError(directoryPath);
- }
- return finalConfigArray;
- }
- }
- /**
- * @fileoverview Compatibility class for flat config.
- * @author Nicholas C. Zakas
- */
- //-----------------------------------------------------------------------------
- // Helpers
- //-----------------------------------------------------------------------------
- /** @typedef {import("../../shared/types").Environment} Environment */
- /** @typedef {import("../../shared/types").Processor} Processor */
- const debug = debugOrig__default["default"]("eslintrc:flat-compat");
- const cafactory = Symbol("cafactory");
- /**
- * Translates an ESLintRC-style config object into a flag-config-style config
- * object.
- * @param {Object} eslintrcConfig An ESLintRC-style config object.
- * @param {Object} options Options to help translate the config.
- * @param {string} options.resolveConfigRelativeTo To the directory to resolve
- * configs from.
- * @param {string} options.resolvePluginsRelativeTo The directory to resolve
- * plugins from.
- * @param {ReadOnlyMap<string,Environment>} options.pluginEnvironments A map of plugin environment
- * names to objects.
- * @param {ReadOnlyMap<string,Processor>} options.pluginProcessors A map of plugin processor
- * names to objects.
- * @returns {Object} A flag-config-style config object.
- */
- function translateESLintRC(eslintrcConfig, {
- resolveConfigRelativeTo,
- resolvePluginsRelativeTo,
- pluginEnvironments,
- pluginProcessors
- }) {
- const flatConfig = {};
- const configs = [];
- const languageOptions = {};
- const linterOptions = {};
- const keysToCopy = ["settings", "rules", "processor"];
- const languageOptionsKeysToCopy = ["globals", "parser", "parserOptions"];
- const linterOptionsKeysToCopy = ["noInlineConfig", "reportUnusedDisableDirectives"];
- // check for special settings for eslint:all and eslint:recommended:
- if (eslintrcConfig.settings) {
- if (eslintrcConfig.settings["eslint:all"] === true) {
- return ["eslint:all"];
- }
- if (eslintrcConfig.settings["eslint:recommended"] === true) {
- return ["eslint:recommended"];
- }
- }
- // copy over simple translations
- for (const key of keysToCopy) {
- if (key in eslintrcConfig && typeof eslintrcConfig[key] !== "undefined") {
- flatConfig[key] = eslintrcConfig[key];
- }
- }
- // copy over languageOptions
- for (const key of languageOptionsKeysToCopy) {
- if (key in eslintrcConfig && typeof eslintrcConfig[key] !== "undefined") {
- // create the languageOptions key in the flat config
- flatConfig.languageOptions = languageOptions;
- if (key === "parser") {
- debug(`Resolving parser '${languageOptions[key]}' relative to ${resolveConfigRelativeTo}`);
- if (eslintrcConfig[key].error) {
- throw eslintrcConfig[key].error;
- }
- languageOptions[key] = eslintrcConfig[key].definition;
- continue;
- }
- // clone any object values that are in the eslintrc config
- if (eslintrcConfig[key] && typeof eslintrcConfig[key] === "object") {
- languageOptions[key] = {
- ...eslintrcConfig[key]
- };
- } else {
- languageOptions[key] = eslintrcConfig[key];
- }
- }
- }
- // copy over linterOptions
- for (const key of linterOptionsKeysToCopy) {
- if (key in eslintrcConfig && typeof eslintrcConfig[key] !== "undefined") {
- flatConfig.linterOptions = linterOptions;
- linterOptions[key] = eslintrcConfig[key];
- }
- }
- // move ecmaVersion a level up
- if (languageOptions.parserOptions) {
- if ("ecmaVersion" in languageOptions.parserOptions) {
- languageOptions.ecmaVersion = languageOptions.parserOptions.ecmaVersion;
- delete languageOptions.parserOptions.ecmaVersion;
- }
- if ("sourceType" in languageOptions.parserOptions) {
- languageOptions.sourceType = languageOptions.parserOptions.sourceType;
- delete languageOptions.parserOptions.sourceType;
- }
- // check to see if we even need parserOptions anymore and remove it if not
- if (Object.keys(languageOptions.parserOptions).length === 0) {
- delete languageOptions.parserOptions;
- }
- }
- // overrides
- if (eslintrcConfig.criteria) {
- flatConfig.files = [absoluteFilePath => eslintrcConfig.criteria.test(absoluteFilePath)];
- }
- // translate plugins
- if (eslintrcConfig.plugins && typeof eslintrcConfig.plugins === "object") {
- debug(`Translating plugins: ${eslintrcConfig.plugins}`);
- flatConfig.plugins = {};
- for (const pluginName of Object.keys(eslintrcConfig.plugins)) {
- debug(`Translating plugin: ${pluginName}`);
- debug(`Resolving plugin '${pluginName} relative to ${resolvePluginsRelativeTo}`);
- const { definition: plugin, error } = eslintrcConfig.plugins[pluginName];
- if (error) {
- throw error;
- }
- flatConfig.plugins[pluginName] = plugin;
- // create a config for any processors
- if (plugin.processors) {
- for (const processorName of Object.keys(plugin.processors)) {
- if (processorName.startsWith(".")) {
- debug(`Assigning processor: ${pluginName}/${processorName}`);
- configs.unshift({
- files: [`**/*${processorName}`],
- processor: pluginProcessors.get(`${pluginName}/${processorName}`)
- });
- }
- }
- }
- }
- }
- // translate env - must come after plugins
- if (eslintrcConfig.env && typeof eslintrcConfig.env === "object") {
- for (const envName of Object.keys(eslintrcConfig.env)) {
- // only add environments that are true
- if (eslintrcConfig.env[envName]) {
- debug(`Translating environment: ${envName}`);
- if (environments.has(envName)) {
- // built-in environments should be defined first
- configs.unshift(...translateESLintRC(environments.get(envName), {
- resolveConfigRelativeTo,
- resolvePluginsRelativeTo
- }));
- } else if (pluginEnvironments.has(envName)) {
- // if the environment comes from a plugin, it should come after the plugin config
- configs.push(...translateESLintRC(pluginEnvironments.get(envName), {
- resolveConfigRelativeTo,
- resolvePluginsRelativeTo
- }));
- }
- }
- }
- }
- // only add if there are actually keys in the config
- if (Object.keys(flatConfig).length > 0) {
- configs.push(flatConfig);
- }
- return configs;
- }
- //-----------------------------------------------------------------------------
- // Exports
- //-----------------------------------------------------------------------------
- /**
- * A compatibility class for working with configs.
- */
- class FlatCompat {
- constructor({
- baseDirectory = process.cwd(),
- resolvePluginsRelativeTo = baseDirectory
- } = {}) {
- this.baseDirectory = baseDirectory;
- this.resolvePluginsRelativeTo = resolvePluginsRelativeTo;
- this[cafactory] = new ConfigArrayFactory({
- cwd: baseDirectory,
- resolvePluginsRelativeTo,
- getEslintAllConfig: () => ({ settings: { "eslint:all": true } }),
- getEslintRecommendedConfig: () => ({ settings: { "eslint:recommended": true } })
- });
- }
- /**
- * Translates an ESLintRC-style config into a flag-config-style config.
- * @param {Object} eslintrcConfig The ESLintRC-style config object.
- * @returns {Object} A flag-config-style config object.
- */
- config(eslintrcConfig) {
- const eslintrcArray = this[cafactory].create(eslintrcConfig, {
- basePath: this.baseDirectory
- });
- const flatArray = [];
- let hasIgnorePatterns = false;
- eslintrcArray.forEach(configData => {
- if (configData.type === "config") {
- hasIgnorePatterns = hasIgnorePatterns || configData.ignorePattern;
- flatArray.push(...translateESLintRC(configData, {
- resolveConfigRelativeTo: path__default["default"].join(this.baseDirectory, "__placeholder.js"),
- resolvePluginsRelativeTo: path__default["default"].join(this.resolvePluginsRelativeTo, "__placeholder.js"),
- pluginEnvironments: eslintrcArray.pluginEnvironments,
- pluginProcessors: eslintrcArray.pluginProcessors
- }));
- }
- });
- // combine ignorePatterns to emulate ESLintRC behavior better
- if (hasIgnorePatterns) {
- flatArray.unshift({
- ignores: [filePath => {
- // Compute the final config for this file.
- // This filters config array elements by `files`/`excludedFiles` then merges the elements.
- const finalConfig = eslintrcArray.extractConfig(filePath);
- // Test the `ignorePattern` properties of the final config.
- return Boolean(finalConfig.ignores) && finalConfig.ignores(filePath);
- }]
- });
- }
- return flatArray;
- }
- /**
- * Translates the `env` section of an ESLintRC-style config.
- * @param {Object} envConfig The `env` section of an ESLintRC config.
- * @returns {Object} A flag-config object representing the environments.
- */
- env(envConfig) {
- return this.config({
- env: envConfig
- });
- }
- /**
- * Translates the `extends` section of an ESLintRC-style config.
- * @param {...string} configsToExtend The names of the configs to load.
- * @returns {Object} A flag-config object representing the config.
- */
- extends(...configsToExtend) {
- return this.config({
- extends: configsToExtend
- });
- }
- /**
- * Translates the `plugins` section of an ESLintRC-style config.
- * @param {...string} plugins The names of the plugins to load.
- * @returns {Object} A flag-config object representing the plugins.
- */
- plugins(...plugins) {
- return this.config({
- plugins
- });
- }
- }
- /**
- * @fileoverview Package exports for @eslint/eslintrc
- * @author Nicholas C. Zakas
- */
- //-----------------------------------------------------------------------------
- // Exports
- //-----------------------------------------------------------------------------
- const Legacy = {
- ConfigArray,
- createConfigArrayFactoryContext: createContext,
- CascadingConfigArrayFactory,
- ConfigArrayFactory,
- ConfigDependency,
- ExtractedConfig,
- IgnorePattern,
- OverrideTester,
- getUsedExtractedConfigs,
- environments,
- // shared
- ConfigOps,
- ConfigValidator,
- ModuleResolver,
- naming
- };
- exports.FlatCompat = FlatCompat;
- exports.Legacy = Legacy;
- //# sourceMappingURL=eslintrc.cjs.map
|