@bigbinary/eslint-plugin-neeto 1.8.2 → 1.8.4

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