html-validate 9.1.2 → 9.2.0

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.
package/dist/cjs/core.js CHANGED
@@ -435,6 +435,11 @@ class UserError extends NestedError {
435
435
  super(message, nested);
436
436
  Error.captureStackTrace(this, UserError);
437
437
  this.name = UserError.name;
438
+ Object.defineProperty(this, "isUserError", {
439
+ value: true,
440
+ enumerable: false,
441
+ writable: false
442
+ });
438
443
  }
439
444
  /**
440
445
  * @public
@@ -473,6 +478,10 @@ class InheritError extends UserError {
473
478
  }
474
479
  }
475
480
 
481
+ function isUserError(error) {
482
+ return Boolean(error && typeof error === "object" && "isUserError" in error);
483
+ }
484
+
476
485
  function getSummary(schema, obj, errors) {
477
486
  const output = betterAjvErrors__default.default(schema, obj, errors, {
478
487
  format: "js"
@@ -1947,7 +1956,7 @@ const table = {
1947
1956
  "nth-child": nthChild,
1948
1957
  scope
1949
1958
  };
1950
- function factory$1(name, context) {
1959
+ function factory(name, context) {
1951
1960
  const fn = table[name];
1952
1961
  if (fn) {
1953
1962
  return fn.bind(context);
@@ -2046,7 +2055,7 @@ function isQuotationMark(ch) {
2046
2055
  function isPseudoElement(ch, buffer) {
2047
2056
  return ch === ":" && buffer === ":";
2048
2057
  }
2049
- function* splitPattern$1(pattern) {
2058
+ function* splitPattern(pattern) {
2050
2059
  if (pattern === "") {
2051
2060
  return;
2052
2061
  }
@@ -2148,7 +2157,7 @@ class PseudoClassMatcher extends Matcher {
2148
2157
  this.args = args;
2149
2158
  }
2150
2159
  match(node, context) {
2151
- const fn = factory$1(this.name, context);
2160
+ const fn = factory(this.name, context);
2152
2161
  return fn(node, this.args);
2153
2162
  }
2154
2163
  }
@@ -2166,7 +2175,7 @@ class Pattern {
2166
2175
  this.selector = pattern;
2167
2176
  this.combinator = parseCombinator(match.shift(), pattern);
2168
2177
  this.tagName = match.shift() || "*";
2169
- this.pattern = Array.from(splitPattern$1(match[0]), (it) => this.createMatcher(it));
2178
+ this.pattern = Array.from(splitPattern(match[0]), (it) => this.createMatcher(it));
2170
2179
  }
2171
2180
  match(node, context) {
2172
2181
  return node.is(this.tagName) && this.pattern.every((cur) => cur.match(node, context));
@@ -13323,7 +13332,7 @@ class HtmlValidate {
13323
13332
  }
13324
13333
 
13325
13334
  const name = "html-validate";
13326
- const version = "9.1.2";
13335
+ const version = "9.2.0";
13327
13336
  const bugs = "https://gitlab.com/html-validate/html-validate/issues/new";
13328
13337
 
13329
13338
  function definePlugin(plugin) {
@@ -13639,777 +13648,802 @@ function compatibilityCheckImpl(name, declared, options) {
13639
13648
  return false;
13640
13649
  }
13641
13650
 
13642
- // A simple implementation of make-array
13643
- function makeArray (subject) {
13644
- return Array.isArray(subject)
13645
- ? subject
13646
- : [subject]
13647
- }
13648
-
13649
- const UNDEFINED = undefined;
13650
- const EMPTY = '';
13651
- const SPACE = ' ';
13652
- const ESCAPE = '\\';
13653
- const REGEX_TEST_BLANK_LINE = /^\s+$/;
13654
- const REGEX_INVALID_TRAILING_BACKSLASH = /(?:[^\\]|^)\\$/;
13655
- const REGEX_REPLACE_LEADING_EXCAPED_EXCLAMATION = /^\\!/;
13656
- const REGEX_REPLACE_LEADING_EXCAPED_HASH = /^\\#/;
13657
- const REGEX_SPLITALL_CRLF = /\r?\n/g;
13658
-
13659
- // Invalid:
13660
- // - /foo,
13661
- // - ./foo,
13662
- // - ../foo,
13663
- // - .
13664
- // - ..
13665
- // Valid:
13666
- // - .foo
13667
- const REGEX_TEST_INVALID_PATH = /^\.*\/|^\.+$/;
13668
-
13669
- const REGEX_TEST_TRAILING_SLASH = /\/$/;
13670
-
13671
- const SLASH = '/';
13672
-
13673
- // Do not use ternary expression here, since "istanbul ignore next" is buggy
13674
- let TMP_KEY_IGNORE = 'node-ignore';
13675
- /* istanbul ignore else */
13676
- if (typeof Symbol !== 'undefined') {
13677
- TMP_KEY_IGNORE = Symbol.for('node-ignore');
13678
- }
13679
- const KEY_IGNORE = TMP_KEY_IGNORE;
13680
-
13681
- const define = (object, key, value) => {
13682
- Object.defineProperty(object, key, {value});
13683
- return value
13684
- };
13685
-
13686
- const REGEX_REGEXP_RANGE = /([0-z])-([0-z])/g;
13687
-
13688
- const RETURN_FALSE = () => false;
13689
-
13690
- // Sanitize the range of a regular expression
13691
- // The cases are complicated, see test cases for details
13692
- const sanitizeRange = range => range.replace(
13693
- REGEX_REGEXP_RANGE,
13694
- (match, from, to) => from.charCodeAt(0) <= to.charCodeAt(0)
13695
- ? match
13696
- // Invalid range (out of order) which is ok for gitignore rules but
13697
- // fatal for JavaScript regular expression, so eliminate it.
13698
- : EMPTY
13699
- );
13700
-
13701
- // See fixtures #59
13702
- const cleanRangeBackSlash = slashes => {
13703
- const {length} = slashes;
13704
- return slashes.slice(0, length - length % 2)
13705
- };
13706
-
13707
- // > If the pattern ends with a slash,
13708
- // > it is removed for the purpose of the following description,
13709
- // > but it would only find a match with a directory.
13710
- // > In other words, foo/ will match a directory foo and paths underneath it,
13711
- // > but will not match a regular file or a symbolic link foo
13712
- // > (this is consistent with the way how pathspec works in general in Git).
13713
- // '`foo/`' will not match regular file '`foo`' or symbolic link '`foo`'
13714
- // -> ignore-rules will not deal with it, because it costs extra `fs.stat` call
13715
- // you could use option `mark: true` with `glob`
13716
-
13717
- // '`foo/`' should not continue with the '`..`'
13718
- const REPLACERS = [
13719
-
13720
- [
13721
- // Remove BOM
13722
- // TODO:
13723
- // Other similar zero-width characters?
13724
- /^\uFEFF/,
13725
- () => EMPTY
13726
- ],
13727
-
13728
- // > Trailing spaces are ignored unless they are quoted with backslash ("\")
13729
- [
13730
- // (a\ ) -> (a )
13731
- // (a ) -> (a)
13732
- // (a ) -> (a)
13733
- // (a \ ) -> (a )
13734
- /((?:\\\\)*?)(\\?\s+)$/,
13735
- (_, m1, m2) => m1 + (
13736
- m2.indexOf('\\') === 0
13737
- ? SPACE
13738
- : EMPTY
13739
- )
13740
- ],
13741
-
13742
- // Replace (\ ) with ' '
13743
- // (\ ) -> ' '
13744
- // (\\ ) -> '\\ '
13745
- // (\\\ ) -> '\\ '
13746
- [
13747
- /(\\+?)\s/g,
13748
- (_, m1) => {
13749
- const {length} = m1;
13750
- return m1.slice(0, length - length % 2) + SPACE
13751
- }
13752
- ],
13753
-
13754
- // Escape metacharacters
13755
- // which is written down by users but means special for regular expressions.
13756
-
13757
- // > There are 12 characters with special meanings:
13758
- // > - the backslash \,
13759
- // > - the caret ^,
13760
- // > - the dollar sign $,
13761
- // > - the period or dot .,
13762
- // > - the vertical bar or pipe symbol |,
13763
- // > - the question mark ?,
13764
- // > - the asterisk or star *,
13765
- // > - the plus sign +,
13766
- // > - the opening parenthesis (,
13767
- // > - the closing parenthesis ),
13768
- // > - and the opening square bracket [,
13769
- // > - the opening curly brace {,
13770
- // > These special characters are often called "metacharacters".
13771
- [
13772
- /[\\$.|*+(){^]/g,
13773
- match => `\\${match}`
13774
- ],
13775
-
13776
- [
13777
- // > a question mark (?) matches a single character
13778
- /(?!\\)\?/g,
13779
- () => '[^/]'
13780
- ],
13781
-
13782
- // leading slash
13783
- [
13784
-
13785
- // > A leading slash matches the beginning of the pathname.
13786
- // > For example, "/*.c" matches "cat-file.c" but not "mozilla-sha1/sha1.c".
13787
- // A leading slash matches the beginning of the pathname
13788
- /^\//,
13789
- () => '^'
13790
- ],
13791
-
13792
- // replace special metacharacter slash after the leading slash
13793
- [
13794
- /\//g,
13795
- () => '\\/'
13796
- ],
13797
-
13798
- [
13799
- // > A leading "**" followed by a slash means match in all directories.
13800
- // > For example, "**/foo" matches file or directory "foo" anywhere,
13801
- // > the same as pattern "foo".
13802
- // > "**/foo/bar" matches file or directory "bar" anywhere that is directly
13803
- // > under directory "foo".
13804
- // Notice that the '*'s have been replaced as '\\*'
13805
- /^\^*\\\*\\\*\\\//,
13806
-
13807
- // '**/foo' <-> 'foo'
13808
- () => '^(?:.*\\/)?'
13809
- ],
13810
-
13811
- // starting
13812
- [
13813
- // there will be no leading '/'
13814
- // (which has been replaced by section "leading slash")
13815
- // If starts with '**', adding a '^' to the regular expression also works
13816
- /^(?=[^^])/,
13817
- function startingReplacer () {
13818
- // If has a slash `/` at the beginning or middle
13819
- return !/\/(?!$)/.test(this)
13820
- // > Prior to 2.22.1
13821
- // > If the pattern does not contain a slash /,
13822
- // > Git treats it as a shell glob pattern
13823
- // Actually, if there is only a trailing slash,
13824
- // git also treats it as a shell glob pattern
13825
-
13826
- // After 2.22.1 (compatible but clearer)
13827
- // > If there is a separator at the beginning or middle (or both)
13828
- // > of the pattern, then the pattern is relative to the directory
13829
- // > level of the particular .gitignore file itself.
13830
- // > Otherwise the pattern may also match at any level below
13831
- // > the .gitignore level.
13832
- ? '(?:^|\\/)'
13833
-
13834
- // > Otherwise, Git treats the pattern as a shell glob suitable for
13835
- // > consumption by fnmatch(3)
13836
- : '^'
13837
- }
13838
- ],
13839
-
13840
- // two globstars
13841
- [
13842
- // Use lookahead assertions so that we could match more than one `'/**'`
13843
- /\\\/\\\*\\\*(?=\\\/|$)/g,
13844
-
13845
- // Zero, one or several directories
13846
- // should not use '*', or it will be replaced by the next replacer
13847
-
13848
- // Check if it is not the last `'/**'`
13849
- (_, index, str) => index + 6 < str.length
13850
-
13851
- // case: /**/
13852
- // > A slash followed by two consecutive asterisks then a slash matches
13853
- // > zero or more directories.
13854
- // > For example, "a/**/b" matches "a/b", "a/x/b", "a/x/y/b" and so on.
13855
- // '/**/'
13856
- ? '(?:\\/[^\\/]+)*'
13857
-
13858
- // case: /**
13859
- // > A trailing `"/**"` matches everything inside.
13860
-
13861
- // #21: everything inside but it should not include the current folder
13862
- : '\\/.+'
13863
- ],
13864
-
13865
- // normal intermediate wildcards
13866
- [
13867
- // Never replace escaped '*'
13868
- // ignore rule '\*' will match the path '*'
13869
-
13870
- // 'abc.*/' -> go
13871
- // 'abc.*' -> skip this rule,
13872
- // coz trailing single wildcard will be handed by [trailing wildcard]
13873
- /(^|[^\\]+)(\\\*)+(?=.+)/g,
13874
-
13875
- // '*.js' matches '.js'
13876
- // '*.js' doesn't match 'abc'
13877
- (_, p1, p2) => {
13878
- // 1.
13879
- // > An asterisk "*" matches anything except a slash.
13880
- // 2.
13881
- // > Other consecutive asterisks are considered regular asterisks
13882
- // > and will match according to the previous rules.
13883
- const unescaped = p2.replace(/\\\*/g, '[^\\/]*');
13884
- return p1 + unescaped
13885
- }
13886
- ],
13887
-
13888
- [
13889
- // unescape, revert step 3 except for back slash
13890
- // For example, if a user escape a '\\*',
13891
- // after step 3, the result will be '\\\\\\*'
13892
- /\\\\\\(?=[$.|*+(){^])/g,
13893
- () => ESCAPE
13894
- ],
13895
-
13896
- [
13897
- // '\\\\' -> '\\'
13898
- /\\\\/g,
13899
- () => ESCAPE
13900
- ],
13901
-
13902
- [
13903
- // > The range notation, e.g. [a-zA-Z],
13904
- // > can be used to match one of the characters in a range.
13905
-
13906
- // `\` is escaped by step 3
13907
- /(\\)?\[([^\]/]*?)(\\*)($|\])/g,
13908
- (match, leadEscape, range, endEscape, close) => leadEscape === ESCAPE
13909
- // '\\[bar]' -> '\\\\[bar\\]'
13910
- ? `\\[${range}${cleanRangeBackSlash(endEscape)}${close}`
13911
- : close === ']'
13912
- ? endEscape.length % 2 === 0
13913
- // A normal case, and it is a range notation
13914
- // '[bar]'
13915
- // '[bar\\\\]'
13916
- ? `[${sanitizeRange(range)}${endEscape}]`
13917
- // Invalid range notaton
13918
- // '[bar\\]' -> '[bar\\\\]'
13919
- : '[]'
13920
- : '[]'
13921
- ],
13922
-
13923
- // ending
13924
- [
13925
- // 'js' will not match 'js.'
13926
- // 'ab' will not match 'abc'
13927
- /(?:[^*])$/,
13928
-
13929
- // WTF!
13930
- // https://git-scm.com/docs/gitignore
13931
- // changes in [2.22.1](https://git-scm.com/docs/gitignore/2.22.1)
13932
- // which re-fixes #24, #38
13933
-
13934
- // > If there is a separator at the end of the pattern then the pattern
13935
- // > will only match directories, otherwise the pattern can match both
13936
- // > files and directories.
13937
-
13938
- // 'js*' will not match 'a.js'
13939
- // 'js/' will not match 'a.js'
13940
- // 'js' will match 'a.js' and 'a.js/'
13941
- match => /\/$/.test(match)
13942
- // foo/ will not match 'foo'
13943
- ? `${match}$`
13944
- // foo matches 'foo' and 'foo/'
13945
- : `${match}(?=$|\\/$)`
13946
- ]
13947
- ];
13948
-
13949
- const REGEX_REPLACE_TRAILING_WILDCARD = /(^|\\\/)?\\\*$/;
13950
- const MODE_IGNORE = 'regex';
13951
- const MODE_CHECK_IGNORE = 'checkRegex';
13952
- const UNDERSCORE = '_';
13953
-
13954
- const TRAILING_WILD_CARD_REPLACERS = {
13955
- [MODE_IGNORE] (_, p1) {
13956
- const prefix = p1
13957
- // '\^':
13958
- // '/*' does not match EMPTY
13959
- // '/*' does not match everything
13960
-
13961
- // '\\\/':
13962
- // 'abc/*' does not match 'abc/'
13963
- ? `${p1}[^/]+`
13964
-
13965
- // 'a*' matches 'a'
13966
- // 'a*' matches 'aa'
13967
- : '[^/]*';
13968
-
13969
- return `${prefix}(?=$|\\/$)`
13970
- },
13971
-
13972
- [MODE_CHECK_IGNORE] (_, p1) {
13973
- // When doing `git check-ignore`
13974
- const prefix = p1
13975
- // '\\\/':
13976
- // 'abc/*' DOES match 'abc/' !
13977
- ? `${p1}[^/]*`
13978
-
13979
- // 'a*' matches 'a'
13980
- // 'a*' matches 'aa'
13981
- : '[^/]*';
13982
-
13983
- return `${prefix}(?=$|\\/$)`
13984
- }
13985
- };
13986
-
13987
- // @param {pattern}
13988
- const makeRegexPrefix = pattern => REPLACERS.reduce(
13989
- (prev, [matcher, replacer]) =>
13990
- prev.replace(matcher, replacer.bind(pattern)),
13991
- pattern
13992
- );
13993
-
13994
- const isString = subject => typeof subject === 'string';
13995
-
13996
- // > A blank line matches no files, so it can serve as a separator for readability.
13997
- const checkPattern = pattern => pattern
13998
- && isString(pattern)
13999
- && !REGEX_TEST_BLANK_LINE.test(pattern)
14000
- && !REGEX_INVALID_TRAILING_BACKSLASH.test(pattern)
14001
-
14002
- // > A line starting with # serves as a comment.
14003
- && pattern.indexOf('#') !== 0;
14004
-
14005
- const splitPattern = pattern => pattern
14006
- .split(REGEX_SPLITALL_CRLF)
14007
- .filter(Boolean);
14008
-
14009
- class IgnoreRule {
14010
- constructor (
14011
- pattern,
14012
- mark,
14013
- body,
14014
- ignoreCase,
14015
- negative,
14016
- prefix
14017
- ) {
14018
- this.pattern = pattern;
14019
- this.mark = mark;
14020
- this.negative = negative;
14021
-
14022
- define(this, 'body', body);
14023
- define(this, 'ignoreCase', ignoreCase);
14024
- define(this, 'regexPrefix', prefix);
14025
- }
14026
-
14027
- get regex () {
14028
- const key = UNDERSCORE + MODE_IGNORE;
14029
-
14030
- if (this[key]) {
14031
- return this[key]
14032
- }
14033
-
14034
- return this._make(MODE_IGNORE, key)
14035
- }
14036
-
14037
- get checkRegex () {
14038
- const key = UNDERSCORE + MODE_CHECK_IGNORE;
14039
-
14040
- if (this[key]) {
14041
- return this[key]
14042
- }
14043
-
14044
- return this._make(MODE_CHECK_IGNORE, key)
14045
- }
14046
-
14047
- _make (mode, key) {
14048
- const str = this.regexPrefix.replace(
14049
- REGEX_REPLACE_TRAILING_WILDCARD,
14050
-
14051
- // It does not need to bind pattern
14052
- TRAILING_WILD_CARD_REPLACERS[mode]
14053
- );
14054
-
14055
- const regex = this.ignoreCase
14056
- ? new RegExp(str, 'i')
14057
- : new RegExp(str);
14058
-
14059
- return define(this, key, regex)
14060
- }
14061
- }
14062
-
14063
- const createRule = ({
14064
- pattern,
14065
- mark
14066
- }, ignoreCase) => {
14067
- let negative = false;
14068
- let body = pattern;
14069
-
14070
- // > An optional prefix "!" which negates the pattern;
14071
- if (body.indexOf('!') === 0) {
14072
- negative = true;
14073
- body = body.substr(1);
14074
- }
13651
+ var ignore$1 = {exports: {}};
14075
13652
 
14076
- body = body
14077
- // > Put a backslash ("\") in front of the first "!" for patterns that
14078
- // > begin with a literal "!", for example, `"\!important!.txt"`.
14079
- .replace(REGEX_REPLACE_LEADING_EXCAPED_EXCLAMATION, '!')
14080
- // > Put a backslash ("\") in front of the first hash for patterns that
14081
- // > begin with a hash.
14082
- .replace(REGEX_REPLACE_LEADING_EXCAPED_HASH, '#');
13653
+ var hasRequiredIgnore;
14083
13654
 
14084
- const regexPrefix = makeRegexPrefix(body);
14085
-
14086
- return new IgnoreRule(
14087
- pattern,
14088
- mark,
14089
- body,
14090
- ignoreCase,
14091
- negative,
14092
- regexPrefix
14093
- )
14094
- };
14095
-
14096
- class RuleManager {
14097
- constructor (ignoreCase) {
14098
- this._ignoreCase = ignoreCase;
14099
- this._rules = [];
14100
- }
14101
-
14102
- _add (pattern) {
14103
- // #32
14104
- if (pattern && pattern[KEY_IGNORE]) {
14105
- this._rules = this._rules.concat(pattern._rules._rules);
14106
- this._added = true;
14107
- return
14108
- }
14109
-
14110
- if (isString(pattern)) {
14111
- pattern = {
14112
- pattern
14113
- };
14114
- }
14115
-
14116
- if (checkPattern(pattern.pattern)) {
14117
- const rule = createRule(pattern, this._ignoreCase);
14118
- this._added = true;
14119
- this._rules.push(rule);
14120
- }
14121
- }
13655
+ function requireIgnore () {
13656
+ if (hasRequiredIgnore) return ignore$1.exports;
13657
+ hasRequiredIgnore = 1;
13658
+ // A simple implementation of make-array
13659
+ function makeArray (subject) {
13660
+ return Array.isArray(subject)
13661
+ ? subject
13662
+ : [subject]
13663
+ }
14122
13664
 
14123
- // @param {Array<string> | string | Ignore} pattern
14124
- add (pattern) {
14125
- this._added = false;
13665
+ const UNDEFINED = undefined;
13666
+ const EMPTY = '';
13667
+ const SPACE = ' ';
13668
+ const ESCAPE = '\\';
13669
+ const REGEX_TEST_BLANK_LINE = /^\s+$/;
13670
+ const REGEX_INVALID_TRAILING_BACKSLASH = /(?:[^\\]|^)\\$/;
13671
+ const REGEX_REPLACE_LEADING_EXCAPED_EXCLAMATION = /^\\!/;
13672
+ const REGEX_REPLACE_LEADING_EXCAPED_HASH = /^\\#/;
13673
+ const REGEX_SPLITALL_CRLF = /\r?\n/g;
13674
+
13675
+ // Invalid:
13676
+ // - /foo,
13677
+ // - ./foo,
13678
+ // - ../foo,
13679
+ // - .
13680
+ // - ..
13681
+ // Valid:
13682
+ // - .foo
13683
+ const REGEX_TEST_INVALID_PATH = /^\.*\/|^\.+$/;
13684
+
13685
+ const REGEX_TEST_TRAILING_SLASH = /\/$/;
13686
+
13687
+ const SLASH = '/';
13688
+
13689
+ // Do not use ternary expression here, since "istanbul ignore next" is buggy
13690
+ let TMP_KEY_IGNORE = 'node-ignore';
13691
+ /* istanbul ignore else */
13692
+ if (typeof Symbol !== 'undefined') {
13693
+ TMP_KEY_IGNORE = Symbol.for('node-ignore');
13694
+ }
13695
+ const KEY_IGNORE = TMP_KEY_IGNORE;
14126
13696
 
14127
- makeArray(
14128
- isString(pattern)
14129
- ? splitPattern(pattern)
14130
- : pattern
14131
- ).forEach(this._add, this);
13697
+ const define = (object, key, value) => {
13698
+ Object.defineProperty(object, key, {value});
13699
+ return value
13700
+ };
14132
13701
 
14133
- return this._added
14134
- }
13702
+ const REGEX_REGEXP_RANGE = /([0-z])-([0-z])/g;
13703
+
13704
+ const RETURN_FALSE = () => false;
13705
+
13706
+ // Sanitize the range of a regular expression
13707
+ // The cases are complicated, see test cases for details
13708
+ const sanitizeRange = range => range.replace(
13709
+ REGEX_REGEXP_RANGE,
13710
+ (match, from, to) => from.charCodeAt(0) <= to.charCodeAt(0)
13711
+ ? match
13712
+ // Invalid range (out of order) which is ok for gitignore rules but
13713
+ // fatal for JavaScript regular expression, so eliminate it.
13714
+ : EMPTY
13715
+ );
13716
+
13717
+ // See fixtures #59
13718
+ const cleanRangeBackSlash = slashes => {
13719
+ const {length} = slashes;
13720
+ return slashes.slice(0, length - length % 2)
13721
+ };
14135
13722
 
14136
- // Test one single path without recursively checking parent directories
14137
- //
14138
- // - checkUnignored `boolean` whether should check if the path is unignored,
14139
- // setting `checkUnignored` to `false` could reduce additional
14140
- // path matching.
14141
- // - check `string` either `MODE_IGNORE` or `MODE_CHECK_IGNORE`
13723
+ // > If the pattern ends with a slash,
13724
+ // > it is removed for the purpose of the following description,
13725
+ // > but it would only find a match with a directory.
13726
+ // > In other words, foo/ will match a directory foo and paths underneath it,
13727
+ // > but will not match a regular file or a symbolic link foo
13728
+ // > (this is consistent with the way how pathspec works in general in Git).
13729
+ // '`foo/`' will not match regular file '`foo`' or symbolic link '`foo`'
13730
+ // -> ignore-rules will not deal with it, because it costs extra `fs.stat` call
13731
+ // you could use option `mark: true` with `glob`
13732
+
13733
+ // '`foo/`' should not continue with the '`..`'
13734
+ const REPLACERS = [
13735
+
13736
+ [
13737
+ // Remove BOM
13738
+ // TODO:
13739
+ // Other similar zero-width characters?
13740
+ /^\uFEFF/,
13741
+ () => EMPTY
13742
+ ],
13743
+
13744
+ // > Trailing spaces are ignored unless they are quoted with backslash ("\")
13745
+ [
13746
+ // (a\ ) -> (a )
13747
+ // (a ) -> (a)
13748
+ // (a ) -> (a)
13749
+ // (a \ ) -> (a )
13750
+ /((?:\\\\)*?)(\\?\s+)$/,
13751
+ (_, m1, m2) => m1 + (
13752
+ m2.indexOf('\\') === 0
13753
+ ? SPACE
13754
+ : EMPTY
13755
+ )
13756
+ ],
13757
+
13758
+ // Replace (\ ) with ' '
13759
+ // (\ ) -> ' '
13760
+ // (\\ ) -> '\\ '
13761
+ // (\\\ ) -> '\\ '
13762
+ [
13763
+ /(\\+?)\s/g,
13764
+ (_, m1) => {
13765
+ const {length} = m1;
13766
+ return m1.slice(0, length - length % 2) + SPACE
13767
+ }
13768
+ ],
13769
+
13770
+ // Escape metacharacters
13771
+ // which is written down by users but means special for regular expressions.
13772
+
13773
+ // > There are 12 characters with special meanings:
13774
+ // > - the backslash \,
13775
+ // > - the caret ^,
13776
+ // > - the dollar sign $,
13777
+ // > - the period or dot .,
13778
+ // > - the vertical bar or pipe symbol |,
13779
+ // > - the question mark ?,
13780
+ // > - the asterisk or star *,
13781
+ // > - the plus sign +,
13782
+ // > - the opening parenthesis (,
13783
+ // > - the closing parenthesis ),
13784
+ // > - and the opening square bracket [,
13785
+ // > - the opening curly brace {,
13786
+ // > These special characters are often called "metacharacters".
13787
+ [
13788
+ /[\\$.|*+(){^]/g,
13789
+ match => `\\${match}`
13790
+ ],
13791
+
13792
+ [
13793
+ // > a question mark (?) matches a single character
13794
+ /(?!\\)\?/g,
13795
+ () => '[^/]'
13796
+ ],
13797
+
13798
+ // leading slash
13799
+ [
13800
+
13801
+ // > A leading slash matches the beginning of the pathname.
13802
+ // > For example, "/*.c" matches "cat-file.c" but not "mozilla-sha1/sha1.c".
13803
+ // A leading slash matches the beginning of the pathname
13804
+ /^\//,
13805
+ () => '^'
13806
+ ],
13807
+
13808
+ // replace special metacharacter slash after the leading slash
13809
+ [
13810
+ /\//g,
13811
+ () => '\\/'
13812
+ ],
13813
+
13814
+ [
13815
+ // > A leading "**" followed by a slash means match in all directories.
13816
+ // > For example, "**/foo" matches file or directory "foo" anywhere,
13817
+ // > the same as pattern "foo".
13818
+ // > "**/foo/bar" matches file or directory "bar" anywhere that is directly
13819
+ // > under directory "foo".
13820
+ // Notice that the '*'s have been replaced as '\\*'
13821
+ /^\^*\\\*\\\*\\\//,
13822
+
13823
+ // '**/foo' <-> 'foo'
13824
+ () => '^(?:.*\\/)?'
13825
+ ],
13826
+
13827
+ // starting
13828
+ [
13829
+ // there will be no leading '/'
13830
+ // (which has been replaced by section "leading slash")
13831
+ // If starts with '**', adding a '^' to the regular expression also works
13832
+ /^(?=[^^])/,
13833
+ function startingReplacer () {
13834
+ // If has a slash `/` at the beginning or middle
13835
+ return !/\/(?!$)/.test(this)
13836
+ // > Prior to 2.22.1
13837
+ // > If the pattern does not contain a slash /,
13838
+ // > Git treats it as a shell glob pattern
13839
+ // Actually, if there is only a trailing slash,
13840
+ // git also treats it as a shell glob pattern
13841
+
13842
+ // After 2.22.1 (compatible but clearer)
13843
+ // > If there is a separator at the beginning or middle (or both)
13844
+ // > of the pattern, then the pattern is relative to the directory
13845
+ // > level of the particular .gitignore file itself.
13846
+ // > Otherwise the pattern may also match at any level below
13847
+ // > the .gitignore level.
13848
+ ? '(?:^|\\/)'
13849
+
13850
+ // > Otherwise, Git treats the pattern as a shell glob suitable for
13851
+ // > consumption by fnmatch(3)
13852
+ : '^'
13853
+ }
13854
+ ],
13855
+
13856
+ // two globstars
13857
+ [
13858
+ // Use lookahead assertions so that we could match more than one `'/**'`
13859
+ /\\\/\\\*\\\*(?=\\\/|$)/g,
13860
+
13861
+ // Zero, one or several directories
13862
+ // should not use '*', or it will be replaced by the next replacer
13863
+
13864
+ // Check if it is not the last `'/**'`
13865
+ (_, index, str) => index + 6 < str.length
13866
+
13867
+ // case: /**/
13868
+ // > A slash followed by two consecutive asterisks then a slash matches
13869
+ // > zero or more directories.
13870
+ // > For example, "a/**/b" matches "a/b", "a/x/b", "a/x/y/b" and so on.
13871
+ // '/**/'
13872
+ ? '(?:\\/[^\\/]+)*'
13873
+
13874
+ // case: /**
13875
+ // > A trailing `"/**"` matches everything inside.
13876
+
13877
+ // #21: everything inside but it should not include the current folder
13878
+ : '\\/.+'
13879
+ ],
13880
+
13881
+ // normal intermediate wildcards
13882
+ [
13883
+ // Never replace escaped '*'
13884
+ // ignore rule '\*' will match the path '*'
13885
+
13886
+ // 'abc.*/' -> go
13887
+ // 'abc.*' -> skip this rule,
13888
+ // coz trailing single wildcard will be handed by [trailing wildcard]
13889
+ /(^|[^\\]+)(\\\*)+(?=.+)/g,
13890
+
13891
+ // '*.js' matches '.js'
13892
+ // '*.js' doesn't match 'abc'
13893
+ (_, p1, p2) => {
13894
+ // 1.
13895
+ // > An asterisk "*" matches anything except a slash.
13896
+ // 2.
13897
+ // > Other consecutive asterisks are considered regular asterisks
13898
+ // > and will match according to the previous rules.
13899
+ const unescaped = p2.replace(/\\\*/g, '[^\\/]*');
13900
+ return p1 + unescaped
13901
+ }
13902
+ ],
13903
+
13904
+ [
13905
+ // unescape, revert step 3 except for back slash
13906
+ // For example, if a user escape a '\\*',
13907
+ // after step 3, the result will be '\\\\\\*'
13908
+ /\\\\\\(?=[$.|*+(){^])/g,
13909
+ () => ESCAPE
13910
+ ],
13911
+
13912
+ [
13913
+ // '\\\\' -> '\\'
13914
+ /\\\\/g,
13915
+ () => ESCAPE
13916
+ ],
13917
+
13918
+ [
13919
+ // > The range notation, e.g. [a-zA-Z],
13920
+ // > can be used to match one of the characters in a range.
13921
+
13922
+ // `\` is escaped by step 3
13923
+ /(\\)?\[([^\]/]*?)(\\*)($|\])/g,
13924
+ (match, leadEscape, range, endEscape, close) => leadEscape === ESCAPE
13925
+ // '\\[bar]' -> '\\\\[bar\\]'
13926
+ ? `\\[${range}${cleanRangeBackSlash(endEscape)}${close}`
13927
+ : close === ']'
13928
+ ? endEscape.length % 2 === 0
13929
+ // A normal case, and it is a range notation
13930
+ // '[bar]'
13931
+ // '[bar\\\\]'
13932
+ ? `[${sanitizeRange(range)}${endEscape}]`
13933
+ // Invalid range notaton
13934
+ // '[bar\\]' -> '[bar\\\\]'
13935
+ : '[]'
13936
+ : '[]'
13937
+ ],
13938
+
13939
+ // ending
13940
+ [
13941
+ // 'js' will not match 'js.'
13942
+ // 'ab' will not match 'abc'
13943
+ /(?:[^*])$/,
13944
+
13945
+ // WTF!
13946
+ // https://git-scm.com/docs/gitignore
13947
+ // changes in [2.22.1](https://git-scm.com/docs/gitignore/2.22.1)
13948
+ // which re-fixes #24, #38
13949
+
13950
+ // > If there is a separator at the end of the pattern then the pattern
13951
+ // > will only match directories, otherwise the pattern can match both
13952
+ // > files and directories.
13953
+
13954
+ // 'js*' will not match 'a.js'
13955
+ // 'js/' will not match 'a.js'
13956
+ // 'js' will match 'a.js' and 'a.js/'
13957
+ match => /\/$/.test(match)
13958
+ // foo/ will not match 'foo'
13959
+ ? `${match}$`
13960
+ // foo matches 'foo' and 'foo/'
13961
+ : `${match}(?=$|\\/$)`
13962
+ ]
13963
+ ];
13964
+
13965
+ const REGEX_REPLACE_TRAILING_WILDCARD = /(^|\\\/)?\\\*$/;
13966
+ const MODE_IGNORE = 'regex';
13967
+ const MODE_CHECK_IGNORE = 'checkRegex';
13968
+ const UNDERSCORE = '_';
13969
+
13970
+ const TRAILING_WILD_CARD_REPLACERS = {
13971
+ [MODE_IGNORE] (_, p1) {
13972
+ const prefix = p1
13973
+ // '\^':
13974
+ // '/*' does not match EMPTY
13975
+ // '/*' does not match everything
13976
+
13977
+ // '\\\/':
13978
+ // 'abc/*' does not match 'abc/'
13979
+ ? `${p1}[^/]+`
13980
+
13981
+ // 'a*' matches 'a'
13982
+ // 'a*' matches 'aa'
13983
+ : '[^/]*';
13984
+
13985
+ return `${prefix}(?=$|\\/$)`
13986
+ },
13987
+
13988
+ [MODE_CHECK_IGNORE] (_, p1) {
13989
+ // When doing `git check-ignore`
13990
+ const prefix = p1
13991
+ // '\\\/':
13992
+ // 'abc/*' DOES match 'abc/' !
13993
+ ? `${p1}[^/]*`
13994
+
13995
+ // 'a*' matches 'a'
13996
+ // 'a*' matches 'aa'
13997
+ : '[^/]*';
13998
+
13999
+ return `${prefix}(?=$|\\/$)`
14000
+ }
14001
+ };
14142
14002
 
14143
- // @returns {TestResult} true if a file is ignored
14144
- test (path, checkUnignored, mode) {
14145
- let ignored = false;
14146
- let unignored = false;
14147
- let matchedRule;
14003
+ // @param {pattern}
14004
+ const makeRegexPrefix = pattern => REPLACERS.reduce(
14005
+ (prev, [matcher, replacer]) =>
14006
+ prev.replace(matcher, replacer.bind(pattern)),
14007
+ pattern
14008
+ );
14009
+
14010
+ const isString = subject => typeof subject === 'string';
14011
+
14012
+ // > A blank line matches no files, so it can serve as a separator for readability.
14013
+ const checkPattern = pattern => pattern
14014
+ && isString(pattern)
14015
+ && !REGEX_TEST_BLANK_LINE.test(pattern)
14016
+ && !REGEX_INVALID_TRAILING_BACKSLASH.test(pattern)
14017
+
14018
+ // > A line starting with # serves as a comment.
14019
+ && pattern.indexOf('#') !== 0;
14020
+
14021
+ const splitPattern = pattern => pattern
14022
+ .split(REGEX_SPLITALL_CRLF)
14023
+ .filter(Boolean);
14024
+
14025
+ class IgnoreRule {
14026
+ constructor (
14027
+ pattern,
14028
+ mark,
14029
+ body,
14030
+ ignoreCase,
14031
+ negative,
14032
+ prefix
14033
+ ) {
14034
+ this.pattern = pattern;
14035
+ this.mark = mark;
14036
+ this.negative = negative;
14037
+
14038
+ define(this, 'body', body);
14039
+ define(this, 'ignoreCase', ignoreCase);
14040
+ define(this, 'regexPrefix', prefix);
14041
+ }
14042
+
14043
+ get regex () {
14044
+ const key = UNDERSCORE + MODE_IGNORE;
14045
+
14046
+ if (this[key]) {
14047
+ return this[key]
14048
+ }
14049
+
14050
+ return this._make(MODE_IGNORE, key)
14051
+ }
14052
+
14053
+ get checkRegex () {
14054
+ const key = UNDERSCORE + MODE_CHECK_IGNORE;
14055
+
14056
+ if (this[key]) {
14057
+ return this[key]
14058
+ }
14059
+
14060
+ return this._make(MODE_CHECK_IGNORE, key)
14061
+ }
14062
+
14063
+ _make (mode, key) {
14064
+ const str = this.regexPrefix.replace(
14065
+ REGEX_REPLACE_TRAILING_WILDCARD,
14066
+
14067
+ // It does not need to bind pattern
14068
+ TRAILING_WILD_CARD_REPLACERS[mode]
14069
+ );
14070
+
14071
+ const regex = this.ignoreCase
14072
+ ? new RegExp(str, 'i')
14073
+ : new RegExp(str);
14074
+
14075
+ return define(this, key, regex)
14076
+ }
14077
+ }
14148
14078
 
14149
- this._rules.forEach(rule => {
14150
- const {negative} = rule;
14079
+ const createRule = ({
14080
+ pattern,
14081
+ mark
14082
+ }, ignoreCase) => {
14083
+ let negative = false;
14084
+ let body = pattern;
14085
+
14086
+ // > An optional prefix "!" which negates the pattern;
14087
+ if (body.indexOf('!') === 0) {
14088
+ negative = true;
14089
+ body = body.substr(1);
14090
+ }
14091
+
14092
+ body = body
14093
+ // > Put a backslash ("\") in front of the first "!" for patterns that
14094
+ // > begin with a literal "!", for example, `"\!important!.txt"`.
14095
+ .replace(REGEX_REPLACE_LEADING_EXCAPED_EXCLAMATION, '!')
14096
+ // > Put a backslash ("\") in front of the first hash for patterns that
14097
+ // > begin with a hash.
14098
+ .replace(REGEX_REPLACE_LEADING_EXCAPED_HASH, '#');
14099
+
14100
+ const regexPrefix = makeRegexPrefix(body);
14101
+
14102
+ return new IgnoreRule(
14103
+ pattern,
14104
+ mark,
14105
+ body,
14106
+ ignoreCase,
14107
+ negative,
14108
+ regexPrefix
14109
+ )
14110
+ };
14151
14111
 
14152
- // | ignored : unignored
14153
- // -------- | ---------------------------------------
14154
- // negative | 0:0 | 0:1 | 1:0 | 1:1
14155
- // -------- | ------- | ------- | ------- | --------
14156
- // 0 | TEST | TEST | SKIP | X
14157
- // 1 | TESTIF | SKIP | TEST | X
14112
+ class RuleManager {
14113
+ constructor (ignoreCase) {
14114
+ this._ignoreCase = ignoreCase;
14115
+ this._rules = [];
14116
+ }
14117
+
14118
+ _add (pattern) {
14119
+ // #32
14120
+ if (pattern && pattern[KEY_IGNORE]) {
14121
+ this._rules = this._rules.concat(pattern._rules._rules);
14122
+ this._added = true;
14123
+ return
14124
+ }
14125
+
14126
+ if (isString(pattern)) {
14127
+ pattern = {
14128
+ pattern
14129
+ };
14130
+ }
14131
+
14132
+ if (checkPattern(pattern.pattern)) {
14133
+ const rule = createRule(pattern, this._ignoreCase);
14134
+ this._added = true;
14135
+ this._rules.push(rule);
14136
+ }
14137
+ }
14138
+
14139
+ // @param {Array<string> | string | Ignore} pattern
14140
+ add (pattern) {
14141
+ this._added = false;
14142
+
14143
+ makeArray(
14144
+ isString(pattern)
14145
+ ? splitPattern(pattern)
14146
+ : pattern
14147
+ ).forEach(this._add, this);
14148
+
14149
+ return this._added
14150
+ }
14151
+
14152
+ // Test one single path without recursively checking parent directories
14153
+ //
14154
+ // - checkUnignored `boolean` whether should check if the path is unignored,
14155
+ // setting `checkUnignored` to `false` could reduce additional
14156
+ // path matching.
14157
+ // - check `string` either `MODE_IGNORE` or `MODE_CHECK_IGNORE`
14158
+
14159
+ // @returns {TestResult} true if a file is ignored
14160
+ test (path, checkUnignored, mode) {
14161
+ let ignored = false;
14162
+ let unignored = false;
14163
+ let matchedRule;
14164
+
14165
+ this._rules.forEach(rule => {
14166
+ const {negative} = rule;
14167
+
14168
+ // | ignored : unignored
14169
+ // -------- | ---------------------------------------
14170
+ // negative | 0:0 | 0:1 | 1:0 | 1:1
14171
+ // -------- | ------- | ------- | ------- | --------
14172
+ // 0 | TEST | TEST | SKIP | X
14173
+ // 1 | TESTIF | SKIP | TEST | X
14174
+
14175
+ // - SKIP: always skip
14176
+ // - TEST: always test
14177
+ // - TESTIF: only test if checkUnignored
14178
+ // - X: that never happen
14179
+ if (
14180
+ unignored === negative && ignored !== unignored
14181
+ || negative && !ignored && !unignored && !checkUnignored
14182
+ ) {
14183
+ return
14184
+ }
14185
+
14186
+ const matched = rule[mode].test(path);
14187
+
14188
+ if (!matched) {
14189
+ return
14190
+ }
14191
+
14192
+ ignored = !negative;
14193
+ unignored = negative;
14194
+
14195
+ matchedRule = negative
14196
+ ? UNDEFINED
14197
+ : rule;
14198
+ });
14199
+
14200
+ const ret = {
14201
+ ignored,
14202
+ unignored
14203
+ };
14204
+
14205
+ if (matchedRule) {
14206
+ ret.rule = matchedRule;
14207
+ }
14208
+
14209
+ return ret
14210
+ }
14211
+ }
14158
14212
 
14159
- // - SKIP: always skip
14160
- // - TEST: always test
14161
- // - TESTIF: only test if checkUnignored
14162
- // - X: that never happen
14163
- if (
14164
- unignored === negative && ignored !== unignored
14165
- || negative && !ignored && !unignored && !checkUnignored
14166
- ) {
14167
- return
14168
- }
14213
+ const throwError = (message, Ctor) => {
14214
+ throw new Ctor(message)
14215
+ };
14169
14216
 
14170
- const matched = rule[mode].test(path);
14217
+ const checkPath = (path, originalPath, doThrow) => {
14218
+ if (!isString(path)) {
14219
+ return doThrow(
14220
+ `path must be a string, but got \`${originalPath}\``,
14221
+ TypeError
14222
+ )
14223
+ }
14224
+
14225
+ // We don't know if we should ignore EMPTY, so throw
14226
+ if (!path) {
14227
+ return doThrow(`path must not be empty`, TypeError)
14228
+ }
14229
+
14230
+ // Check if it is a relative path
14231
+ if (checkPath.isNotRelative(path)) {
14232
+ const r = '`path.relative()`d';
14233
+ return doThrow(
14234
+ `path should be a ${r} string, but got "${originalPath}"`,
14235
+ RangeError
14236
+ )
14237
+ }
14238
+
14239
+ return true
14240
+ };
14171
14241
 
14172
- if (!matched) {
14173
- return
14174
- }
14242
+ const isNotRelative = path => REGEX_TEST_INVALID_PATH.test(path);
14243
+
14244
+ checkPath.isNotRelative = isNotRelative;
14245
+
14246
+ // On windows, the following function will be replaced
14247
+ /* istanbul ignore next */
14248
+ checkPath.convert = p => p;
14249
+
14250
+
14251
+ class Ignore {
14252
+ constructor ({
14253
+ ignorecase = true,
14254
+ ignoreCase = ignorecase,
14255
+ allowRelativePaths = false
14256
+ } = {}) {
14257
+ define(this, KEY_IGNORE, true);
14258
+
14259
+ this._rules = new RuleManager(ignoreCase);
14260
+ this._strictPathCheck = !allowRelativePaths;
14261
+ this._initCache();
14262
+ }
14263
+
14264
+ _initCache () {
14265
+ // A cache for the result of `.ignores()`
14266
+ this._ignoreCache = Object.create(null);
14267
+
14268
+ // A cache for the result of `.test()`
14269
+ this._testCache = Object.create(null);
14270
+ }
14271
+
14272
+ add (pattern) {
14273
+ if (this._rules.add(pattern)) {
14274
+ // Some rules have just added to the ignore,
14275
+ // making the behavior changed,
14276
+ // so we need to re-initialize the result cache
14277
+ this._initCache();
14278
+ }
14279
+
14280
+ return this
14281
+ }
14282
+
14283
+ // legacy
14284
+ addPattern (pattern) {
14285
+ return this.add(pattern)
14286
+ }
14287
+
14288
+ // @returns {TestResult}
14289
+ _test (originalPath, cache, checkUnignored, slices) {
14290
+ const path = originalPath
14291
+ // Supports nullable path
14292
+ && checkPath.convert(originalPath);
14293
+
14294
+ checkPath(
14295
+ path,
14296
+ originalPath,
14297
+ this._strictPathCheck
14298
+ ? throwError
14299
+ : RETURN_FALSE
14300
+ );
14301
+
14302
+ return this._t(path, cache, checkUnignored, slices)
14303
+ }
14304
+
14305
+ checkIgnore (path) {
14306
+ // If the path doest not end with a slash, `.ignores()` is much equivalent
14307
+ // to `git check-ignore`
14308
+ if (!REGEX_TEST_TRAILING_SLASH.test(path)) {
14309
+ return this.test(path)
14310
+ }
14311
+
14312
+ const slices = path.split(SLASH).filter(Boolean);
14313
+ slices.pop();
14314
+
14315
+ if (slices.length) {
14316
+ const parent = this._t(
14317
+ slices.join(SLASH) + SLASH,
14318
+ this._testCache,
14319
+ true,
14320
+ slices
14321
+ );
14322
+
14323
+ if (parent.ignored) {
14324
+ return parent
14325
+ }
14326
+ }
14327
+
14328
+ return this._rules.test(path, false, MODE_CHECK_IGNORE)
14329
+ }
14330
+
14331
+ _t (
14332
+ // The path to be tested
14333
+ path,
14334
+
14335
+ // The cache for the result of a certain checking
14336
+ cache,
14337
+
14338
+ // Whether should check if the path is unignored
14339
+ checkUnignored,
14340
+
14341
+ // The path slices
14342
+ slices
14343
+ ) {
14344
+ if (path in cache) {
14345
+ return cache[path]
14346
+ }
14347
+
14348
+ if (!slices) {
14349
+ // path/to/a.js
14350
+ // ['path', 'to', 'a.js']
14351
+ slices = path.split(SLASH).filter(Boolean);
14352
+ }
14353
+
14354
+ slices.pop();
14355
+
14356
+ // If the path has no parent directory, just test it
14357
+ if (!slices.length) {
14358
+ return cache[path] = this._rules.test(path, checkUnignored, MODE_IGNORE)
14359
+ }
14360
+
14361
+ const parent = this._t(
14362
+ slices.join(SLASH) + SLASH,
14363
+ cache,
14364
+ checkUnignored,
14365
+ slices
14366
+ );
14367
+
14368
+ // If the path contains a parent directory, check the parent first
14369
+ return cache[path] = parent.ignored
14370
+ // > It is not possible to re-include a file if a parent directory of
14371
+ // > that file is excluded.
14372
+ ? parent
14373
+ : this._rules.test(path, checkUnignored, MODE_IGNORE)
14374
+ }
14375
+
14376
+ ignores (path) {
14377
+ return this._test(path, this._ignoreCache, false).ignored
14378
+ }
14379
+
14380
+ createFilter () {
14381
+ return path => !this.ignores(path)
14382
+ }
14383
+
14384
+ filter (paths) {
14385
+ return makeArray(paths).filter(this.createFilter())
14386
+ }
14387
+
14388
+ // @returns {TestResult}
14389
+ test (path) {
14390
+ return this._test(path, this._testCache, true)
14391
+ }
14392
+ }
14175
14393
 
14176
- ignored = !negative;
14177
- unignored = negative;
14394
+ const factory = options => new Ignore(options);
14395
+
14396
+ const isPathValid = path =>
14397
+ checkPath(path && checkPath.convert(path), path, RETURN_FALSE);
14398
+
14399
+
14400
+ // Windows
14401
+ // --------------------------------------------------------------
14402
+ /* istanbul ignore next */
14403
+ if (
14404
+ // Detect `process` so that it can run in browsers.
14405
+ typeof process !== 'undefined'
14406
+ && (
14407
+ process.env && process.env.IGNORE_TEST_WIN32
14408
+ || process.platform === 'win32'
14409
+ )
14410
+ ) {
14411
+ /* eslint no-control-regex: "off" */
14412
+ const makePosix = str => /^\\\\\?\\/.test(str)
14413
+ || /["<>|\u0000-\u001F]+/u.test(str)
14414
+ ? str
14415
+ : str.replace(/\\/g, '/');
14416
+
14417
+ checkPath.convert = makePosix;
14418
+
14419
+ // 'C:\\foo' <- 'C:\\foo' has been converted to 'C:/'
14420
+ // 'd:\\foo'
14421
+ const REGEX_TEST_WINDOWS_PATH_ABSOLUTE = /^[a-z]:\//i;
14422
+ checkPath.isNotRelative = path =>
14423
+ REGEX_TEST_WINDOWS_PATH_ABSOLUTE.test(path)
14424
+ || isNotRelative(path);
14425
+ }
14178
14426
 
14179
- matchedRule = negative
14180
- ? UNDEFINED
14181
- : rule;
14182
- });
14427
+ // COMMONJS_EXPORTS ////////////////////////////////////////////////////////////
14183
14428
 
14184
- const ret = {
14185
- ignored,
14186
- unignored
14187
- };
14429
+ ignore$1.exports = factory;
14188
14430
 
14189
- if (matchedRule) {
14190
- ret.rule = matchedRule;
14191
- }
14431
+ // Although it is an anti-pattern,
14432
+ // it is still widely misused by a lot of libraries in github
14433
+ // Ref: https://github.com/search?q=ignore.default%28%29&type=code
14434
+ factory.default = factory;
14192
14435
 
14193
- return ret
14194
- }
14436
+ ignore$1.exports.isPathValid = isPathValid;
14437
+ return ignore$1.exports;
14195
14438
  }
14196
14439
 
14197
- const throwError = (message, Ctor) => {
14198
- throw new Ctor(message)
14199
- };
14200
-
14201
- const checkPath = (path, originalPath, doThrow) => {
14202
- if (!isString(path)) {
14203
- return doThrow(
14204
- `path must be a string, but got \`${originalPath}\``,
14205
- TypeError
14206
- )
14207
- }
14208
-
14209
- // We don't know if we should ignore EMPTY, so throw
14210
- if (!path) {
14211
- return doThrow(`path must not be empty`, TypeError)
14212
- }
14213
-
14214
- // Check if it is a relative path
14215
- if (checkPath.isNotRelative(path)) {
14216
- const r = '`path.relative()`d';
14217
- return doThrow(
14218
- `path should be a ${r} string, but got "${originalPath}"`,
14219
- RangeError
14220
- )
14221
- }
14440
+ var ignoreExports = /*@__PURE__*/ requireIgnore();
14441
+ var ignore = /*@__PURE__*/getDefaultExportFromCjs(ignoreExports);
14222
14442
 
14223
- return true
14443
+ const engines = {
14444
+ node: "^18.19.0 || >= 20.6.0"
14224
14445
  };
14225
14446
 
14226
- const isNotRelative = path => REGEX_TEST_INVALID_PATH.test(path);
14227
-
14228
- checkPath.isNotRelative = isNotRelative;
14229
-
14230
- // On windows, the following function will be replaced
14231
- /* istanbul ignore next */
14232
- checkPath.convert = p => p;
14233
-
14234
-
14235
- class Ignore {
14236
- constructor ({
14237
- ignorecase = true,
14238
- ignoreCase = ignorecase,
14239
- allowRelativePaths = false
14240
- } = {}) {
14241
- define(this, KEY_IGNORE, true);
14242
-
14243
- this._rules = new RuleManager(ignoreCase);
14244
- this._strictPathCheck = !allowRelativePaths;
14245
- this._initCache();
14246
- }
14247
-
14248
- _initCache () {
14249
- // A cache for the result of `.ignores()`
14250
- this._ignoreCache = Object.create(null);
14251
-
14252
- // A cache for the result of `.test()`
14253
- this._testCache = Object.create(null);
14254
- }
14255
-
14256
- add (pattern) {
14257
- if (this._rules.add(pattern)) {
14258
- // Some rules have just added to the ignore,
14259
- // making the behavior changed,
14260
- // so we need to re-initialize the result cache
14261
- this._initCache();
14262
- }
14263
-
14264
- return this
14265
- }
14266
-
14267
- // legacy
14268
- addPattern (pattern) {
14269
- return this.add(pattern)
14270
- }
14271
-
14272
- // @returns {TestResult}
14273
- _test (originalPath, cache, checkUnignored, slices) {
14274
- const path = originalPath
14275
- // Supports nullable path
14276
- && checkPath.convert(originalPath);
14277
-
14278
- checkPath(
14279
- path,
14280
- originalPath,
14281
- this._strictPathCheck
14282
- ? throwError
14283
- : RETURN_FALSE
14284
- );
14285
-
14286
- return this._t(path, cache, checkUnignored, slices)
14287
- }
14288
-
14289
- checkIgnore (path) {
14290
- // If the path doest not end with a slash, `.ignores()` is much equivalent
14291
- // to `git check-ignore`
14292
- if (!REGEX_TEST_TRAILING_SLASH.test(path)) {
14293
- return this.test(path)
14294
- }
14295
-
14296
- const slices = path.split(SLASH).filter(Boolean);
14297
- slices.pop();
14298
-
14299
- if (slices.length) {
14300
- const parent = this._t(
14301
- slices.join(SLASH) + SLASH,
14302
- this._testCache,
14303
- true,
14304
- slices
14305
- );
14306
-
14307
- if (parent.ignored) {
14308
- return parent
14309
- }
14310
- }
14311
-
14312
- return this._rules.test(path, false, MODE_CHECK_IGNORE)
14313
- }
14314
-
14315
- _t (
14316
- // The path to be tested
14317
- path,
14318
-
14319
- // The cache for the result of a certain checking
14320
- cache,
14321
-
14322
- // Whether should check if the path is unignored
14323
- checkUnignored,
14324
-
14325
- // The path slices
14326
- slices
14327
- ) {
14328
- if (path in cache) {
14329
- return cache[path]
14330
- }
14331
-
14332
- if (!slices) {
14333
- // path/to/a.js
14334
- // ['path', 'to', 'a.js']
14335
- slices = path.split(SLASH).filter(Boolean);
14336
- }
14337
-
14338
- slices.pop();
14339
-
14340
- // If the path has no parent directory, just test it
14341
- if (!slices.length) {
14342
- return cache[path] = this._rules.test(path, checkUnignored, MODE_IGNORE)
14343
- }
14344
-
14345
- const parent = this._t(
14346
- slices.join(SLASH) + SLASH,
14347
- cache,
14348
- checkUnignored,
14349
- slices
14350
- );
14351
-
14352
- // If the path contains a parent directory, check the parent first
14353
- return cache[path] = parent.ignored
14354
- // > It is not possible to re-include a file if a parent directory of
14355
- // > that file is excluded.
14356
- ? parent
14357
- : this._rules.test(path, checkUnignored, MODE_IGNORE)
14358
- }
14359
-
14360
- ignores (path) {
14361
- return this._test(path, this._ignoreCache, false).ignored
14362
- }
14363
-
14364
- createFilter () {
14365
- return path => !this.ignores(path)
14366
- }
14367
-
14368
- filter (paths) {
14369
- return makeArray(paths).filter(this.createFilter())
14370
- }
14371
-
14372
- // @returns {TestResult}
14373
- test (path) {
14374
- return this._test(path, this._testCache, true)
14375
- }
14376
- }
14377
-
14378
- const factory = options => new Ignore(options);
14379
-
14380
- const isPathValid = path =>
14381
- checkPath(path && checkPath.convert(path), path, RETURN_FALSE);
14382
-
14383
- factory.isPathValid = isPathValid;
14384
-
14385
-
14386
- // Windows
14387
- // --------------------------------------------------------------
14388
- /* istanbul ignore next */
14389
- if (
14390
- // Detect `process` so that it can run in browsers.
14391
- typeof process !== 'undefined'
14392
- && (
14393
- process.env && process.env.IGNORE_TEST_WIN32
14394
- || process.platform === 'win32'
14395
- )
14396
- ) {
14397
- /* eslint no-control-regex: "off" */
14398
- const makePosix = str => /^\\\\\?\\/.test(str)
14399
- || /["<>|\u0000-\u001F]+/u.test(str)
14400
- ? str
14401
- : str.replace(/\\/g, '/');
14402
-
14403
- checkPath.convert = makePosix;
14404
-
14405
- // 'C:\\foo' <- 'C:\\foo' has been converted to 'C:/'
14406
- // 'd:\\foo'
14407
- const REGEX_TEST_WINDOWS_PATH_ABSOLUTE = /^[a-z]:\//i;
14408
- checkPath.isNotRelative = path =>
14409
- REGEX_TEST_WINDOWS_PATH_ABSOLUTE.test(path)
14410
- || isNotRelative(path);
14411
- }
14412
-
14413
14447
  var workerPath = "./jest-worker.js";
14414
14448
 
14415
14449
  exports.Attribute = Attribute;
@@ -14449,10 +14483,12 @@ exports.compatibilityCheckImpl = compatibilityCheckImpl;
14449
14483
  exports.deepmerge = deepmerge;
14450
14484
  exports.defineConfig = defineConfig;
14451
14485
  exports.definePlugin = definePlugin;
14486
+ exports.engines = engines;
14452
14487
  exports.ensureError = ensureError;
14453
- exports.factory = factory;
14454
14488
  exports.getFormatter = getFormatter;
14489
+ exports.ignore = ignore;
14455
14490
  exports.isThenable = isThenable;
14491
+ exports.isUserError = isUserError;
14456
14492
  exports.keywordPatternMatcher = keywordPatternMatcher;
14457
14493
  exports.name = name;
14458
14494
  exports.presets = presets;