@bigbinary/eslint-plugin-neeto 1.8.2 → 1.8.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +1078 -956
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -1,8 +1,8 @@
1
1
  (function (global, factory) {
2
2
  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('fs'), require('path'), require('ramda'), require('@bigbinary/neeto-cist'), require('@bigbinary/neeto-commons-frontend/constants')) :
3
3
  typeof define === 'function' && define.amd ? define(['fs', 'path', 'ramda', '@bigbinary/neeto-cist', '@bigbinary/neeto-commons-frontend/constants'], factory) :
4
- (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global["@bigbinary/eslint-plugin-neeto"] = factory(global.fs, global.path$2, global.ramda, global["@bigbinary/neeto-cist"], global.neetoCommonsConstants));
5
- })(this, (function (fs, path$2, ramda, neetoCist, neetoCommonsConstants) { 'use strict';
4
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global["@bigbinary/eslint-plugin-neeto"] = factory(global.fs, global.path$1, global.ramda, global["@bigbinary/neeto-cist"], global.neetoCommonsConstants));
5
+ })(this, (function (fs, path$1, ramda, neetoCist, neetoCommonsConstants) { 'use strict';
6
6
 
7
7
  function _interopNamespaceDefault(e) {
8
8
  var n = Object.create(null);
@@ -24,7 +24,7 @@
24
24
  var neetoCommonsConstants__namespace = /*#__PURE__*/_interopNamespaceDefault(neetoCommonsConstants);
25
25
 
26
26
  /* eslint-disable @bigbinary/neeto/use-title-case-neeto-in-strings */
27
- const absolutePath$1 = jsPath => path$2.resolve(__dirname, "../../../..", jsPath);
27
+ const absolutePath$1 = jsPath => path$1.resolve(__dirname, "../../../..", jsPath);
28
28
  const loadJS$2 = jsPath => {
29
29
  try {
30
30
  return require(absolutePath$1(jsPath));
@@ -185,7 +185,7 @@
185
185
  rules
186
186
  };
187
187
 
188
- const absolutePath = jsPath => path$2.resolve(__dirname, "../../../..", jsPath);
188
+ const absolutePath = jsPath => path$1.resolve(__dirname, "../../../..", jsPath);
189
189
  const srcPath = fs.existsSync(absolutePath("src")) ? absolutePath("src") : absolutePath("app/javascript/src");
190
190
  const pathToTranslationsDir = `${srcPath}/translations`;
191
191
  const pathToResolveFile$1 = "resolve.js";
@@ -259,11 +259,11 @@
259
259
  }
260
260
  });
261
261
 
262
- const rootOfTheProject = path$2.join(__dirname, "../../../../");
262
+ const rootOfTheProject = path$1.join(__dirname, "../../../../");
263
263
  const pathToResolveFile = "resolve.js";
264
264
  const loadJS = jsPath => {
265
265
  try {
266
- return require(path$2.join(rootOfTheProject, jsPath));
266
+ return require(path$1.join(rootOfTheProject, jsPath));
267
267
  } catch {
268
268
  return {};
269
269
  }
@@ -285,7 +285,7 @@
285
285
  }
286
286
  });
287
287
 
288
- var version = "1.8.1";
288
+ var version = "1.8.2";
289
289
  var packageJson = {
290
290
  version: version};
291
291
 
@@ -701,7 +701,7 @@
701
701
  */
702
702
  const isInsideApisDirectory = context => {
703
703
  const filename = context.getFilename();
704
- const apisDirectory = path$2.resolve(APIS_DIRECTORY);
704
+ const apisDirectory = path$1.resolve(APIS_DIRECTORY);
705
705
  return filename.startsWith(apisDirectory) && filename !== `${apisDirectory}/axios.js`;
706
706
  };
707
707
 
@@ -712,7 +712,7 @@
712
712
  */
713
713
  const isInsideComponentsDirectory = context => {
714
714
  const filename = context.getFilename();
715
- const componentsDirectory = path$2.resolve(COMPONENTS_DIRECTORY);
715
+ const componentsDirectory = path$1.resolve(COMPONENTS_DIRECTORY);
716
716
  return filename.startsWith(componentsDirectory);
717
717
  };
718
718
 
@@ -785,7 +785,7 @@
785
785
  optional: true
786
786
  }, node);
787
787
  const optionalChainingOptimizedName = (funcName, node) => isOptionalChainingPresent(node) ? `_${funcName}` : funcName;
788
- const isExcludedFile = (excludedFiles, filename) => excludedFiles.some(filePath => filePath.test(path$2.resolve(filename)));
788
+ const isExcludedFile = (excludedFiles, filename) => excludedFiles.some(filePath => filePath.test(path$1.resolve(filename)));
789
789
  const parseJsonData = filePath => {
790
790
  try {
791
791
  const jsonData = fs.readFileSync(filePath).toString();
@@ -3531,11 +3531,6 @@
3531
3531
  })
3532
3532
  };
3533
3533
 
3534
- const isWindows = typeof process === 'object' &&
3535
- process &&
3536
- process.platform === 'win32';
3537
- var path$1 = isWindows ? { sep: '\\' } : { sep: '/' };
3538
-
3539
3534
  var balancedMatch = balanced$1;
3540
3535
  function balanced$1(a, b, str) {
3541
3536
  if (a instanceof RegExp) a = maybeMatch(a, str);
@@ -3675,7 +3670,7 @@
3675
3670
  str = '\\{\\}' + str.substr(2);
3676
3671
  }
3677
3672
 
3678
- return expand$1(escapeBraces(str), true).map(unescapeBraces);
3673
+ return expand(escapeBraces(str), true).map(unescapeBraces);
3679
3674
  }
3680
3675
 
3681
3676
  function embrace(str) {
@@ -3692,7 +3687,7 @@
3692
3687
  return i >= y;
3693
3688
  }
3694
3689
 
