html-validate 9.1.3 → 9.2.1

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