3695
- function expand$1(str, isTop) {
3690
+ function expand(str, isTop) {
3696
3691
  var expansions = [];
3697
3692
 
3698
3693
  var m = balanced('{', '}', str);
@@ -3701,7 +3696,7 @@
3701
3696
  // no need to expand pre, since it is guaranteed to be free of brace-sets
3702
3697
  var pre = m.pre;
3703
3698
  var post = m.post.length
3704
- ? expand$1(m.post, false)
3699
+ ? expand(m.post, false)
3705
3700
  : [''];
3706
3701
 
3707
3702
  if (/\$$/.test(m.pre)) {
@@ -3718,7 +3713,7 @@
3718
3713
  // {a},b}
3719
3714
  if (m.post.match(/,(?!,).*\}/)) {
3720
3715
  str = m.pre + '{' + m.body + escClose + m.post;
3721
- return expand$1(str);
3716
+ return expand(str);
3722
3717
  }
3723
3718
  return [str];
3724
3719
  }
@@ -3730,7 +3725,7 @@
3730
3725
  n = parseCommaParts(m.body);
3731
3726
  if (n.length === 1) {
3732
3727
  // x{{a,b}}y ==> x{a}y x{b}y
3733
- n = expand$1(n[0], false).map(embrace);
3728
+ n = expand(n[0], false).map(embrace);
3734
3729
  if (n.length === 1) {
3735
3730
  return post.map(function(p) {
3736
3731
  return m.pre + n[0] + p;
@@ -3785,7 +3780,7 @@
3785
3780
  N = [];
3786
3781
 
3787
3782
  for (var j = 0; j < n.length; j++) {
3788
- N.push.apply(N, expand$1(n[j], false));
3783
+ N.push.apply(N, expand(n[j], false));
3789
3784
  }
3790
3785
  }
3791
3786
 
@@ -3801,102 +3796,135 @@
3801
3796
  return expansions;
3802
3797
  }
3803
3798
 
3804
- const minimatch = minimatch_1 = (p, pattern, options = {}) => {
3805
- assertValidPattern(pattern);
3806
-
3807
- // shortcut: comments match nothing.
3808
- if (!options.nocomment && pattern.charAt(0) === '#') {
3809
- return false
3810
- }
3811
-
3812
- return new Minimatch(pattern, options).match(p)
3813
- };
3814
-
3815
- var minimatch_1 = minimatch;
3816
-
3817
- const path = path$1;
3818
- minimatch.sep = path.sep;
3819
-
3799
+ const minimatch = (p, pattern, options = {}) => {
3800
+ assertValidPattern(pattern);
3801
+ // shortcut: comments match nothing.
3802
+ if (!options.nocomment && pattern.charAt(0) === '#') {
3803
+ return false;
3804
+ }
3805
+ return new Minimatch(pattern, options).match(p);
3806
+ };
3807
+ // Optimized checking for the most common glob patterns.
3808
+ const starDotExtRE = /^\*+([^+@!?\*\[\(]*)$/;
3809
+ const starDotExtTest = (ext) => (f) => !f.startsWith('.') && f.endsWith(ext);
3810
+ const starDotExtTestDot = (ext) => (f) => f.endsWith(ext);
3811
+ const starDotExtTestNocase = (ext) => {
3812
+ ext = ext.toLowerCase();
3813
+ return (f) => !f.startsWith('.') && f.toLowerCase().endsWith(ext);
3814
+ };
3815
+ const starDotExtTestNocaseDot = (ext) => {
3816
+ ext = ext.toLowerCase();
3817
+ return (f) => f.toLowerCase().endsWith(ext);
3818
+ };
3819
+ const starDotStarRE = /^\*+\.\*+$/;
3820
+ const starDotStarTest = (f) => !f.startsWith('.') && f.includes('.');
3821
+ const starDotStarTestDot = (f) => f !== '.' && f !== '..' && f.includes('.');
3822
+ const dotStarRE = /^\.\*+$/;
3823
+ const dotStarTest = (f) => f !== '.' && f !== '..' && f.startsWith('.');
3824
+ const starRE = /^\*+$/;
3825
+ const starTest = (f) => f.length !== 0 && !f.startsWith('.');
3826
+ const starTestDot = (f) => f.length !== 0 && f !== '.' && f !== '..';
3827
+ const qmarksRE = /^\?+([^+@!?\*\[\(]*)?$/;
3828
+ const qmarksTestNocase = ([$0, ext = '']) => {
3829
+ const noext = qmarksTestNoExt([$0]);
3830
+ if (!ext)
3831
+ return noext;
3832
+ ext = ext.toLowerCase();
3833
+ return (f) => noext(f) && f.toLowerCase().endsWith(ext);
3834
+ };
3835
+ const qmarksTestNocaseDot = ([$0, ext = '']) => {
3836
+ const noext = qmarksTestNoExtDot([$0]);
3837
+ if (!ext)
3838
+ return noext;
3839
+ ext = ext.toLowerCase();
3840
+ return (f) => noext(f) && f.toLowerCase().endsWith(ext);
3841
+ };
3842
+ const qmarksTestDot = ([$0, ext = '']) => {
3843
+ const noext = qmarksTestNoExtDot([$0]);
3844
+ return !ext ? noext : (f) => noext(f) && f.endsWith(ext);
3845
+ };
3846
+ const qmarksTest = ([$0, ext = '']) => {
3847
+ const noext = qmarksTestNoExt([$0]);
3848
+ return !ext ? noext : (f) => noext(f) && f.endsWith(ext);
3849
+ };
3850
+ const qmarksTestNoExt = ([$0]) => {
3851
+ const len = $0.length;
3852
+ return (f) => f.length === len && !f.startsWith('.');
3853
+ };
3854
+ const qmarksTestNoExtDot = ([$0]) => {
3855
+ const len = $0.length;
3856
+ return (f) => f.length === len && f !== '.' && f !== '..';
3857
+ };
3858
+ /* c8 ignore start */
3859
+ const platform = typeof process === 'object' && process
3860
+ ? (typeof process.env === 'object' &&
3861
+ process.env &&
3862
+ process.env.__MINIMATCH_TESTING_PLATFORM__) ||
3863
+ process.platform
3864
+ : 'posix';
3865
+ const isWindows = platform === 'win32';
3866
+ const path = isWindows ? { sep: '\\' } : { sep: '/' };
3867
+ /* c8 ignore stop */
3868
+ const sep = path.sep;
3869
+ minimatch.sep = sep;
3820
3870
  const GLOBSTAR = Symbol('globstar **');
3821
3871
  minimatch.GLOBSTAR = GLOBSTAR;
3822
- const expand = braceExpansion;
3823
-
3824
3872
  const plTypes = {
3825
- '!': { open: '(?:(?!(?:', close: '))[^/]*?)'},
3826
- '?': { open: '(?:', close: ')?' },
3827
- '+': { open: '(?:', close: ')+' },
3828
- '*': { open: '(?:', close: ')*' },
3829
- '@': { open: '(?:', close: ')' }
3873
+ '!': { open: '(?:(?!(?:', close: '))[^/]*?)' },
3874
+ '?': { open: '(?:', close: ')?' },
3875
+ '+': { open: '(?:', close: ')+' },
3876
+ '*': { open: '(?:', close: ')*' },
3877
+ '@': { open: '(?:', close: ')' },
3830
3878
  };
3831
-
3832
3879
  // any single thing other than /
3833
3880
  // don't need to escape / when using new RegExp()
3834
3881
  const qmark = '[^/]';
3835
-
3836
3882
  // * => any number of characters
3837
3883
  const star = qmark + '*?';
3838
-
3839
3884
  // ** when dots are allowed. Anything goes, except .. and .
3840
3885
  // not (^ or / followed by one or two dots followed by $ or /),
3841
3886
  // followed by anything, any number of times.
3842
- const twoStarDot = '(?:(?!(?:\\\/|^)(?:\\.{1,2})($|\\\/)).)*?';
3843
-
3887
+ const twoStarDot = '(?:(?!(?:\\/|^)(?:\\.{1,2})($|\\/)).)*?';
3844
3888
  // not a ^ or / followed by a dot,
3845
3889
  // followed by anything, any number of times.
3846
- const twoStarNoDot = '(?:(?!(?:\\\/|^)\\.).)*?';
3847
-
3890
+ const twoStarNoDot = '(?:(?!(?:\\/|^)\\.).)*?';
3848
3891
  // "abc" -> { a:true, b:true, c:true }
3849
- const charSet = s => s.split('').reduce((set, c) => {
3850
- set[c] = true;
3851
- return set
3892
+ const charSet = (s) => s.split('').reduce((set, c) => {
3893
+ set[c] = true;
3894
+ return set;
3852
3895
  }, {});
3853
-
3854
3896
  // characters that need to be escaped in RegExp.
3855
3897
  const reSpecials = charSet('().*{}+?[]^$\\!');
3856
-
3857
3898
  // characters that indicate we have to add the pattern start
3858
3899
  const addPatternStartSet = charSet('[.(');
3859
-
3860
- // normalizes slashes.
3861
- const slashSplit = /\/+/;
3862
-
3863
- minimatch.filter = (pattern, options = {}) =>
3864
- (p, i, list) => minimatch(p, pattern, options);
3865
-
3866
- const ext = (a, b = {}) => {
3867
- const t = {};
3868
- Object.keys(a).forEach(k => t[k] = a[k]);
3869
- Object.keys(b).forEach(k => t[k] = b[k]);
3870
- return t
3871
- };
3872
-
3873
- minimatch.defaults = def => {
3874
- if (!def || typeof def !== 'object' || !Object.keys(def).length) {
3875
- return minimatch
3876
- }
3877
-
3878
- const orig = minimatch;
3879
-
3880
- const m = (p, pattern, options) => orig(p, pattern, ext(def, options));
3881
- m.Minimatch = class Minimatch extends orig.Minimatch {
3882
- constructor (pattern, options) {
3883
- super(pattern, ext(def, options));
3884
- }
3885
- };
3886
- m.Minimatch.defaults = options => orig.defaults(ext(def, options)).Minimatch;
3887
- m.filter = (pattern, options) => orig.filter(pattern, ext(def, options));
3888
- m.defaults = options => orig.defaults(ext(def, options));
3889
- m.makeRe = (pattern, options) => orig.makeRe(pattern, ext(def, options));
3890
- m.braceExpand = (pattern, options) => orig.braceExpand(pattern, ext(def, options));
3891
- m.match = (list, pattern, options) => orig.match(list, pattern, ext(def, options));
3892
-
3893
- return m
3900
+ const filter = (pattern, options = {}) => (p) => minimatch(p, pattern, options);
3901
+ minimatch.filter = filter;
3902
+ const ext = (a, b = {}) => Object.assign({}, a, b);
3903
+ const defaults = (def) => {
3904
+ if (!def || typeof def !== 'object' || !Object.keys(def).length) {
3905
+ return minimatch;
3906
+ }
3907
+ const orig = minimatch;
3908
+ const m = (p, pattern, options = {}) => orig(p, pattern, ext(def, options));
3909
+ return Object.assign(m, {
3910
+ Minimatch: class Minimatch extends orig.Minimatch {
3911
+ constructor(pattern, options = {}) {
3912
+ super(pattern, ext(def, options));
3913
+ }
3914
+ static defaults(options) {
3915
+ return orig.defaults(ext(def, options)).Minimatch;
3916
+ }
3917
+ },
3918
+ filter: (pattern, options = {}) => orig.filter(pattern, ext(def, options)),
3919
+ defaults: (options) => orig.defaults(ext(def, options)),
3920
+ makeRe: (pattern, options = {}) => orig.makeRe(pattern, ext(def, options)),
3921
+ braceExpand: (pattern, options = {}) => orig.braceExpand(pattern, ext(def, options)),
3922
+ match: (list, pattern, options = {}) => orig.match(list, pattern, ext(def, options)),
3923
+ sep: orig.sep,
3924
+ GLOBSTAR: GLOBSTAR,
3925
+ });
3894
3926
  };
3895
-
3896
-
3897
-
3898
-
3899
-
3927
+ minimatch.defaults = defaults;
3900
3928
  // Brace expansion:
3901
3929
  // a{b,c}d -> abd acd
3902
3930
  // a{b,}c -> abc ac
@@ -3907,32 +3935,26 @@
3907
3935
  // Invalid sets are not expanded.
3908
3936
  // a{2..}b -> a{2..}b
3909
3937
  // a{b}c -> a{b}c
3910
- minimatch.braceExpand = (pattern, options) => braceExpand(pattern, options);
3911
-
3912
3938
  const braceExpand = (pattern, options = {}) => {
3913
- assertValidPattern(pattern);
3914
-
3915
- // Thanks to Yeting Li <https://github.com/yetingli> for
3916
- // improving this regexp to avoid a ReDOS vulnerability.
3917
- if (options.nobrace || !/\{(?:(?!\{).)*\}/.test(pattern)) {
3918
- // shortcut. no need to expand.
3919
- return [pattern]
3920
- }
3921
-
3922
- return expand(pattern)
3939
+ assertValidPattern(pattern);
3940
+ // Thanks to Yeting Li <https://github.com/yetingli> for
3941
+ // improving this regexp to avoid a ReDOS vulnerability.
3942
+ if (options.nobrace || !/\{(?:(?!\{).)*\}/.test(pattern)) {
3943
+ // shortcut. no need to expand.
3944
+ return [pattern];
3945
+ }
3946
+ return braceExpansion(pattern);
3923
3947
  };
3924
-
3948
+ minimatch.braceExpand = braceExpand;
3925
3949
  const MAX_PATTERN_LENGTH = 1024 * 64;
3926
- const assertValidPattern = pattern => {
3927
- if (typeof pattern !== 'string') {
3928
- throw new TypeError('invalid pattern')
3929
- }
3930
-
3931
- if (pattern.length > MAX_PATTERN_LENGTH) {
3932
- throw new TypeError('pattern is too long')
3933
- }
3950
+ const assertValidPattern = (pattern) => {
3951
+ if (typeof pattern !== 'string') {
3952
+ throw new TypeError('invalid pattern');
3953
+ }
3954
+ if (pattern.length > MAX_PATTERN_LENGTH) {
3955
+ throw new TypeError('pattern is too long');
3956
+ }
3934
3957
  };
3935
-
3936
3958
  // parse a component of the expanded set.
3937
3959
  // At this point, no pattern may contain "/" in it
3938
3960
  // so we're going to return a 2d array, where each entry is the full
@@ -3945,861 +3967,961 @@
3945
3967
  // of * is equivalent to a single *. Globstar behavior is enabled by
3946
3968
  // default, and can be disabled by setting options.noglobstar.
3947
3969
  const SUBPARSE = Symbol('subparse');
3948
-
3949
- minimatch.makeRe = (pattern, options) =>
3950
- new Minimatch(pattern, options || {}).makeRe();
3951
-
3952
- minimatch.match = (list, pattern, options = {}) => {
3953
- const mm = new Minimatch(pattern, options);
3954
- list = list.filter(f => mm.match(f));
3955
- if (mm.options.nonull && !list.length) {
3956
- list.push(pattern);
3957
- }
3958
- return list
3970
+ const makeRe = (pattern, options = {}) => new Minimatch(pattern, options).makeRe();
3971
+ minimatch.makeRe = makeRe;
3972
+ const match = (list, pattern, options = {}) => {
3973
+ const mm = new Minimatch(pattern, options);
3974
+ list = list.filter(f => mm.match(f));
3975
+ if (mm.options.nonull && !list.length) {
3976
+ list.push(pattern);
3977
+ }
3978
+ return list;
3959
3979
  };
3960
-
3980
+ minimatch.match = match;
3961
3981
  // replace stuff like \* with *
3962
- const globUnescape = s => s.replace(/\\(.)/g, '$1');
3963
- const charUnescape = s => s.replace(/\\([^-\]])/g, '$1');
3964
- const regExpEscape = s => s.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
3965
- const braExpEscape = s => s.replace(/[[\]\\]/g, '\\$&');
3966
-
3982
+ const globUnescape = (s) => s.replace(/\\(.)/g, '$1');
3983
+ const charUnescape = (s) => s.replace(/\\([^-\]])/g, '$1');
3984
+ const regExpEscape = (s) => s.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
3985
+ const braExpEscape = (s) => s.replace(/[[\]\\]/g, '\\$&');
3967
3986
  class Minimatch {
3968
- constructor (pattern, options) {
3969
- assertValidPattern(pattern);
3970
-
3971
- if (!options) options = {};
3972
-
3973
- this.options = options;
3974
- this.maxGlobstarRecursion = options.maxGlobstarRecursion !== undefined
3975
- ? options.maxGlobstarRecursion : 200;
3976
- this.set = [];
3977
- this.pattern = pattern;
3978
- this.windowsPathsNoEscape = !!options.windowsPathsNoEscape ||
3979
- options.allowWindowsEscape === false;
3980
- if (this.windowsPathsNoEscape) {
3981
- this.pattern = this.pattern.replace(/\\/g, '/');
3982
- }
3983
- this.regexp = null;
3984
- this.negate = false;
3985
- this.comment = false;
3986
- this.empty = false;
3987
- this.partial = !!options.partial;
3988
-
3989
- // make the set of regexps etc.
3990
- this.make();
3991
- }
3992
-
3993
- debug () {}
3994
-
3995
- make () {
3996
- const pattern = this.pattern;
3997
- const options = this.options;
3998
-
3999
- // empty patterns and comments match nothing.
4000
- if (!options.nocomment && pattern.charAt(0) === '#') {
4001
- this.comment = true;
4002
- return
4003
- }
4004
- if (!pattern) {
4005
- this.empty = true;
4006
- return
4007
- }
4008
-
4009
- // step 1: figure out negation, etc.
4010
- this.parseNegate();
4011
-
4012
- // step 2: expand braces
4013
- let set = this.globSet = this.braceExpand();
4014
-
4015
- if (options.debug) this.debug = (...args) => console.error(...args);
4016
-
4017
- this.debug(this.pattern, set);
4018
-
4019
- // step 3: now we have a set, so turn each one into a series of path-portion
4020
- // matching patterns.
4021
- // These will be regexps, except in the case of "**", which is
4022
- // set to the GLOBSTAR object for globstar behavior,
4023
- // and will not contain any / characters
4024
- set = this.globParts = set.map(s => s.split(slashSplit));
4025
-
4026
- this.debug(this.pattern, set);
4027
-
4028
- // glob --> regexps
4029
- set = set.map((s, si, set) => s.map(this.parse, this));
4030
-
4031
- this.debug(this.pattern, set);
4032
-
4033
- // filter out everything that didn't compile properly.
4034
- set = set.filter(s => s.indexOf(false) === -1);
4035
-
4036
- this.debug(this.pattern, set);
4037
-
4038
- this.set = set;
4039
- }
4040
-
4041
- parseNegate () {
4042
- if (this.options.nonegate) return
4043
-
4044
- const pattern = this.pattern;
4045
- let negate = false;
4046
- let negateOffset = 0;
4047
-
4048
- for (let i = 0; i < pattern.length && pattern.charAt(i) === '!'; i++) {
4049
- negate = !negate;
4050
- negateOffset++;
4051
- }
4052
-
4053
- if (negateOffset) this.pattern = pattern.slice(negateOffset);
4054
- this.negate = negate;
4055
- }
4056
-
4057
- // set partial to true to test if, for example,
4058
- // "/a/b" matches the start of "/*/b/*/d"
4059
- // Partial means, if you run out of file before you run
4060
- // out of pattern, then that's fine, as long as all
4061
- // the parts match.
4062
- matchOne (file, pattern, partial) {
4063
- if (pattern.indexOf(GLOBSTAR) !== -1) {
4064
- return this._matchGlobstar(file, pattern, partial, 0, 0)
4065
- }
4066
- return this._matchOne(file, pattern, partial, 0, 0)
4067
- }
4068
-
4069
- _matchGlobstar (file, pattern, partial, fileIndex, patternIndex) {
4070
- // find first globstar from patternIndex
4071
- let firstgs = -1;
4072
- for (let i = patternIndex; i < pattern.length; i++) {
4073
- if (pattern[i] === GLOBSTAR) { firstgs = i; break }
4074
- }
4075
-
4076
- // find last globstar
4077
- let lastgs = -1;
4078
- for (let i = pattern.length - 1; i >= 0; i--) {
4079
- if (pattern[i] === GLOBSTAR) { lastgs = i; break }
4080
- }
4081
-
4082
- const head = pattern.slice(patternIndex, firstgs);
4083
- const body = partial ? pattern.slice(firstgs + 1) : pattern.slice(firstgs + 1, lastgs);
4084
- const tail = partial ? [] : pattern.slice(lastgs + 1);
4085
-
4086
- // check the head
4087
- if (head.length) {
4088
- const fileHead = file.slice(fileIndex, fileIndex + head.length);
4089
- if (!this._matchOne(fileHead, head, partial, 0, 0)) {
4090
- return false
4091
- }
4092
- fileIndex += head.length;
4093
- }
4094
-
4095
- // check the tail
4096
- let fileTailMatch = 0;
4097
- if (tail.length) {
4098
- if (tail.length + fileIndex > file.length) return false
4099
-
4100
- const tailStart = file.length - tail.length;
4101
- if (this._matchOne(file, tail, partial, tailStart, 0)) {
4102
- fileTailMatch = tail.length;
4103
- } else {
4104
- // affordance for stuff like a/**/* matching a/b/
4105
- if (file[file.length - 1] !== '' ||
4106
- fileIndex + tail.length === file.length) {
4107
- return false
3987
+ options;
3988
+ set;
3989
+ pattern;
3990
+ windowsPathsNoEscape;
3991
+ nonegate;
3992
+ negate;
3993
+ comment;
3994
+ empty;
3995
+ preserveMultipleSlashes;
3996
+ partial;
3997
+ globSet;
3998
+ globParts;
3999
+ regexp;
4000
+ maxGlobstarRecursion;
4001
+ constructor(pattern, options = {}) {
4002
+ assertValidPattern(pattern);
4003
+ options = options || {};
4004
+ this.options = options;
4005
+ this.pattern = pattern;
4006
+ this.windowsPathsNoEscape =
4007
+ !!options.windowsPathsNoEscape || options.allowWindowsEscape === false;
4008
+ if (this.windowsPathsNoEscape) {
4009
+ this.pattern = this.pattern.replace(/\\/g, '/');
4108
4010
  }
4109
- if (!this._matchOne(file, tail, partial, tailStart - 1, 0)) {
4110
- return false
4011
+ this.preserveMultipleSlashes = !!options.preserveMultipleSlashes;
4012
+ this.regexp = null;
4013
+ this.negate = false;
4014
+ this.nonegate = !!options.nonegate;
4015
+ this.comment = false;
4016
+ this.empty = false;
4017
+ this.partial = !!options.partial;
4018
+ this.maxGlobstarRecursion = options.maxGlobstarRecursion !== undefined
4019
+ ? options.maxGlobstarRecursion : 200;
4020
+ this.globSet = [];
4021
+ this.globParts = [];
4022
+ this.set = [];
4023
+ // make the set of regexps etc.
4024
+ this.make();
4025
+ }
4026
+ debug(..._) { }
4027
+ make() {
4028
+ const pattern = this.pattern;
4029
+ const options = this.options;
4030
+ // empty patterns and comments match nothing.
4031
+ if (!options.nocomment && pattern.charAt(0) === '#') {
4032
+ this.comment = true;
4033
+ return;
4111
4034
  }
4112
- fileTailMatch = tail.length + 1;
4113
- }
4114
- }
4115
-
4116
- // if body is empty (single ** between head and tail)
4117
- if (!body.length) {
4118
- let sawSome = !!fileTailMatch;
4119
- for (let i = fileIndex; i < file.length - fileTailMatch; i++) {
4120
- const f = String(file[i]);
4121
- sawSome = true;
4122
- if (f === '.' || f === '..' ||
4123
- (!this.options.dot && f.charAt(0) === '.')) {
4124
- return false
4035
+ if (!pattern) {
4036
+ this.empty = true;
4037
+ return;
4125
4038
  }
4126
- }
4127
- return partial || sawSome
4128
- }
4129
-
4130
- // split body into segments at each GLOBSTAR
4131
- const bodySegments = [[[], 0]];
4132
- let currentBody = bodySegments[0];
4133
- let nonGsParts = 0;
4134
- const nonGsPartsSums = [0];
4135
- for (const b of body) {
4136
- if (b === GLOBSTAR) {
4137
- nonGsPartsSums.push(nonGsParts);
4138
- currentBody = [[], 0];
4139
- bodySegments.push(currentBody);
4140
- } else {
4141
- currentBody[0].push(b);
4142
- nonGsParts++;
4143
- }
4144
- }
4145
-
4146
- let idx = bodySegments.length - 1;
4147
- const fileLength = file.length - fileTailMatch;
4148
- for (const b of bodySegments) {
4149
- b[1] = fileLength - (nonGsPartsSums[idx--] + b[0].length);
4150
- }
4151
-
4152
- return !!this._matchGlobStarBodySections(
4153
- file, bodySegments, fileIndex, 0, partial, 0, !!fileTailMatch
4154
- )
4155
- }
4156
-
4157
- // return false for "nope, not matching"
4158
- // return null for "not matching, cannot keep trying"
4159
- _matchGlobStarBodySections (
4160
- file, bodySegments, fileIndex, bodyIndex, partial, globStarDepth, sawTail
4161
- ) {
4162
- const bs = bodySegments[bodyIndex];
4163
- if (!bs) {
4164
- // just make sure there are no bad dots
4165
- for (let i = fileIndex; i < file.length; i++) {
4166
- sawTail = true;
4167
- const f = file[i];
4168
- if (f === '.' || f === '..' ||
4169
- (!this.options.dot && f.charAt(0) === '.')) {
4170
- return false
4039
+ // step 1: figure out negation, etc.
4040
+ this.parseNegate();
4041
+ // step 2: expand braces
4042
+ this.globSet = this.braceExpand();
4043
+ if (options.debug) {
4044
+ this.debug = (...args) => console.error(...args);
4171
4045
  }
4172
- }
4173
- return sawTail
4174
- }
4175
-
4176
- const [body, after] = bs;
4177
- while (fileIndex <= after) {
4178
- const m = this._matchOne(
4179
- file.slice(0, fileIndex + body.length),
4180
- body,
4181
- partial,
4182
- fileIndex,
4183
- 0
4184
- );
4185
- // if limit exceeded, no match. intentional false negative,
4186
- // acceptable break in correctness for security.
4187
- if (m && globStarDepth < this.maxGlobstarRecursion) {
4188
- const sub = this._matchGlobStarBodySections(
4189
- file, bodySegments,
4190
- fileIndex + body.length, bodyIndex + 1,
4191
- partial, globStarDepth + 1, sawTail
4192
- );
4193
- if (sub !== false) {
4194
- return sub
4046
+ this.debug(this.pattern, this.globSet);
4047
+ // step 3: now we have a set, so turn each one into a series of path-portion
4048
+ // matching patterns.
4049
+ // These will be regexps, except in the case of "**", which is
4050
+ // set to the GLOBSTAR object for globstar behavior,
4051
+ // and will not contain any / characters
4052
+ const rawGlobParts = this.globSet.map(s => this.slashSplit(s));
4053
+ // consecutive globstars are an unncessary perf killer
4054
+ // also, **/*/... is equivalent to */**/..., so swap all of those
4055
+ // this turns a pattern like **/*/**/*/x into */*/**/x
4056
+ // and a pattern like **/x/**/*/y becomes **/x/*/**/y
4057
+ // the *later* we can push the **, the more efficient it is,
4058
+ // because we can avoid having to do a recursive walk until
4059
+ // the walked tree is as shallow as possible.
4060
+ // Note that this is only true up to the last pattern, though, because
4061
+ // a/*/** will only match a/b if b is a dir, but a/**/* will match a/b
4062
+ // regardless, since it's "0 or more path segments" if it's not final.
4063
+ if (this.options.noglobstar) {
4064
+ // ** is * anyway
4065
+ this.globParts = rawGlobParts;
4195
4066
  }
4196
- }
4197
- const f = file[fileIndex];
4198
- if (f === '.' || f === '..' ||
4199
- (!this.options.dot && f.charAt(0) === '.')) {
4200
- return false
4201
- }
4202
- fileIndex++;
4203
- }
4204
- return partial || null
4205
- }
4206
-
4207
- _matchOne (file, pattern, partial, fileIndex, patternIndex) {
4208
- let fi, pi, fl, pl;
4209
- for (
4210
- fi = fileIndex, pi = patternIndex, fl = file.length, pl = pattern.length
4211
- ; (fi < fl) && (pi < pl)
4212
- ; fi++, pi++
4213
- ) {
4214
- this.debug('matchOne loop');
4215
- const p = pattern[pi];
4216
- const f = file[fi];
4217
-
4218
- this.debug(pattern, p, f);
4219
-
4220
- // should be impossible.
4221
- // some invalid regexp stuff in the set.
4222
- /* istanbul ignore if */
4223
- if (p === false || p === GLOBSTAR) return false
4224
-
4225
- // something other than **
4226
- // non-magic patterns just have to match exactly
4227
- // patterns with magic have been turned into regexps.
4228
- let hit;
4229
- if (typeof p === 'string') {
4230
- hit = f === p;
4231
- this.debug('string match', p, f, hit);
4232
- } else {
4233
- hit = f.match(p);
4234
- this.debug('pattern match', p, f, hit);
4235
- }
4236
-
4237
- if (!hit) return false
4238
- }
4239
-
4240
- // now either we fell off the end of the pattern, or we're done.
4241
- if (fi === fl && pi === pl) {
4242
- // ran out of pattern and filename at the same time.
4243
- // an exact hit!
4244
- return true
4245
- } else if (fi === fl) {
4246
- // ran out of file, but still had pattern left.
4247
- // this is ok if we're doing the match as part of
4248
- // a glob fs traversal.
4249
- return partial
4250
- } else /* istanbul ignore else */ if (pi === pl) {
4251
- // ran out of pattern, still have file left.
4252
- // this is only acceptable if we're on the very last
4253
- // empty segment of a file with a trailing slash.
4254
- // a/* should match a/b/
4255
- return (fi === fl - 1) && (file[fi] === '')
4256
- }
4257
-
4258
- // should be unreachable.
4259
- /* istanbul ignore next */
4260
- throw new Error('wtf?')
4261
- }
4262
-
4263
- braceExpand () {
4264
- return braceExpand(this.pattern, this.options)
4265
- }
4266
-
4267
- parse (pattern, isSub) {
4268
- assertValidPattern(pattern);
4269
-
4270
- const options = this.options;
4271
-
4272
- // shortcuts
4273
- if (pattern === '**') {
4274
- if (!options.noglobstar)
4275
- return GLOBSTAR
4276
- else
4277
- pattern = '*';
4278
- }
4279
- if (pattern === '') return ''
4280
-
4281
- let re = '';
4282
- let hasMagic = false;
4283
- let escaping = false;
4284
- // ? => one single character
4285
- const patternListStack = [];
4286
- const negativeLists = [];
4287
- let stateChar;
4288
- let inClass = false;
4289
- let reClassStart = -1;
4290
- let classStart = -1;
4291
- let cs;
4292
- let pl;
4293
- let sp;
4294
- // . and .. never match anything that doesn't start with .,
4295
- // even when options.dot is set. However, if the pattern
4296
- // starts with ., then traversal patterns can match.
4297
- let dotTravAllowed = pattern.charAt(0) === '.';
4298
- let dotFileAllowed = options.dot || dotTravAllowed;
4299
- const patternStart = () =>
4300
- dotTravAllowed
4301
- ? ''
4302
- : dotFileAllowed
4303
- ? '(?!(?:^|\\/)\\.{1,2}(?:$|\\/))'
4304
- : '(?!\\.)';
4305
- const subPatternStart = (p) =>
4306
- p.charAt(0) === '.'
4307
- ? ''
4308
- : options.dot
4309
- ? '(?!(?:^|\\/)\\.{1,2}(?:$|\\/))'
4310
- : '(?!\\.)';
4311
-
4312
-
4313
- const clearStateChar = () => {
4314
- if (stateChar) {
4315
- // we had some state-tracking character
4316
- // that wasn't consumed by this pass.
4317
- switch (stateChar) {
4318
- case '*':
4319
- re += star;
4320
- hasMagic = true;
4321
- break
4322
- case '?':
4323
- re += qmark;
4067
+ else {
4068
+ // do this swap BEFORE the reduce, so that we can turn a string
4069
+ // of **/*/**/* into */*/**/** and then reduce the **'s into one
4070
+ for (const parts of rawGlobParts) {
4071
+ let swapped;
4072
+ do {
4073
+ swapped = false;
4074
+ for (let i = 0; i < parts.length - 1; i++) {
4075
+ if (parts[i] === '*' && parts[i - 1] === '**') {
4076
+ parts[i] = '**';
4077
+ parts[i - 1] = '*';
4078
+ swapped = true;
4079
+ }
4080
+ }
4081
+ } while (swapped);
4082
+ }
4083
+ this.globParts = rawGlobParts.map(parts => {
4084
+ parts = parts.reduce((set, part) => {
4085
+ const prev = set[set.length - 1];
4086
+ if (part === '**' && prev === '**') {
4087
+ return set;
4088
+ }
4089
+ if (part === '..') {
4090
+ if (prev && prev !== '..' && prev !== '.' && prev !== '**') {
4091
+ set.pop();
4092
+ return set;
4093
+ }
4094
+ }
4095
+ set.push(part);
4096
+ return set;
4097
+ }, []);
4098
+ return parts.length === 0 ? [''] : parts;
4099
+ });
4100
+ }
4101
+ this.debug(this.pattern, this.globParts);
4102
+ // glob --> regexps
4103
+ let set = this.globParts.map((s, _, __) => s.map(ss => this.parse(ss)));
4104
+ this.debug(this.pattern, set);
4105
+ // filter out everything that didn't compile properly.
4106
+ this.set = set.filter(s => s.indexOf(false) === -1);
4107
+ // do not treat the ? in UNC paths as magic
4108
+ if (isWindows) {
4109
+ for (let i = 0; i < this.set.length; i++) {
4110
+ const p = this.set[i];
4111
+ if (p[0] === '' &&
4112
+ p[1] === '' &&
4113
+ this.globParts[i][2] === '?' &&
4114
+ typeof p[3] === 'string' &&
4115
+ /^[a-z]:$/i.test(p[3])) {
4116
+ p[2] = '?';
4117
+ }
4118
+ }
4119
+ }
4120
+ this.debug(this.pattern, this.set);
4121
+ }
4122
+ parseNegate() {
4123
+ if (this.nonegate)
4124
+ return;
4125
+ const pattern = this.pattern;
4126
+ let negate = false;
4127
+ let negateOffset = 0;
4128
+ for (let i = 0; i < pattern.length && pattern.charAt(i) === '!'; i++) {
4129
+ negate = !negate;
4130
+ negateOffset++;
4131
+ }
4132
+ if (negateOffset)
4133
+ this.pattern = pattern.slice(negateOffset);
4134
+ this.negate = negate;
4135
+ }
4136
+ // set partial to true to test if, for example,
4137
+ // "/a/b" matches the start of "/*/b/*/d"
4138
+ // Partial means, if you run out of file before you run
4139
+ // out of pattern, then that's fine, as long as all
4140
+ // the parts match.
4141
+ matchOne(file, pattern, partial = false) {
4142
+ // a UNC pattern like //?/c:/* can match a path like c:/x
4143
+ // and vice versa
4144
+ if (isWindows) {
4145
+ const fileUNC = file[0] === '' &&
4146
+ file[1] === '' &&
4147
+ file[2] === '?' &&
4148
+ typeof file[3] === 'string' &&
4149
+ /^[a-z]:$/i.test(file[3]);
4150
+ const patternUNC = pattern[0] === '' &&
4151
+ pattern[1] === '' &&
4152
+ pattern[2] === '?' &&
4153
+ typeof pattern[3] === 'string' &&
4154
+ /^[a-z]:$/i.test(pattern[3]);
4155
+ if (fileUNC && patternUNC) {
4156
+ const fd = file[3];
4157
+ const pd = pattern[3];
4158
+ if (fd.toLowerCase() === pd.toLowerCase()) {
4159
+ file[3] = pd;
4160
+ }
4161
+ }
4162
+ else if (patternUNC && typeof file[0] === 'string') {
4163
+ const pd = pattern[3];
4164
+ const fd = file[0];
4165
+ if (pd.toLowerCase() === fd.toLowerCase()) {
4166
+ pattern[3] = fd;
4167
+ pattern = pattern.slice(3);
4168
+ }
4169
+ }
4170
+ else if (fileUNC && typeof pattern[0] === 'string') {
4171
+ const fd = file[3];
4172
+ if (fd.toLowerCase() === pattern[0].toLowerCase()) {
4173
+ pattern[0] = fd;
4174
+ file = file.slice(3);
4175
+ }
4176
+ }
4177
+ }
4178
+ if (pattern.indexOf(GLOBSTAR) !== -1) {
4179
+ return this._matchGlobstar(file, pattern, partial, 0, 0);
4180
+ }
4181
+ return this._matchOne(file, pattern, partial, 0, 0);
4182
+ }
4183
+ _matchGlobstar(file, pattern, partial, fileIndex, patternIndex) {
4184
+ // find first globstar from patternIndex
4185
+ let firstgs = -1;
4186
+ for (let i = patternIndex; i < pattern.length; i++) {
4187
+ if (pattern[i] === GLOBSTAR) {
4188
+ firstgs = i;
4189
+ break;
4190
+ }
4191
+ }
4192
+ // find last globstar
4193
+ let lastgs = -1;
4194
+ for (let i = pattern.length - 1; i >= 0; i--) {
4195
+ if (pattern[i] === GLOBSTAR) {
4196
+ lastgs = i;
4197
+ break;
4198
+ }
4199
+ }
4200
+ const head = pattern.slice(patternIndex, firstgs);
4201
+ const body = pattern.slice(firstgs + 1, lastgs);
4202
+ const tail = pattern.slice(lastgs + 1);
4203
+ // check the head
4204
+ if (head.length) {
4205
+ const fileHead = file.slice(fileIndex, fileIndex + head.length);
4206
+ if (!this._matchOne(fileHead, head, partial, 0, 0)) {
4207
+ return false;
4208
+ }
4209
+ fileIndex += head.length;
4210
+ }
4211
+ // check the tail
4212
+ let fileTailMatch = 0;
4213
+ if (tail.length) {
4214
+ if (tail.length + fileIndex > file.length)
4215
+ return false;
4216
+ const tailStart = file.length - tail.length;
4217
+ if (this._matchOne(file, tail, partial, tailStart, 0)) {
4218
+ fileTailMatch = tail.length;
4219
+ }
4220
+ else {
4221
+ // affordance for stuff like a/**/* matching a/b/
4222
+ if (file[file.length - 1] !== '' ||
4223
+ fileIndex + tail.length === file.length) {
4224
+ return false;
4225
+ }
4226
+ if (!this._matchOne(file, tail, partial, tailStart - 1, 0)) {
4227
+ return false;
4228
+ }
4229
+ fileTailMatch = tail.length + 1;
4230
+ }
4231
+ }
4232
+ // if body is empty (single ** between head and tail)
4233
+ if (!body.length) {
4234
+ let sawSome = !!fileTailMatch;
4235
+ for (let i = fileIndex; i < file.length - fileTailMatch; i++) {
4236
+ const f = String(file[i]);
4237
+ sawSome = true;
4238
+ if (f === '.' ||
4239
+ f === '..' ||
4240
+ (!this.options.dot && f.startsWith('.'))) {
4241
+ return false;
4242
+ }
4243
+ }
4244
+ return sawSome;
4245
+ }
4246
+ // split body into segments at each GLOBSTAR
4247
+ const bodySegments = [[[], 0]];
4248
+ let currentBody = bodySegments[0];
4249
+ let nonGsParts = 0;
4250
+ const nonGsPartsSums = [0];
4251
+ for (const b of body) {
4252
+ if (b === GLOBSTAR) {
4253
+ nonGsPartsSums.push(nonGsParts);
4254
+ currentBody = [[], 0];
4255
+ bodySegments.push(currentBody);
4256
+ }
4257
+ else {
4258
+ currentBody[0].push(b);
4259
+ nonGsParts++;
4260
+ }
4261
+ }
4262
+ let idx = bodySegments.length - 1;
4263
+ const fileLength = file.length - fileTailMatch;
4264
+ for (const b of bodySegments) {
4265
+ b[1] = fileLength - (nonGsPartsSums[idx--] + b[0].length);
4266
+ }
4267
+ return !!this._matchGlobStarBodySections(file, bodySegments, fileIndex, 0, partial, 0, !!fileTailMatch);
4268
+ }
4269
+ // return false for "nope, not matching"
4270
+ // return null for "not matching, cannot keep trying"
4271
+ _matchGlobStarBodySections(file, bodySegments, fileIndex, bodyIndex, partial, globStarDepth, sawTail) {
4272
+ const bs = bodySegments[bodyIndex];
4273
+ if (!bs) {
4274
+ // just make sure there are no bad dots
4275
+ for (let i = fileIndex; i < file.length; i++) {
4276
+ sawTail = true;
4277
+ const f = file[i];
4278
+ if (f === '.' ||
4279
+ f === '..' ||
4280
+ (!this.options.dot && f.startsWith('.'))) {
4281
+ return false;
4282
+ }
4283
+ }
4284
+ return sawTail;
4285
+ }
4286
+ const [body, after] = bs;
4287
+ while (fileIndex <= after) {
4288
+ const m = this._matchOne(file.slice(0, fileIndex + body.length), body, partial, fileIndex, 0);
4289
+ // if limit exceeded, no match. intentional false negative,
4290
+ // acceptable break in correctness for security.
4291
+ if (m && globStarDepth < this.maxGlobstarRecursion) {
4292
+ const sub = this._matchGlobStarBodySections(file, bodySegments, fileIndex + body.length, bodyIndex + 1, partial, globStarDepth + 1, sawTail);
4293
+ if (sub !== false) {
4294
+ return sub;
4295
+ }
4296
+ }
4297
+ const f = file[fileIndex];
4298
+ if (f === '.' ||
4299
+ f === '..' ||
4300
+ (!this.options.dot && f.startsWith('.'))) {
4301
+ return false;
4302
+ }
4303
+ fileIndex++;
4304
+ }
4305
+ return null;
4306
+ }
4307
+ _matchOne(file, pattern, partial, fileIndex, patternIndex) {
4308
+ let fi;
4309
+ let pi;
4310
+ let fl;
4311
+ let pl;
4312
+ for (fi = fileIndex,
4313
+ pi = patternIndex,
4314
+ fl = file.length,
4315
+ pl = pattern.length; fi < fl && pi < pl; fi++, pi++) {
4316
+ this.debug('matchOne loop');
4317
+ const p = pattern[pi];
4318
+ const f = file[fi];
4319
+ this.debug(pattern, p, f);
4320
+ // should be impossible.
4321
+ // some invalid regexp stuff in the set.
4322
+ /* c8 ignore start */
4323
+ if (p === false || p === GLOBSTAR) {
4324
+ return false;
4325
+ }
4326
+ /* c8 ignore stop */
4327
+ // something other than **
4328
+ // non-magic patterns just have to match exactly
4329
+ // patterns with magic have been turned into regexps.
4330
+ let hit;
4331
+ if (typeof p === 'string') {
4332
+ hit = f === p;
4333
+ this.debug('string match', p, f, hit);
4334
+ }
4335
+ else {
4336
+ hit = p.test(f);
4337
+ this.debug('pattern match', p, f, hit);
4338
+ }
4339
+ if (!hit)
4340
+ return false;
4341
+ }
4342
+ // now either we fell off the end of the pattern, or we're done.
4343
+ if (fi === fl && pi === pl) {
4344
+ // ran out of pattern and filename at the same time.
4345
+ // an exact hit!
4346
+ return true;
4347
+ }
4348
+ else if (fi === fl) {
4349
+ // ran out of file, but still had pattern left.
4350
+ // this is ok if we're doing the match as part of
4351
+ // a glob fs traversal.
4352
+ return partial;
4353
+ }
4354
+ else if (pi === pl) {
4355
+ // ran out of pattern, still have file left.
4356
+ // this is only acceptable if we're on the very last
4357
+ // empty segment of a file with a trailing slash.
4358
+ // a/* should match a/b/
4359
+ return fi === fl - 1 && file[fi] === '';
4360
+ /* c8 ignore start */
4361
+ }
4362
+ else {
4363
+ // should be unreachable.
4364
+ throw new Error('wtf?');
4365
+ }
4366
+ /* c8 ignore stop */
4367
+ }
4368
+ braceExpand() {
4369
+ return braceExpand(this.pattern, this.options);
4370
+ }
4371
+ parse(pattern, isSub) {
4372
+ assertValidPattern(pattern);
4373
+ const options = this.options;
4374
+ // shortcuts
4375
+ if (pattern === '**') {
4376
+ if (!options.noglobstar)
4377
+ return GLOBSTAR;
4378
+ else
4379
+ pattern = '*';
4380
+ }
4381
+ if (pattern === '')
4382
+ return '';
4383
+ // far and away, the most common glob pattern parts are
4384
+ // *, *.*, and *.<ext> Add a fast check method for those.
4385
+ let m;
4386
+ let fastTest = null;
4387
+ if (isSub !== SUBPARSE) {
4388
+ if ((m = pattern.match(starRE))) {
4389
+ fastTest = options.dot ? starTestDot : starTest;
4390
+ }
4391
+ else if ((m = pattern.match(starDotExtRE))) {
4392
+ fastTest = (options.nocase
4393
+ ? options.dot
4394
+ ? starDotExtTestNocaseDot
4395
+ : starDotExtTestNocase
4396
+ : options.dot
4397
+ ? starDotExtTestDot
4398
+ : starDotExtTest)(m[1]);
4399
+ }
4400
+ else if ((m = pattern.match(qmarksRE))) {
4401
+ fastTest = (options.nocase
4402
+ ? options.dot
4403
+ ? qmarksTestNocaseDot
4404
+ : qmarksTestNocase
4405
+ : options.dot
4406
+ ? qmarksTestDot
4407
+ : qmarksTest)(m);
4408
+ }
4409
+ else if ((m = pattern.match(starDotStarRE))) {
4410
+ fastTest = options.dot ? starDotStarTestDot : starDotStarTest;
4411
+ }
4412
+ else if ((m = pattern.match(dotStarRE))) {
4413
+ fastTest = dotStarTest;
4414
+ }
4415
+ }
4416
+ let re = '';
4417
+ let hasMagic = false;
4418
+ let escaping = false;
4419
+ // ? => one single character
4420
+ const patternListStack = [];
4421
+ const negativeLists = [];
4422
+ let stateChar = false;
4423
+ let inClass = false;
4424
+ let reClassStart = -1;
4425
+ let classStart = -1;
4426
+ let cs;
4427
+ let pl;
4428
+ let sp;
4429
+ // . and .. never match anything that doesn't start with .,
4430
+ // even when options.dot is set. However, if the pattern
4431
+ // starts with ., then traversal patterns can match.
4432
+ let dotTravAllowed = pattern.charAt(0) === '.';
4433
+ let dotFileAllowed = options.dot || dotTravAllowed;
4434
+ const patternStart = () => dotTravAllowed
4435
+ ? ''
4436
+ : dotFileAllowed
4437
+ ? '(?!(?:^|\\/)\\.{1,2}(?:$|\\/))'
4438
+ : '(?!\\.)';
4439
+ const subPatternStart = (p) => p.charAt(0) === '.'
4440
+ ? ''
4441
+ : options.dot
4442
+ ? '(?!(?:^|\\/)\\.{1,2}(?:$|\\/))'
4443
+ : '(?!\\.)';
4444
+ const clearStateChar = () => {
4445
+ if (stateChar) {
4446
+ // we had some state-tracking character
4447
+ // that wasn't consumed by this pass.
4448
+ switch (stateChar) {
4449
+ case '*':
4450
+ re += star;
4451
+ hasMagic = true;
4452
+ break;
4453
+ case '?':
4454
+ re += qmark;
4455
+ hasMagic = true;
4456
+ break;
4457
+ default:
4458
+ re += '\\' + stateChar;
4459
+ break;
4460
+ }
4461
+ this.debug('clearStateChar %j %j', stateChar, re);
4462
+ stateChar = false;
4463
+ }
4464
+ };
4465
+ for (let i = 0, c; i < pattern.length && (c = pattern.charAt(i)); i++) {
4466
+ this.debug('%s\t%s %s %j', pattern, i, re, c);
4467
+ // skip over any that are escaped.
4468
+ if (escaping) {
4469
+ // completely not allowed, even escaped.
4470
+ // should be impossible.
4471
+ /* c8 ignore start */
4472
+ if (c === '/') {
4473
+ return false;
4474
+ }
4475
+ /* c8 ignore stop */
4476
+ if (reSpecials[c]) {
4477
+ re += '\\';
4478
+ }
4479
+ re += c;
4480
+ escaping = false;
4481
+ continue;
4482
+ }
4483
+ switch (c) {
4484
+ // Should already be path-split by now.
4485
+ /* c8 ignore start */
4486
+ case '/': {
4487
+ return false;
4488
+ }
4489
+ /* c8 ignore stop */
4490
+ case '\\':
4491
+ if (inClass && pattern.charAt(i + 1) === '-') {
4492
+ re += c;
4493
+ continue;
4494
+ }
4495
+ clearStateChar();
4496
+ escaping = true;
4497
+ continue;
4498
+ // the various stateChar values
4499
+ // for the "extglob" stuff.
4500
+ case '?':
4501
+ case '*':
4502
+ case '+':
4503
+ case '@':
4504
+ case '!':
4505
+ this.debug('%s\t%s %s %j <-- stateChar', pattern, i, re, c);
4506
+ // all of those are literals inside a class, except that
4507
+ // the glob [!a] means [^a] in regexp
4508
+ if (inClass) {
4509
+ this.debug(' in class');
4510
+ if (c === '!' && i === classStart + 1)
4511
+ c = '^';
4512
+ re += c;
4513
+ continue;
4514
+ }
4515
+ // coalesce consecutive non-globstar * characters
4516
+ if (c === '*' && stateChar === '*')
4517
+ continue;
4518
+ // if we already have a stateChar, then it means
4519
+ // that there was something like ** or +? in there.
4520
+ // Handle the stateChar, then proceed with this one.
4521
+ this.debug('call clearStateChar %j', stateChar);
4522
+ clearStateChar();
4523
+ stateChar = c;
4524
+ // if extglob is disabled, then +(asdf|foo) isn't a thing.
4525
+ // just clear the statechar *now*, rather than even diving into
4526
+ // the patternList stuff.
4527
+ if (options.noext)
4528
+ clearStateChar();
4529
+ continue;
4530
+ case '(': {
4531
+ if (inClass) {
4532
+ re += '(';
4533
+ continue;
4534
+ }
4535
+ if (!stateChar) {
4536
+ re += '\\(';
4537
+ continue;
4538
+ }
4539
+ const plEntry = {
4540
+ type: stateChar,
4541
+ start: i - 1,
4542
+ reStart: re.length,
4543
+ open: plTypes[stateChar].open,
4544
+ close: plTypes[stateChar].close,
4545
+ };
4546
+ this.debug(this.pattern, '\t', plEntry);
4547
+ patternListStack.push(plEntry);
4548
+ // negation is (?:(?!(?:js)(?:<rest>))[^/]*)
4549
+ re += plEntry.open;
4550
+ // next entry starts with a dot maybe?
4551
+ if (plEntry.start === 0 && plEntry.type !== '!') {
4552
+ dotTravAllowed = true;
4553
+ re += subPatternStart(pattern.slice(i + 1));
4554
+ }
4555
+ this.debug('plType %j %j', stateChar, re);
4556
+ stateChar = false;
4557
+ continue;
4558
+ }
4559
+ case ')': {
4560
+ const plEntry = patternListStack[patternListStack.length - 1];
4561
+ if (inClass || !plEntry) {
4562
+ re += '\\)';
4563
+ continue;
4564
+ }
4565
+ patternListStack.pop();
4566
+ // closing an extglob
4567
+ clearStateChar();
4568
+ hasMagic = true;
4569
+ pl = plEntry;
4570
+ // negation is (?:(?!js)[^/]*)
4571
+ // The others are (?:<pattern>)<type>
4572
+ re += pl.close;
4573
+ if (pl.type === '!') {
4574
+ negativeLists.push(Object.assign(pl, { reEnd: re.length }));
4575
+ }
4576
+ continue;
4577
+ }
4578
+ case '|': {
4579
+ const plEntry = patternListStack[patternListStack.length - 1];
4580
+ if (inClass || !plEntry) {
4581
+ re += '\\|';
4582
+ continue;
4583
+ }
4584
+ clearStateChar();
4585
+ re += '|';
4586
+ // next subpattern can start with a dot?
4587
+ if (plEntry.start === 0 && plEntry.type !== '!') {
4588
+ dotTravAllowed = true;
4589
+ re += subPatternStart(pattern.slice(i + 1));
4590
+ }
4591
+ continue;
4592
+ }
4593
+ // these are mostly the same in regexp and glob
4594
+ case '[':
4595
+ // swallow any state-tracking char before the [
4596
+ clearStateChar();
4597
+ if (inClass) {
4598
+ re += '\\' + c;
4599
+ continue;
4600
+ }
4601
+ inClass = true;
4602
+ classStart = i;
4603
+ reClassStart = re.length;
4604
+ re += c;
4605
+ continue;
4606
+ case ']':
4607
+ // a right bracket shall lose its special
4608
+ // meaning and represent itself in
4609
+ // a bracket expression if it occurs
4610
+ // first in the list. -- POSIX.2 2.8.3.2
4611
+ if (i === classStart + 1 || !inClass) {
4612
+ re += '\\' + c;
4613
+ continue;
4614
+ }
4615
+ // split where the last [ was, make sure we don't have
4616
+ // an invalid re. if so, re-walk the contents of the
4617
+ // would-be class to re-translate any characters that
4618
+ // were passed through as-is
4619
+ // TODO: It would probably be faster to determine this
4620
+ // without a try/catch and a new RegExp, but it's tricky
4621
+ // to do safely. For now, this is safe and works.
4622
+ cs = pattern.substring(classStart + 1, i);
4623
+ try {
4624
+ RegExp('[' + braExpEscape(charUnescape(cs)) + ']');
4625
+ // looks good, finish up the class.
4626
+ re += c;
4627
+ }
4628
+ catch (er) {
4629
+ // out of order ranges in JS are errors, but in glob syntax,
4630
+ // they're just a range that matches nothing.
4631
+ re = re.substring(0, reClassStart) + '(?:$.)'; // match nothing ever
4632
+ }
4633
+ hasMagic = true;
4634
+ inClass = false;
4635
+ continue;
4636
+ default:
4637
+ // swallow any state char that wasn't consumed
4638
+ clearStateChar();
4639
+ if (reSpecials[c] && !(c === '^' && inClass)) {
4640
+ re += '\\';
4641
+ }
4642
+ re += c;
4643
+ break;
4644
+ } // switch
4645
+ } // for
4646
+ // handle the case where we left a class open.
4647
+ // "[abc" is valid, equivalent to "\[abc"
4648
+ if (inClass) {
4649
+ // split where the last [ was, and escape it
4650
+ // this is a huge pita. We now have to re-walk
4651
+ // the contents of the would-be class to re-translate
4652
+ // any characters that were passed through as-is
4653
+ cs = pattern.slice(classStart + 1);
4654
+ sp = this.parse(cs, SUBPARSE);
4655
+ re = re.substring(0, reClassStart) + '\\[' + sp[0];
4656
+ hasMagic = hasMagic || sp[1];
4657
+ }
4658
+ // handle the case where we had a +( thing at the *end*
4659
+ // of the pattern.
4660
+ // each pattern list stack adds 3 chars, and we need to go through
4661
+ // and escape any | chars that were passed through as-is for the regexp.
4662
+ // Go through and escape them, taking care not to double-escape any
4663
+ // | chars that were already escaped.
4664
+ for (pl = patternListStack.pop(); pl; pl = patternListStack.pop()) {
4665
+ let tail;
4666
+ tail = re.slice(pl.reStart + pl.open.length);
4667
+ this.debug(this.pattern, 'setting tail', re, pl);
4668
+ // maybe some even number of \, then maybe 1 \, followed by a |
4669
+ tail = tail.replace(/((?:\\{2}){0,64})(\\?)\|/g, (_, $1, $2) => {
4670
+ if (!$2) {
4671
+ // the | isn't already escaped, so escape it.
4672
+ $2 = '\\';
4673
+ // should already be done
4674
+ /* c8 ignore start */
4675
+ }
4676
+ /* c8 ignore stop */
4677
+ // need to escape all those slashes *again*, without escaping the
4678
+ // one that we need for escaping the | character. As it works out,
4679
+ // escaping an even number of slashes can be done by simply repeating
4680
+ // it exactly after itself. That's why this trick works.
4681
+ //
4682
+ // I am sorry that you have to see this.
4683
+ return $1 + $1 + $2 + '|';
4684
+ });
4685
+ this.debug('tail=%j\n %s', tail, tail, pl, re);
4686
+ const t = pl.type === '*' ? star : pl.type === '?' ? qmark : '\\' + pl.type;
4324
4687
  hasMagic = true;
4325
- break
4326
- default:
4327
- re += '\\' + stateChar;
4328
- break
4688
+ re = re.slice(0, pl.reStart) + t + '\\(' + tail;
4329
4689
  }
4330
- this.debug('clearStateChar %j %j', stateChar, re);
4331
- stateChar = false;
4332
- }
4333
- };
4334
-
4335
- for (let i = 0, c; (i < pattern.length) && (c = pattern.charAt(i)); i++) {
4336
- this.debug('%s\t%s %s %j', pattern, i, re, c);
4337
-
4338
- // skip over any that are escaped.
4339
- if (escaping) {
4340
- /* istanbul ignore next - completely not allowed, even escaped. */
4341
- if (c === '/') {
4342
- return false
4690
+ // handle trailing things that only matter at the very end.
4691
+ clearStateChar();
4692
+ if (escaping) {
4693
+ // trailing \\
4694
+ re += '\\\\';
4343
4695
  }
4344
-
4345
- if (reSpecials[c]) {
4346
- re += '\\';
4696
+ // only need to apply the nodot start if the re starts with
4697
+ // something that could conceivably capture a dot
4698
+ const addPatternStart = addPatternStartSet[re.charAt(0)];
4699
+ // Hack to work around lack of negative lookbehind in JS
4700
+ // A pattern like: *.!(x).!(y|z) needs to ensure that a name
4701
+ // like 'a.xyz.yz' doesn't match. So, the first negative
4702
+ // lookahead, has to look ALL the way ahead, to the end of
4703
+ // the pattern.
4704
+ for (let n = negativeLists.length - 1; n > -1; n--) {
4705
+ const nl = negativeLists[n];
4706
+ const nlBefore = re.slice(0, nl.reStart);
4707
+ const nlFirst = re.slice(nl.reStart, nl.reEnd - 8);
4708
+ let nlAfter = re.slice(nl.reEnd);
4709
+ const nlLast = re.slice(nl.reEnd - 8, nl.reEnd) + nlAfter;
4710
+ // Handle nested stuff like *(*.js|!(*.json)), where open parens
4711
+ // mean that we should *not* include the ) in the bit that is considered
4712
+ // "after" the negated section.
4713
+ const closeParensBefore = nlBefore.split(')').length;
4714
+ const openParensBefore = nlBefore.split('(').length - closeParensBefore;
4715
+ let cleanAfter = nlAfter;
4716
+ for (let i = 0; i < openParensBefore; i++) {
4717
+ cleanAfter = cleanAfter.replace(/\)[+*?]?/, '');
4718
+ }
4719
+ nlAfter = cleanAfter;
4720
+ const dollar = nlAfter === '' && isSub !== SUBPARSE ? '(?:$|\\/)' : '';
4721
+ re = nlBefore + nlFirst + nlAfter + dollar + nlLast;
4347
4722
  }
4348
- re += c;
4349
- escaping = false;
4350
- continue
4351
- }
4352
-
4353
- switch (c) {
4354
- /* istanbul ignore next */
4355
- case '/': {
4356
- // Should already be path-split by now.
4357
- return false
4723
+ // if the re is not "" at this point, then we need to make sure
4724
+ // it doesn't match against an empty path part.
4725
+ // Otherwise a/* will match a/, which it should not.
4726
+ if (re !== '' && hasMagic) {
4727
+ re = '(?=.)' + re;
4358
4728
  }
4359
-
4360
- case '\\':
4361
- if (inClass && pattern.charAt(i + 1) === '-') {
4362
- re += c;
4363
- continue
4364
- }
4365
-
4366
- clearStateChar();
4367
- escaping = true;
4368
- continue
4369
-
4370
- // the various stateChar values
4371
- // for the "extglob" stuff.
4372
- case '?':
4373
- case '*':
4374
- case '+':
4375
- case '@':
4376
- case '!':
4377
- this.debug('%s\t%s %s %j <-- stateChar', pattern, i, re, c);
4378
-
4379
- // all of those are literals inside a class, except that
4380
- // the glob [!a] means [^a] in regexp
4381
- if (inClass) {
4382
- this.debug(' in class');
4383
- if (c === '!' && i === classStart + 1) c = '^';
4384
- re += c;
4385
- continue
4386
- }
4387
-
4388
- // coalesce consecutive non-globstar * characters
4389
- if (c === '*' && stateChar === '*') continue
4390
-
4391
- // if we already have a stateChar, then it means
4392
- // that there was something like ** or +? in there.
4393
- // Handle the stateChar, then proceed with this one.
4394
- this.debug('call clearStateChar %j', stateChar);
4395
- clearStateChar();
4396
- stateChar = c;
4397
- // if extglob is disabled, then +(asdf|foo) isn't a thing.
4398
- // just clear the statechar *now*, rather than even diving into
4399
- // the patternList stuff.
4400
- if (options.noext) clearStateChar();
4401
- continue
4402
-
4403
- case '(': {
4404
- if (inClass) {
4405
- re += '(';
4406
- continue
4407
- }
4408
-
4409
- if (!stateChar) {
4410
- re += '\\(';
4411
- continue
4412
- }
4413
-
4414
- const plEntry = {
4415
- type: stateChar,
4416
- start: i - 1,
4417
- reStart: re.length,
4418
- open: plTypes[stateChar].open,
4419
- close: plTypes[stateChar].close,
4420
- };
4421
- this.debug(this.pattern, '\t', plEntry);
4422
- patternListStack.push(plEntry);
4423
- // negation is (?:(?!(?:js)(?:<rest>))[^/]*)
4424
- re += plEntry.open;
4425
- // next entry starts with a dot maybe?
4426
- if (plEntry.start === 0 && plEntry.type !== '!') {
4427
- dotTravAllowed = true;
4428
- re += subPatternStart(pattern.slice(i + 1));
4429
- }
4430
- this.debug('plType %j %j', stateChar, re);
4431
- stateChar = false;
4432
- continue
4729
+ if (addPatternStart) {
4730
+ re = patternStart() + re;
4433
4731
  }
4434
-
4435
- case ')': {
4436
- const plEntry = patternListStack[patternListStack.length - 1];
4437
- if (inClass || !plEntry) {
4438
- re += '\\)';
4439
- continue
4440
- }
4441
- patternListStack.pop();
4442
-
4443
- // closing an extglob
4444
- clearStateChar();
4445
- hasMagic = true;
4446
- pl = plEntry;
4447
- // negation is (?:(?!js)[^/]*)
4448
- // The others are (?:<pattern>)<type>
4449
- re += pl.close;
4450
- if (pl.type === '!') {
4451
- negativeLists.push(Object.assign(pl, { reEnd: re.length }));
4452
- }
4453
- continue
4732
+ // parsing just a piece of a larger pattern.
4733
+ if (isSub === SUBPARSE) {
4734
+ return [re, hasMagic];
4454
4735
  }
4455
-
4456
- case '|': {
4457
- const plEntry = patternListStack[patternListStack.length - 1];
4458
- if (inClass || !plEntry) {
4459
- re += '\\|';
4460
- continue
4461
- }
4462
-
4463
- clearStateChar();
4464
- re += '|';
4465
- // next subpattern can start with a dot?
4466
- if (plEntry.start === 0 && plEntry.type !== '!') {
4467
- dotTravAllowed = true;
4468
- re += subPatternStart(pattern.slice(i + 1));
4469
- }
4470
- continue
4736
+ // if it's nocase, and the lcase/uppercase don't match, it's magic
4737
+ if (options.nocase && !hasMagic && !options.nocaseMagicOnly) {
4738
+ hasMagic = pattern.toUpperCase() !== pattern.toLowerCase();
4471
4739
  }
4472
-
4473
- // these are mostly the same in regexp and glob
4474
- case '[':
4475
- // swallow any state-tracking char before the [
4476
- clearStateChar();
4477
-
4478
- if (inClass) {
4479
- re += '\\' + c;
4480
- continue
4481
- }
4482
-
4483
- inClass = true;
4484
- classStart = i;
4485
- reClassStart = re.length;
4486
- re += c;
4487
- continue
4488
-
4489
- case ']':
4490
- // a right bracket shall lose its special
4491
- // meaning and represent itself in
4492
- // a bracket expression if it occurs
4493
- // first in the list. -- POSIX.2 2.8.3.2
4494
- if (i === classStart + 1 || !inClass) {
4495
- re += '\\' + c;
4496
- continue
4497
- }
4498
-
4499
- // split where the last [ was, make sure we don't have
4500
- // an invalid re. if so, re-walk the contents of the
4501
- // would-be class to re-translate any characters that
4502
- // were passed through as-is
4503
- // TODO: It would probably be faster to determine this
4504
- // without a try/catch and a new RegExp, but it's tricky
4505
- // to do safely. For now, this is safe and works.
4506
- cs = pattern.substring(classStart + 1, i);
4507
- try {
4508
- RegExp('[' + braExpEscape(charUnescape(cs)) + ']');
4509
- // looks good, finish up the class.
4510
- re += c;
4511
- } catch (er) {
4512
- // out of order ranges in JS are errors, but in glob syntax,
4513
- // they're just a range that matches nothing.
4514
- re = re.substring(0, reClassStart) + '(?:$.)'; // match nothing ever
4515
- }
4516
- hasMagic = true;
4517
- inClass = false;
4518
- continue
4519
-
4520
- default:
4521
- // swallow any state char that wasn't consumed
4522
- clearStateChar();
4523
-
4524
- if (reSpecials[c] && !(c === '^' && inClass)) {
4525
- re += '\\';
4526
- }
4527
-
4528
- re += c;
4529
- break
4530
-
4531
- } // switch
4532
- } // for
4533
-
4534
- // handle the case where we left a class open.
4535
- // "[abc" is valid, equivalent to "\[abc"
4536
- if (inClass) {
4537
- // split where the last [ was, and escape it
4538
- // this is a huge pita. We now have to re-walk
4539
- // the contents of the would-be class to re-translate
4540
- // any characters that were passed through as-is
4541
- cs = pattern.slice(classStart + 1);
4542
- sp = this.parse(cs, SUBPARSE);
4543
- re = re.substring(0, reClassStart) + '\\[' + sp[0];
4544
- hasMagic = hasMagic || sp[1];
4545
- }
4546
-
4547
- // handle the case where we had a +( thing at the *end*
4548
- // of the pattern.
4549
- // each pattern list stack adds 3 chars, and we need to go through
4550
- // and escape any | chars that were passed through as-is for the regexp.
4551
- // Go through and escape them, taking care not to double-escape any
4552
- // | chars that were already escaped.
4553
- for (pl = patternListStack.pop(); pl; pl = patternListStack.pop()) {
4554
- let tail;
4555
- tail = re.slice(pl.reStart + pl.open.length);
4556
- this.debug('setting tail', re, pl);
4557
- // maybe some even number of \, then maybe 1 \, followed by a |
4558
- tail = tail.replace(/((?:\\{2}){0,64})(\\?)\|/g, (_, $1, $2) => {
4559
- /* istanbul ignore else - should already be done */
4560
- if (!$2) {
4561
- // the | isn't already escaped, so escape it.
4562
- $2 = '\\';
4740
+ // skip the regexp for non-magical patterns
4741
+ // unescape anything in it, though, so that it'll be
4742
+ // an exact match against a file etc.
4743
+ if (!hasMagic) {
4744
+ return globUnescape(pattern);
4563
4745
  }
4564
-
4565
- // need to escape all those slashes *again*, without escaping the
4566
- // one that we need for escaping the | character. As it works out,
4567
- // escaping an even number of slashes can be done by simply repeating
4568
- // it exactly after itself. That's why this trick works.
4569
- //
4570
- // I am sorry that you have to see this.
4571
- return $1 + $1 + $2 + '|'
4572
- });
4573
-
4574
- this.debug('tail=%j\n %s', tail, tail, pl, re);
4575
- const t = pl.type === '*' ? star
4576
- : pl.type === '?' ? qmark
4577
- : '\\' + pl.type;
4578
-
4579
- hasMagic = true;
4580
- re = re.slice(0, pl.reStart) + t + '\\(' + tail;
4581
- }
4582
-
4583
- // handle trailing things that only matter at the very end.
4584
- clearStateChar();
4585
- if (escaping) {
4586
- // trailing \\
4587
- re += '\\\\';
4588
- }
4589
-
4590
- // only need to apply the nodot start if the re starts with
4591
- // something that could conceivably capture a dot
4592
- const addPatternStart = addPatternStartSet[re.charAt(0)];
4593
-
4594
- // Hack to work around lack of negative lookbehind in JS
4595
- // A pattern like: *.!(x).!(y|z) needs to ensure that a name
4596
- // like 'a.xyz.yz' doesn't match. So, the first negative
4597
- // lookahead, has to look ALL the way ahead, to the end of
4598
- // the pattern.
4599
- for (let n = negativeLists.length - 1; n > -1; n--) {
4600
- const nl = negativeLists[n];
4601
-
4602
- const nlBefore = re.slice(0, nl.reStart);
4603
- const nlFirst = re.slice(nl.reStart, nl.reEnd - 8);
4604
- let nlAfter = re.slice(nl.reEnd);
4605
- const nlLast = re.slice(nl.reEnd - 8, nl.reEnd) + nlAfter;
4606
-
4607
- // Handle nested stuff like *(*.js|!(*.json)), where open parens
4608
- // mean that we should *not* include the ) in the bit that is considered
4609
- // "after" the negated section.
4610
- const closeParensBefore = nlBefore.split(')').length;
4611
- const openParensBefore = nlBefore.split('(').length - closeParensBefore;
4612
- let cleanAfter = nlAfter;
4613
- for (let i = 0; i < openParensBefore; i++) {
4614
- cleanAfter = cleanAfter.replace(/\)[+*?]?/, '');
4615
- }
4616
- nlAfter = cleanAfter;
4617
-
4618
- const dollar = nlAfter === '' && isSub !== SUBPARSE ? '(?:$|\\/)' : '';
4619
-
4620
- re = nlBefore + nlFirst + nlAfter + dollar + nlLast;
4621
- }
4622
-
4623
- // if the re is not "" at this point, then we need to make sure
4624
- // it doesn't match against an empty path part.
4625
- // Otherwise a/* will match a/, which it should not.
4626
- if (re !== '' && hasMagic) {
4627
- re = '(?=.)' + re;
4628
- }
4629
-
4630
- if (addPatternStart) {
4631
- re = patternStart() + re;
4632
- }
4633
-
4634
- // parsing just a piece of a larger pattern.
4635
- if (isSub === SUBPARSE) {
4636
- return [re, hasMagic]
4637
- }
4638
-
4639
- // if it's nocase, and the lcase/uppercase don't match, it's magic
4640
- if (options.nocase && !hasMagic) {
4641
- hasMagic = pattern.toUpperCase() !== pattern.toLowerCase();
4642
- }
4643
-
4644
- // skip the regexp for non-magical patterns
4645
- // unescape anything in it, though, so that it'll be
4646
- // an exact match against a file etc.
4647
- if (!hasMagic) {
4648
- return globUnescape(pattern)
4746
+ const flags = options.nocase ? 'i' : '';
4747
+ try {
4748
+ const ext = fastTest
4749
+ ? {
4750
+ _glob: pattern,
4751
+ _src: re,
4752
+ test: fastTest,
4753
+ }
4754
+ : {
4755
+ _glob: pattern,
4756
+ _src: re,
4757
+ };
4758
+ return Object.assign(new RegExp('^' + re + '$', flags), ext);
4759
+ /* c8 ignore start */
4760
+ }
4761
+ catch (er) {
4762
+ // should be impossible
4763
+ // If it was an invalid regular expression, then it can't match
4764
+ // anything. This trick looks for a character after the end of
4765
+ // the string, which is of course impossible, except in multi-line
4766
+ // mode, but it's not a /m regex.
4767
+ this.debug('invalid regexp', er);
4768
+ return new RegExp('$.');
4769
+ }
4770
+ /* c8 ignore stop */
4649
4771
  }
4650
-
4651
- const flags = options.nocase ? 'i' : '';
4652
- try {
4653
- return Object.assign(new RegExp('^' + re + '$', flags), {
4654
- _glob: pattern,
4655
- _src: re,
4656
- })
4657
- } catch (er) /* istanbul ignore next - should be impossible */ {
4658
- // If it was an invalid regular expression, then it can't match
4659
- // anything. This trick looks for a character after the end of
4660
- // the string, which is of course impossible, except in multi-line
4661
- // mode, but it's not a /m regex.
4662
- return new RegExp('$.')
4663
- }
4664
- }
4665
-
4666
- makeRe () {
4667
- if (this.regexp || this.regexp === false) return this.regexp
4668
-
4669
- // at this point, this.set is a 2d array of partial
4670
- // pattern strings, or "**".
4671
- //
4672
- // It's better to use .match(). This function shouldn't
4673
- // be used, really, but it's pretty convenient sometimes,
4674
- // when you just want to work with a regex.
4675
- const set = this.set;
4676
-
4677
- if (!set.length) {
4678
- this.regexp = false;
4679
- return this.regexp
4680
- }
4681
- const options = this.options;
4682
-
4683
- const twoStar = options.noglobstar ? star
4684
- : options.dot ? twoStarDot
4685
- : twoStarNoDot;
4686
- const flags = options.nocase ? 'i' : '';
4687
-
4688
- // coalesce globstars and regexpify non-globstar patterns
4689
- // if it's the only item, then we just do one twoStar
4690
- // if it's the first, and there are more, prepend (\/|twoStar\/)? to next
4691
- // if it's the last, append (\/twoStar|) to previous
4692
- // if it's in the middle, append (\/|\/twoStar\/) to previous
4693
- // then filter out GLOBSTAR symbols
4694
- let re = set.map(pattern => {
4695
- pattern = pattern.map(p =>
4696
- typeof p === 'string' ? regExpEscape(p)
4697
- : p === GLOBSTAR ? GLOBSTAR
4698
- : p._src
4699
- ).reduce((set, p) => {
4700
- if (!(set[set.length - 1] === GLOBSTAR && p === GLOBSTAR)) {
4701
- set.push(p);
4772
+ makeRe() {
4773
+ if (this.regexp || this.regexp === false)
4774
+ return this.regexp;
4775
+ // at this point, this.set is a 2d array of partial
4776
+ // pattern strings, or "**".
4777
+ //
4778
+ // It's better to use .match(). This function shouldn't
4779
+ // be used, really, but it's pretty convenient sometimes,
4780
+ // when you just want to work with a regex.
4781
+ const set = this.set;
4782
+ if (!set.length) {
4783
+ this.regexp = false;
4784
+ return this.regexp;
4785
+ }
4786
+ const options = this.options;
4787
+ const twoStar = options.noglobstar
4788
+ ? star
4789
+ : options.dot
4790
+ ? twoStarDot
4791
+ : twoStarNoDot;
4792
+ const flags = options.nocase ? 'i' : '';
4793
+ // regexpify non-globstar patterns
4794
+ // if ** is only item, then we just do one twoStar
4795
+ // if ** is first, and there are more, prepend (\/|twoStar\/)? to next
4796
+ // if ** is last, append (\/twoStar|) to previous
4797
+ // if ** is in the middle, append (\/|\/twoStar\/) to previous
4798
+ // then filter out GLOBSTAR symbols
4799
+ let re = set
4800
+ .map(pattern => {
4801
+ const pp = pattern.map(p => typeof p === 'string'
4802
+ ? regExpEscape(p)
4803
+ : p === GLOBSTAR
4804
+ ? GLOBSTAR
4805
+ : p._src);
4806
+ pp.forEach((p, i) => {
4807
+ const next = pp[i + 1];
4808
+ const prev = pp[i - 1];
4809
+ if (p !== GLOBSTAR || prev === GLOBSTAR) {
4810
+ return;
4811
+ }
4812
+ if (prev === undefined) {
4813
+ if (next !== undefined && next !== GLOBSTAR) {
4814
+ pp[i + 1] = '(?:\\/|' + twoStar + '\\/)?' + next;
4815
+ }
4816
+ else {
4817
+ pp[i] = twoStar;
4818
+ }
4819
+ }
4820
+ else if (next === undefined) {
4821
+ pp[i - 1] = prev + '(?:\\/|' + twoStar + ')?';
4822
+ }
4823
+ else if (next !== GLOBSTAR) {
4824
+ pp[i - 1] = prev + '(?:\\/|\\/' + twoStar + '\\/)' + next;
4825
+ pp[i + 1] = GLOBSTAR;
4826
+ }
4827
+ });
4828
+ return pp.filter(p => p !== GLOBSTAR).join('/');
4829
+ })
4830
+ .join('|');
4831
+ // must match entire pattern
4832
+ // ending in a * or ** will make it less strict.
4833
+ re = '^(?:' + re + ')$';
4834
+ // can match anything, as long as it's not this.
4835
+ if (this.negate)
4836
+ re = '^(?!' + re + ').*$';
4837
+ try {
4838
+ this.regexp = new RegExp(re, flags);
4839
+ /* c8 ignore start */
4702
4840
  }
4703
- return set
4704
- }, []);
4705
- pattern.forEach((p, i) => {
4706
- if (p !== GLOBSTAR || pattern[i-1] === GLOBSTAR) {
4707
- return
4841
+ catch (ex) {
4842
+ // should be impossible
4843
+ this.regexp = false;
4708
4844
  }
4709
- if (i === 0) {
4710
- if (pattern.length > 1) {
4711
- pattern[i+1] = '(?:\\\/|' + twoStar + '\\\/)?' + pattern[i+1];
4712
- } else {
4713
- pattern[i] = twoStar;
4714
- }
4715
- } else if (i === pattern.length - 1) {
4716
- pattern[i-1] += '(?:\\\/|' + twoStar + ')?';
4717
- } else {
4718
- pattern[i-1] += '(?:\\\/|\\\/' + twoStar + '\\\/)' + pattern[i+1];
4719
- pattern[i+1] = GLOBSTAR;
4845
+ /* c8 ignore stop */
4846
+ return this.regexp;
4847
+ }
4848
+ slashSplit(p) {
4849
+ // if p starts with // on windows, we preserve that
4850
+ // so that UNC paths aren't broken. Otherwise, any number of
4851
+ // / characters are coalesced into one, unless
4852
+ // preserveMultipleSlashes is set to true.
4853
+ if (this.preserveMultipleSlashes) {
4854
+ return p.split('/');
4855
+ }
4856
+ else if (isWindows && /^\/\/[^\/]+/.test(p)) {
4857
+ // add an extra '' for the one we lose
4858
+ return ['', ...p.split(/\/+/)];
4859
+ }
4860
+ else {
4861
+ return p.split(/\/+/);
4720
4862
  }
4721
- });
4722
- return pattern.filter(p => p !== GLOBSTAR).join('/')
4723
- }).join('|');
4724
-
4725
- // must match entire pattern
4726
- // ending in a * or ** will make it less strict.
4727
- re = '^(?:' + re + ')$';
4728
-
4729
- // can match anything, as long as it's not this.
4730
- if (this.negate) re = '^(?!' + re + ').*$';
4731
-
4732
- try {
4733
- this.regexp = new RegExp(re, flags);
4734
- } catch (ex) /* istanbul ignore next - should be impossible */ {
4735
- this.regexp = false;
4736
- }
4737
- return this.regexp
4738
- }
4739
-
4740
- match (f, partial = this.partial) {
4741
- this.debug('match', f, this.pattern);
4742
- // short-circuit in the case of busted things.
4743
- // comments, etc.
4744
- if (this.comment) return false
4745
- if (this.empty) return f === ''
4746
-
4747
- if (f === '/' && partial) return true
4748
-
4749
- const options = this.options;
4750
-
4751
- // windows: need to use /, not \
4752
- if (path.sep !== '/') {
4753
- f = f.split(path.sep).join('/');
4754
4863
  }
4755
-
4756
- // treat the test path as a set of pathparts.
4757
- f = f.split(slashSplit);
4758
- this.debug(this.pattern, 'split', f);
4759
-
4760
- // just ONE of the pattern sets in this.set needs to match
4761
- // in order for it to be valid. If negating, then just one
4762
- // match means that we have failed.
4763
- // Either way, return on the first hit.
4764
-
4765
- const set = this.set;
4766
- this.debug(this.pattern, 'set', set);
4767
-
4768
- // Find the basename of the path by looking for the last non-empty segment
4769
- let filename;
4770
- for (let i = f.length - 1; i >= 0; i--) {
4771
- filename = f[i];
4772
- if (filename) break
4864
+ match(f, partial = this.partial) {
4865
+ this.debug('match', f, this.pattern);
4866
+ // short-circuit in the case of busted things.
4867
+ // comments, etc.
4868
+ if (this.comment) {
4869
+ return false;
4870
+ }
4871
+ if (this.empty) {
4872
+ return f === '';
4873
+ }
4874
+ if (f === '/' && partial) {
4875
+ return true;
4876
+ }
4877
+ const options = this.options;
4878
+ // windows: need to use /, not \
4879
+ if (path.sep !== '/') {
4880
+ f = f.split(path.sep).join('/');
4881
+ }
4882
+ // treat the test path as a set of pathparts.
4883
+ const ff = this.slashSplit(f);
4884
+ this.debug(this.pattern, 'split', ff);
4885
+ // just ONE of the pattern sets in this.set needs to match
4886
+ // in order for it to be valid. If negating, then just one
4887
+ // match means that we have failed.
4888
+ // Either way, return on the first hit.
4889
+ const set = this.set;
4890
+ this.debug(this.pattern, 'set', set);
4891
+ // Find the basename of the path by looking for the last non-empty segment
4892
+ let filename = ff[ff.length - 1];
4893
+ if (!filename) {
4894
+ for (let i = ff.length - 2; !filename && i >= 0; i--) {
4895
+ filename = ff[i];
4896
+ }
4897
+ }
4898
+ for (let i = 0; i < set.length; i++) {
4899
+ const pattern = set[i];
4900
+ let file = ff;
4901
+ if (options.matchBase && pattern.length === 1) {
4902
+ file = [filename];
4903
+ }
4904
+ const hit = this.matchOne(file, pattern, partial);
4905
+ if (hit) {
4906
+ if (options.flipNegate) {
4907
+ return true;
4908
+ }
4909
+ return !this.negate;
4910
+ }
4911
+ }
4912
+ // didn't get any hits. this is success if it's a negative
4913
+ // pattern, failure otherwise.
4914
+ if (options.flipNegate) {
4915
+ return false;
4916
+ }
4917
+ return this.negate;
4773
4918
  }
4774
-
4775
- for (let i = 0; i < set.length; i++) {
4776
- const pattern = set[i];
4777
- let file = f;
4778
- if (options.matchBase && pattern.length === 1) {
4779
- file = [filename];
4780
- }
4781
- const hit = this.matchOne(file, pattern, partial);
4782
- if (hit) {
4783
- if (options.flipNegate) return true
4784
- return !this.negate
4785
- }
4919
+ static defaults(def) {
4920
+ return minimatch.defaults(def).Minimatch;
4786
4921
  }
4787
-
4788
- // didn't get any hits. this is success if it's a negative
4789
- // pattern, failure otherwise.
4790
- if (options.flipNegate) return false
4791
- return this.negate
4792
- }
4793
-
4794
- static defaults (def) {
4795
- return minimatch.defaults(def).Minimatch
4796
- }
4797
4922
  }
4798
-
4799
4923
  minimatch.Minimatch = Minimatch;
4800
4924
 
4801
- var minimatch$1 = minimatch_1;
4802
-
4803
4925
  const EXPORT_PATTERN = {
4804
4926
  type: ramda.includes(ramda.__, [TYPES.EXPORT_DEFAULT_DECLARATION, TYPES.EXPORT_NAMED_DECLARATION])
4805
4927
  };
@@ -4830,9 +4952,9 @@
4830
4952
  const fullFilePath = context.getFilename();
4831
4953
  const basePath = context.options[0].basePath;
4832
4954
  return configs.find(config => {
4833
- const isIncluded = asArray(config.includes).some(pathPattern => minimatch$1(fullFilePath, basePath + pathPattern));
4955
+ const isIncluded = asArray(config.includes).some(pathPattern => minimatch(fullFilePath, basePath + pathPattern));
4834
4956
  if (config.includes && !isIncluded) return false;
4835
- const isExcluded = asArray(config.excludes).some(pathPattern => minimatch$1(fullFilePath, basePath + pathPattern));
4957
+ const isExcluded = asArray(config.excludes).some(pathPattern => minimatch(fullFilePath, basePath + pathPattern));
4836
4958
  return !(config.excludes && isExcluded);
4837
4959
  });
4838
4960
  };
@@ -5574,7 +5696,7 @@
5574
5696
  translationFiles = neetoCist.modifyBy({
5575
5697
  lng
5576
5698
  }, ramda.assoc("content", {
5577
- ...parseJsonData(path$2.join(translationsDirPath, changedFileName)),
5699
+ ...parseJsonData(path$1.join(translationsDirPath, changedFileName)),
5578
5700
  ...nanosContent[lng]
5579
5701
  }), translationFiles);
5580
5702
  });
@@ -5657,11 +5779,11 @@
5657
5779
  if (neetoCist.isNot(previousOptions, context.options[0])) {
5658
5780
  const nanosTranslationOption = context.options[0].nanosTranslationDir;
5659
5781
  translationFiles = context.options[0].languages.map(lng => {
5660
- nanosContent[lng] = nanosTranslationOption ? nanosTranslationOption.map(filePath => path$2.join(filePath, `${lng}.json`)).reduce((mergedObj, filePath) => ({
5782
+ nanosContent[lng] = nanosTranslationOption ? nanosTranslationOption.map(filePath => path$1.join(filePath, `${lng}.json`)).reduce((mergedObj, filePath) => ({
5661
5783
  ...mergedObj,
5662
5784
  ...parseJsonData(filePath)
5663
5785
  }), {}) : {};
5664
- const translationsFilePath = path$2.join(context.options[0].translationsDir, `${lng}.json`);
5786
+ const translationsFilePath = path$1.join(context.options[0].translationsDir, `${lng}.json`);
5665
5787
  const translationsContent = parseJsonData(translationsFilePath);
5666
5788
  const combinedContent = ramda.mergeDeepLeft(translationsContent, nanosContent[lng]);
5667
5789
  return {
@@ -7084,7 +7206,7 @@
7084
7206
 
7085
7207
  // Do not replace this with `isInsideApisDirectory` since this rule should include axios.js
7086
7208
  // `isInsideApisDirectory` returns false for apis/axios.js
7087
- const apisFolder = path$2.resolve(aliases?.apis || APIS_DIRECTORY);
7209
+ const apisFolder = path$1.resolve(aliases?.apis || APIS_DIRECTORY);
7088
7210
  if (context.getFilename().startsWith(apisFolder)) return;
7089
7211
  if (!isPackageImported(context, node, "axios")) return;
7090
7212
  context.report(node, NO_AXIOS_IMPORT_OUTSIDE_APIS_MESSAGE);
@@ -9530,7 +9652,7 @@
9530
9652
  const WHITELISTED_FOLDER_NAMES = ["constants", "utils"];
9531
9653
  const WHITELISTED_FILE_NAMES = ["constants", "utils"];
9532
9654
 
9533
- const getFolderName = fileName => path$2.basename(path$2.dirname(fileName));
9655
+ const getFolderName = fileName => path$1.basename(path$1.dirname(fileName));
9534
9656
  var filesInsideReactQueryFolderShouldEndWithApi = {
9535
9657
  meta: {
9536
9658
  type: "problem",
@@ -9562,7 +9684,7 @@
9562
9684
  };
9563
9685
  const isInsideReactQueryDirectory = context => {
9564
9686
  const filename = context.getFilename();
9565
- const reactQueryDirectory = path$2.resolve(REACT_QUERY_DIRECTORY);
9687
+ const reactQueryDirectory = path$1.resolve(REACT_QUERY_DIRECTORY);
9566
9688
  return filename.startsWith(reactQueryDirectory);
9567
9689
  };
9568
9690
  var useReactQueryForManagingRemoteData = {
@@ -10649,7 +10771,7 @@
10649
10771
 
10650
10772
  const IMAGE_PATH = "images/";
10651
10773
 
10652
- const resolvePath = relativePath => path$2.resolve(__dirname, "../../../../", relativePath);
10774
+ const resolvePath = relativePath => path$1.resolve(__dirname, "../../../../", relativePath);
10653
10775
  const isImportFileSvg = importPath => fs.existsSync(resolvePath(`app/assets/${importPath}.svg`));
10654
10776
  const findSrcAttributeIndex = (attributes, svgs) => neetoCist.findIndexBy({
10655
10777
  name: {
@@ -11536,7 +11658,7 @@
11536
11658
  const aliases = context.options[0];
11537
11659
  if (ramda.isEmpty(aliases) || ramda.isNil(aliases)) return;
11538
11660
  const importPath = node.source.value;
11539
- const importFullPath = importPath.startsWith("../") ? path$2.resolve(context.getFilename(), "../", importPath) : importPath;
11661
+ const importFullPath = importPath.startsWith("../") ? path$1.resolve(context.getFilename(), "../", importPath) : importPath;
11540
11662
  const matches = Object.entries(aliases).filter(([, path]) => importFullPath.startsWith(path) && ["/", undefined].includes(importFullPath.split(path)[1][0])).sort((first, second) => first.length - second.length);
11541
11663
  if (matches.length === 0) return;
11542
11664
  const aliasMatch = matches[matches.length - 1];