html-validate 9.5.4 → 9.6.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/es/core.js CHANGED
@@ -11720,7 +11720,7 @@ class EventHandler {
11720
11720
  }
11721
11721
 
11722
11722
  const name = "html-validate";
11723
- const version = "9.5.4";
11723
+ const version = "9.6.0";
11724
11724
  const bugs = "https://gitlab.com/html-validate/html-validate/issues/new";
11725
11725
 
11726
11726
  function freeze(src) {
@@ -13324,785 +13324,792 @@ var hasRequiredIgnore;
13324
13324
  function requireIgnore () {
13325
13325
  if (hasRequiredIgnore) return ignore$1.exports;
13326
13326
  hasRequiredIgnore = 1;
13327
- // A simple implementation of make-array
13328
- function makeArray (subject) {
13329
- return Array.isArray(subject)
13330
- ? subject
13331
- : [subject]
13332
- }
13333
-
13334
- const UNDEFINED = undefined;
13335
- const EMPTY = '';
13336
- const SPACE = ' ';
13337
- const ESCAPE = '\\';
13338
- const REGEX_TEST_BLANK_LINE = /^\s+$/;
13339
- const REGEX_INVALID_TRAILING_BACKSLASH = /(?:[^\\]|^)\\$/;
13340
- const REGEX_REPLACE_LEADING_EXCAPED_EXCLAMATION = /^\\!/;
13341
- const REGEX_REPLACE_LEADING_EXCAPED_HASH = /^\\#/;
13342
- const REGEX_SPLITALL_CRLF = /\r?\n/g;
13343
-
13344
- // Invalid:
13345
- // - /foo,
13346
- // - ./foo,
13347
- // - ../foo,
13348
- // - .
13349
- // - ..
13350
- // Valid:
13351
- // - .foo
13352
- const REGEX_TEST_INVALID_PATH = /^\.{0,2}\/|^\.{1,2}$/;
13353
-
13354
- const REGEX_TEST_TRAILING_SLASH = /\/$/;
13355
-
13356
- const SLASH = '/';
13357
-
13358
- // Do not use ternary expression here, since "istanbul ignore next" is buggy
13359
- let TMP_KEY_IGNORE = 'node-ignore';
13360
- /* istanbul ignore else */
13361
- if (typeof Symbol !== 'undefined') {
13362
- TMP_KEY_IGNORE = Symbol.for('node-ignore');
13363
- }
13364
- const KEY_IGNORE = TMP_KEY_IGNORE;
13365
-
13366
- const define = (object, key, value) => {
13367
- Object.defineProperty(object, key, {value});
13368
- return value
13369
- };
13370
-
13371
- const REGEX_REGEXP_RANGE = /([0-z])-([0-z])/g;
13372
-
13373
- const RETURN_FALSE = () => false;
13374
-
13375
- // Sanitize the range of a regular expression
13376
- // The cases are complicated, see test cases for details
13377
- const sanitizeRange = range => range.replace(
13378
- REGEX_REGEXP_RANGE,
13379
- (match, from, to) => from.charCodeAt(0) <= to.charCodeAt(0)
13380
- ? match
13381
- // Invalid range (out of order) which is ok for gitignore rules but
13382
- // fatal for JavaScript regular expression, so eliminate it.
13383
- : EMPTY
13384
- );
13385
-
13386
- // See fixtures #59
13387
- const cleanRangeBackSlash = slashes => {
13388
- const {length} = slashes;
13389
- return slashes.slice(0, length - length % 2)
13390
- };
13391
-
13392
- // > If the pattern ends with a slash,
13393
- // > it is removed for the purpose of the following description,
13394
- // > but it would only find a match with a directory.
13395
- // > In other words, foo/ will match a directory foo and paths underneath it,
13396
- // > but will not match a regular file or a symbolic link foo
13397
- // > (this is consistent with the way how pathspec works in general in Git).
13398
- // '`foo/`' will not match regular file '`foo`' or symbolic link '`foo`'
13399
- // -> ignore-rules will not deal with it, because it costs extra `fs.stat` call
13400
- // you could use option `mark: true` with `glob`
13401
-
13402
- // '`foo/`' should not continue with the '`..`'
13403
- const REPLACERS = [
13404
-
13405
- [
13406
- // Remove BOM
13407
- // TODO:
13408
- // Other similar zero-width characters?
13409
- /^\uFEFF/,
13410
- () => EMPTY
13411
- ],
13412
-
13413
- // > Trailing spaces are ignored unless they are quoted with backslash ("\")
13414
- [
13415
- // (a\ ) -> (a )
13416
- // (a ) -> (a)
13417
- // (a ) -> (a)
13418
- // (a \ ) -> (a )
13419
- /((?:\\\\)*?)(\\?\s+)$/,
13420
- (_, m1, m2) => m1 + (
13421
- m2.indexOf('\\') === 0
13422
- ? SPACE
13423
- : EMPTY
13424
- )
13425
- ],
13426
-
13427
- // Replace (\ ) with ' '
13428
- // (\ ) -> ' '
13429
- // (\\ ) -> '\\ '
13430
- // (\\\ ) -> '\\ '
13431
- [
13432
- /(\\+?)\s/g,
13433
- (_, m1) => {
13434
- const {length} = m1;
13435
- return m1.slice(0, length - length % 2) + SPACE
13436
- }
13437
- ],
13438
-
13439
- // Escape metacharacters
13440
- // which is written down by users but means special for regular expressions.
13441
-
13442
- // > There are 12 characters with special meanings:
13443
- // > - the backslash \,
13444
- // > - the caret ^,
13445
- // > - the dollar sign $,
13446
- // > - the period or dot .,
13447
- // > - the vertical bar or pipe symbol |,
13448
- // > - the question mark ?,
13449
- // > - the asterisk or star *,
13450
- // > - the plus sign +,
13451
- // > - the opening parenthesis (,
13452
- // > - the closing parenthesis ),
13453
- // > - and the opening square bracket [,
13454
- // > - the opening curly brace {,
13455
- // > These special characters are often called "metacharacters".
13456
- [
13457
- /[\\$.|*+(){^]/g,
13458
- match => `\\${match}`
13459
- ],
13460
-
13461
- [
13462
- // > a question mark (?) matches a single character
13463
- /(?!\\)\?/g,
13464
- () => '[^/]'
13465
- ],
13466
-
13467
- // leading slash
13468
- [
13469
-
13470
- // > A leading slash matches the beginning of the pathname.
13471
- // > For example, "/*.c" matches "cat-file.c" but not "mozilla-sha1/sha1.c".
13472
- // A leading slash matches the beginning of the pathname
13473
- /^\//,
13474
- () => '^'
13475
- ],
13476
-
13477
- // replace special metacharacter slash after the leading slash
13478
- [
13479
- /\//g,
13480
- () => '\\/'
13481
- ],
13482
-
13483
- [
13484
- // > A leading "**" followed by a slash means match in all directories.
13485
- // > For example, "**/foo" matches file or directory "foo" anywhere,
13486
- // > the same as pattern "foo".
13487
- // > "**/foo/bar" matches file or directory "bar" anywhere that is directly
13488
- // > under directory "foo".
13489
- // Notice that the '*'s have been replaced as '\\*'
13490
- /^\^*\\\*\\\*\\\//,
13491
-
13492
- // '**/foo' <-> 'foo'
13493
- () => '^(?:.*\\/)?'
13494
- ],
13495
-
13496
- // starting
13497
- [
13498
- // there will be no leading '/'
13499
- // (which has been replaced by section "leading slash")
13500
- // If starts with '**', adding a '^' to the regular expression also works
13501
- /^(?=[^^])/,
13502
- function startingReplacer () {
13503
- // If has a slash `/` at the beginning or middle
13504
- return !/\/(?!$)/.test(this)
13505
- // > Prior to 2.22.1
13506
- // > If the pattern does not contain a slash /,
13507
- // > Git treats it as a shell glob pattern
13508
- // Actually, if there is only a trailing slash,
13509
- // git also treats it as a shell glob pattern
13510
-
13511
- // After 2.22.1 (compatible but clearer)
13512
- // > If there is a separator at the beginning or middle (or both)
13513
- // > of the pattern, then the pattern is relative to the directory
13514
- // > level of the particular .gitignore file itself.
13515
- // > Otherwise the pattern may also match at any level below
13516
- // > the .gitignore level.
13517
- ? '(?:^|\\/)'
13518
-
13519
- // > Otherwise, Git treats the pattern as a shell glob suitable for
13520
- // > consumption by fnmatch(3)
13521
- : '^'
13522
- }
13523
- ],
13524
-
13525
- // two globstars
13526
- [
13527
- // Use lookahead assertions so that we could match more than one `'/**'`
13528
- /\\\/\\\*\\\*(?=\\\/|$)/g,
13529
-
13530
- // Zero, one or several directories
13531
- // should not use '*', or it will be replaced by the next replacer
13532
-
13533
- // Check if it is not the last `'/**'`
13534
- (_, index, str) => index + 6 < str.length
13535
-
13536
- // case: /**/
13537
- // > A slash followed by two consecutive asterisks then a slash matches
13538
- // > zero or more directories.
13539
- // > For example, "a/**/b" matches "a/b", "a/x/b", "a/x/y/b" and so on.
13540
- // '/**/'
13541
- ? '(?:\\/[^\\/]+)*'
13542
-
13543
- // case: /**
13544
- // > A trailing `"/**"` matches everything inside.
13545
-
13546
- // #21: everything inside but it should not include the current folder
13547
- : '\\/.+'
13548
- ],
13549
-
13550
- // normal intermediate wildcards
13551
- [
13552
- // Never replace escaped '*'
13553
- // ignore rule '\*' will match the path '*'
13554
-
13555
- // 'abc.*/' -> go
13556
- // 'abc.*' -> skip this rule,
13557
- // coz trailing single wildcard will be handed by [trailing wildcard]
13558
- /(^|[^\\]+)(\\\*)+(?=.+)/g,
13559
-
13560
- // '*.js' matches '.js'
13561
- // '*.js' doesn't match 'abc'
13562
- (_, p1, p2) => {
13563
- // 1.
13564
- // > An asterisk "*" matches anything except a slash.
13565
- // 2.
13566
- // > Other consecutive asterisks are considered regular asterisks
13567
- // > and will match according to the previous rules.
13568
- const unescaped = p2.replace(/\\\*/g, '[^\\/]*');
13569
- return p1 + unescaped
13570
- }
13571
- ],
13572
-
13573
- [
13574
- // unescape, revert step 3 except for back slash
13575
- // For example, if a user escape a '\\*',
13576
- // after step 3, the result will be '\\\\\\*'
13577
- /\\\\\\(?=[$.|*+(){^])/g,
13578
- () => ESCAPE
13579
- ],
13580
-
13581
- [
13582
- // '\\\\' -> '\\'
13583
- /\\\\/g,
13584
- () => ESCAPE
13585
- ],
13586
-
13587
- [
13588
- // > The range notation, e.g. [a-zA-Z],
13589
- // > can be used to match one of the characters in a range.
13590
-
13591
- // `\` is escaped by step 3
13592
- /(\\)?\[([^\]/]*?)(\\*)($|\])/g,
13593
- (match, leadEscape, range, endEscape, close) => leadEscape === ESCAPE
13594
- // '\\[bar]' -> '\\\\[bar\\]'
13595
- ? `\\[${range}${cleanRangeBackSlash(endEscape)}${close}`
13596
- : close === ']'
13597
- ? endEscape.length % 2 === 0
13598
- // A normal case, and it is a range notation
13599
- // '[bar]'
13600
- // '[bar\\\\]'
13601
- ? `[${sanitizeRange(range)}${endEscape}]`
13602
- // Invalid range notaton
13603
- // '[bar\\]' -> '[bar\\\\]'
13604
- : '[]'
13605
- : '[]'
13606
- ],
13607
-
13608
- // ending
13609
- [
13610
- // 'js' will not match 'js.'
13611
- // 'ab' will not match 'abc'
13612
- /(?:[^*])$/,
13613
-
13614
- // WTF!
13615
- // https://git-scm.com/docs/gitignore
13616
- // changes in [2.22.1](https://git-scm.com/docs/gitignore/2.22.1)
13617
- // which re-fixes #24, #38
13618
-
13619
- // > If there is a separator at the end of the pattern then the pattern
13620
- // > will only match directories, otherwise the pattern can match both
13621
- // > files and directories.
13622
-
13623
- // 'js*' will not match 'a.js'
13624
- // 'js/' will not match 'a.js'
13625
- // 'js' will match 'a.js' and 'a.js/'
13626
- match => /\/$/.test(match)
13627
- // foo/ will not match 'foo'
13628
- ? `${match}$`
13629
- // foo matches 'foo' and 'foo/'
13630
- : `${match}(?=$|\\/$)`
13631
- ]
13632
- ];
13633
-
13634
- const REGEX_REPLACE_TRAILING_WILDCARD = /(^|\\\/)?\\\*$/;
13635
- const MODE_IGNORE = 'regex';
13636
- const MODE_CHECK_IGNORE = 'checkRegex';
13637
- const UNDERSCORE = '_';
13638
-
13639
- const TRAILING_WILD_CARD_REPLACERS = {
13640
- [MODE_IGNORE] (_, p1) {
13641
- const prefix = p1
13642
- // '\^':
13643
- // '/*' does not match EMPTY
13644
- // '/*' does not match everything
13645
-
13646
- // '\\\/':
13647
- // 'abc/*' does not match 'abc/'
13648
- ? `${p1}[^/]+`
13649
-
13650
- // 'a*' matches 'a'
13651
- // 'a*' matches 'aa'
13652
- : '[^/]*';
13653
-
13654
- return `${prefix}(?=$|\\/$)`
13655
- },
13656
-
13657
- [MODE_CHECK_IGNORE] (_, p1) {
13658
- // When doing `git check-ignore`
13659
- const prefix = p1
13660
- // '\\\/':
13661
- // 'abc/*' DOES match 'abc/' !
13662
- ? `${p1}[^/]*`
13663
-
13664
- // 'a*' matches 'a'
13665
- // 'a*' matches 'aa'
13666
- : '[^/]*';
13667
-
13668
- return `${prefix}(?=$|\\/$)`
13669
- }
13670
- };
13671
-
13672
- // @param {pattern}
13673
- const makeRegexPrefix = pattern => REPLACERS.reduce(
13674
- (prev, [matcher, replacer]) =>
13675
- prev.replace(matcher, replacer.bind(pattern)),
13676
- pattern
13677
- );
13678
-
13679
- const isString = subject => typeof subject === 'string';
13680
-
13681
- // > A blank line matches no files, so it can serve as a separator for readability.
13682
- const checkPattern = pattern => pattern
13683
- && isString(pattern)
13684
- && !REGEX_TEST_BLANK_LINE.test(pattern)
13685
- && !REGEX_INVALID_TRAILING_BACKSLASH.test(pattern)
13686
-
13687
- // > A line starting with # serves as a comment.
13688
- && pattern.indexOf('#') !== 0;
13689
-
13690
- const splitPattern = pattern => pattern
13691
- .split(REGEX_SPLITALL_CRLF)
13692
- .filter(Boolean);
13693
-
13694
- class IgnoreRule {
13695
- constructor (
13696
- pattern,
13697
- mark,
13698
- body,
13699
- ignoreCase,
13700
- negative,
13701
- prefix
13702
- ) {
13703
- this.pattern = pattern;
13704
- this.mark = mark;
13705
- this.negative = negative;
13706
-
13707
- define(this, 'body', body);
13708
- define(this, 'ignoreCase', ignoreCase);
13709
- define(this, 'regexPrefix', prefix);
13710
- }
13711
-
13712
- get regex () {
13713
- const key = UNDERSCORE + MODE_IGNORE;
13714
-
13715
- if (this[key]) {
13716
- return this[key]
13717
- }
13718
-
13719
- return this._make(MODE_IGNORE, key)
13720
- }
13721
-
13722
- get checkRegex () {
13723
- const key = UNDERSCORE + MODE_CHECK_IGNORE;
13724
-
13725
- if (this[key]) {
13726
- return this[key]
13727
- }
13728
-
13729
- return this._make(MODE_CHECK_IGNORE, key)
13730
- }
13731
-
13732
- _make (mode, key) {
13733
- const str = this.regexPrefix.replace(
13734
- REGEX_REPLACE_TRAILING_WILDCARD,
13735
-
13736
- // It does not need to bind pattern
13737
- TRAILING_WILD_CARD_REPLACERS[mode]
13738
- );
13739
-
13740
- const regex = this.ignoreCase
13741
- ? new RegExp(str, 'i')
13742
- : new RegExp(str);
13743
-
13744
- return define(this, key, regex)
13745
- }
13746
- }
13747
-
13748
- const createRule = ({
13749
- pattern,
13750
- mark
13751
- }, ignoreCase) => {
13752
- let negative = false;
13753
- let body = pattern;
13754
-
13755
- // > An optional prefix "!" which negates the pattern;
13756
- if (body.indexOf('!') === 0) {
13757
- negative = true;
13758
- body = body.substr(1);
13759
- }
13760
-
13761
- body = body
13762
- // > Put a backslash ("\") in front of the first "!" for patterns that
13763
- // > begin with a literal "!", for example, `"\!important!.txt"`.
13764
- .replace(REGEX_REPLACE_LEADING_EXCAPED_EXCLAMATION, '!')
13765
- // > Put a backslash ("\") in front of the first hash for patterns that
13766
- // > begin with a hash.
13767
- .replace(REGEX_REPLACE_LEADING_EXCAPED_HASH, '#');
13768
-
13769
- const regexPrefix = makeRegexPrefix(body);
13770
-
13771
- return new IgnoreRule(
13772
- pattern,
13773
- mark,
13774
- body,
13775
- ignoreCase,
13776
- negative,
13777
- regexPrefix
13778
- )
13779
- };
13327
+ (function (module) {
13328
+ // A simple implementation of make-array
13329
+ function makeArray (subject) {
13330
+ return Array.isArray(subject)
13331
+ ? subject
13332
+ : [subject]
13333
+ }
13780
13334
 
13781
- class RuleManager {
13782
- constructor (ignoreCase) {
13783
- this._ignoreCase = ignoreCase;
13784
- this._rules = [];
13785
- }
13786
-
13787
- _add (pattern) {
13788
- // #32
13789
- if (pattern && pattern[KEY_IGNORE]) {
13790
- this._rules = this._rules.concat(pattern._rules._rules);
13791
- this._added = true;
13792
- return
13793
- }
13794
-
13795
- if (isString(pattern)) {
13796
- pattern = {
13797
- pattern
13798
- };
13799
- }
13800
-
13801
- if (checkPattern(pattern.pattern)) {
13802
- const rule = createRule(pattern, this._ignoreCase);
13803
- this._added = true;
13804
- this._rules.push(rule);
13805
- }
13806
- }
13807
-
13808
- // @param {Array<string> | string | Ignore} pattern
13809
- add (pattern) {
13810
- this._added = false;
13811
-
13812
- makeArray(
13813
- isString(pattern)
13814
- ? splitPattern(pattern)
13815
- : pattern
13816
- ).forEach(this._add, this);
13817
-
13818
- return this._added
13819
- }
13820
-
13821
- // Test one single path without recursively checking parent directories
13822
- //
13823
- // - checkUnignored `boolean` whether should check if the path is unignored,
13824
- // setting `checkUnignored` to `false` could reduce additional
13825
- // path matching.
13826
- // - check `string` either `MODE_IGNORE` or `MODE_CHECK_IGNORE`
13827
-
13828
- // @returns {TestResult} true if a file is ignored
13829
- test (path, checkUnignored, mode) {
13830
- let ignored = false;
13831
- let unignored = false;
13832
- let matchedRule;
13833
-
13834
- this._rules.forEach(rule => {
13835
- const {negative} = rule;
13836
-
13837
- // | ignored : unignored
13838
- // -------- | ---------------------------------------
13839
- // negative | 0:0 | 0:1 | 1:0 | 1:1
13840
- // -------- | ------- | ------- | ------- | --------
13841
- // 0 | TEST | TEST | SKIP | X
13842
- // 1 | TESTIF | SKIP | TEST | X
13843
-
13844
- // - SKIP: always skip
13845
- // - TEST: always test
13846
- // - TESTIF: only test if checkUnignored
13847
- // - X: that never happen
13848
- if (
13849
- unignored === negative && ignored !== unignored
13850
- || negative && !ignored && !unignored && !checkUnignored
13851
- ) {
13852
- return
13853
- }
13854
-
13855
- const matched = rule[mode].test(path);
13856
-
13857
- if (!matched) {
13858
- return
13859
- }
13860
-
13861
- ignored = !negative;
13862
- unignored = negative;
13863
-
13864
- matchedRule = negative
13865
- ? UNDEFINED
13866
- : rule;
13867
- });
13868
-
13869
- const ret = {
13870
- ignored,
13871
- unignored
13872
- };
13873
-
13874
- if (matchedRule) {
13875
- ret.rule = matchedRule;
13876
- }
13877
-
13878
- return ret
13879
- }
13880
- }
13335
+ const UNDEFINED = undefined;
13336
+ const EMPTY = '';
13337
+ const SPACE = ' ';
13338
+ const ESCAPE = '\\';
13339
+ const REGEX_TEST_BLANK_LINE = /^\s+$/;
13340
+ const REGEX_INVALID_TRAILING_BACKSLASH = /(?:[^\\]|^)\\$/;
13341
+ const REGEX_REPLACE_LEADING_EXCAPED_EXCLAMATION = /^\\!/;
13342
+ const REGEX_REPLACE_LEADING_EXCAPED_HASH = /^\\#/;
13343
+ const REGEX_SPLITALL_CRLF = /\r?\n/g;
13344
+
13345
+ // Invalid:
13346
+ // - /foo,
13347
+ // - ./foo,
13348
+ // - ../foo,
13349
+ // - .
13350
+ // - ..
13351
+ // Valid:
13352
+ // - .foo
13353
+ const REGEX_TEST_INVALID_PATH = /^\.{0,2}\/|^\.{1,2}$/;
13354
+
13355
+ const REGEX_TEST_TRAILING_SLASH = /\/$/;
13356
+
13357
+ const SLASH = '/';
13358
+
13359
+ // Do not use ternary expression here, since "istanbul ignore next" is buggy
13360
+ let TMP_KEY_IGNORE = 'node-ignore';
13361
+ /* istanbul ignore else */
13362
+ if (typeof Symbol !== 'undefined') {
13363
+ TMP_KEY_IGNORE = Symbol.for('node-ignore');
13364
+ }
13365
+ const KEY_IGNORE = TMP_KEY_IGNORE;
13366
+
13367
+ const define = (object, key, value) => {
13368
+ Object.defineProperty(object, key, {value});
13369
+ return value
13370
+ };
13371
+
13372
+ const REGEX_REGEXP_RANGE = /([0-z])-([0-z])/g;
13373
+
13374
+ const RETURN_FALSE = () => false;
13375
+
13376
+ // Sanitize the range of a regular expression
13377
+ // The cases are complicated, see test cases for details
13378
+ const sanitizeRange = range => range.replace(
13379
+ REGEX_REGEXP_RANGE,
13380
+ (match, from, to) => from.charCodeAt(0) <= to.charCodeAt(0)
13381
+ ? match
13382
+ // Invalid range (out of order) which is ok for gitignore rules but
13383
+ // fatal for JavaScript regular expression, so eliminate it.
13384
+ : EMPTY
13385
+ );
13386
+
13387
+ // See fixtures #59
13388
+ const cleanRangeBackSlash = slashes => {
13389
+ const {length} = slashes;
13390
+ return slashes.slice(0, length - length % 2)
13391
+ };
13392
+
13393
+ // > If the pattern ends with a slash,
13394
+ // > it is removed for the purpose of the following description,
13395
+ // > but it would only find a match with a directory.
13396
+ // > In other words, foo/ will match a directory foo and paths underneath it,
13397
+ // > but will not match a regular file or a symbolic link foo
13398
+ // > (this is consistent with the way how pathspec works in general in Git).
13399
+ // '`foo/`' will not match regular file '`foo`' or symbolic link '`foo`'
13400
+ // -> ignore-rules will not deal with it, because it costs extra `fs.stat` call
13401
+ // you could use option `mark: true` with `glob`
13402
+
13403
+ // '`foo/`' should not continue with the '`..`'
13404
+ const REPLACERS = [
13405
+
13406
+ [
13407
+ // Remove BOM
13408
+ // TODO:
13409
+ // Other similar zero-width characters?
13410
+ /^\uFEFF/,
13411
+ () => EMPTY
13412
+ ],
13413
+
13414
+ // > Trailing spaces are ignored unless they are quoted with backslash ("\")
13415
+ [
13416
+ // (a\ ) -> (a )
13417
+ // (a ) -> (a)
13418
+ // (a ) -> (a)
13419
+ // (a \ ) -> (a )
13420
+ /((?:\\\\)*?)(\\?\s+)$/,
13421
+ (_, m1, m2) => m1 + (
13422
+ m2.indexOf('\\') === 0
13423
+ ? SPACE
13424
+ : EMPTY
13425
+ )
13426
+ ],
13427
+
13428
+ // Replace (\ ) with ' '
13429
+ // (\ ) -> ' '
13430
+ // (\\ ) -> '\\ '
13431
+ // (\\\ ) -> '\\ '
13432
+ [
13433
+ /(\\+?)\s/g,
13434
+ (_, m1) => {
13435
+ const {length} = m1;
13436
+ return m1.slice(0, length - length % 2) + SPACE
13437
+ }
13438
+ ],
13439
+
13440
+ // Escape metacharacters
13441
+ // which is written down by users but means special for regular expressions.
13442
+
13443
+ // > There are 12 characters with special meanings:
13444
+ // > - the backslash \,
13445
+ // > - the caret ^,
13446
+ // > - the dollar sign $,
13447
+ // > - the period or dot .,
13448
+ // > - the vertical bar or pipe symbol |,
13449
+ // > - the question mark ?,
13450
+ // > - the asterisk or star *,
13451
+ // > - the plus sign +,
13452
+ // > - the opening parenthesis (,
13453
+ // > - the closing parenthesis ),
13454
+ // > - and the opening square bracket [,
13455
+ // > - the opening curly brace {,
13456
+ // > These special characters are often called "metacharacters".
13457
+ [
13458
+ /[\\$.|*+(){^]/g,
13459
+ match => `\\${match}`
13460
+ ],
13461
+
13462
+ [
13463
+ // > a question mark (?) matches a single character
13464
+ /(?!\\)\?/g,
13465
+ () => '[^/]'
13466
+ ],
13467
+
13468
+ // leading slash
13469
+ [
13470
+
13471
+ // > A leading slash matches the beginning of the pathname.
13472
+ // > For example, "/*.c" matches "cat-file.c" but not "mozilla-sha1/sha1.c".
13473
+ // A leading slash matches the beginning of the pathname
13474
+ /^\//,
13475
+ () => '^'
13476
+ ],
13477
+
13478
+ // replace special metacharacter slash after the leading slash
13479
+ [
13480
+ /\//g,
13481
+ () => '\\/'
13482
+ ],
13483
+
13484
+ [
13485
+ // > A leading "**" followed by a slash means match in all directories.
13486
+ // > For example, "**/foo" matches file or directory "foo" anywhere,
13487
+ // > the same as pattern "foo".
13488
+ // > "**/foo/bar" matches file or directory "bar" anywhere that is directly
13489
+ // > under directory "foo".
13490
+ // Notice that the '*'s have been replaced as '\\*'
13491
+ /^\^*\\\*\\\*\\\//,
13492
+
13493
+ // '**/foo' <-> 'foo'
13494
+ () => '^(?:.*\\/)?'
13495
+ ],
13496
+
13497
+ // starting
13498
+ [
13499
+ // there will be no leading '/'
13500
+ // (which has been replaced by section "leading slash")
13501
+ // If starts with '**', adding a '^' to the regular expression also works
13502
+ /^(?=[^^])/,
13503
+ function startingReplacer () {
13504
+ // If has a slash `/` at the beginning or middle
13505
+ return !/\/(?!$)/.test(this)
13506
+ // > Prior to 2.22.1
13507
+ // > If the pattern does not contain a slash /,
13508
+ // > Git treats it as a shell glob pattern
13509
+ // Actually, if there is only a trailing slash,
13510
+ // git also treats it as a shell glob pattern
13511
+
13512
+ // After 2.22.1 (compatible but clearer)
13513
+ // > If there is a separator at the beginning or middle (or both)
13514
+ // > of the pattern, then the pattern is relative to the directory
13515
+ // > level of the particular .gitignore file itself.
13516
+ // > Otherwise the pattern may also match at any level below
13517
+ // > the .gitignore level.
13518
+ ? '(?:^|\\/)'
13519
+
13520
+ // > Otherwise, Git treats the pattern as a shell glob suitable for
13521
+ // > consumption by fnmatch(3)
13522
+ : '^'
13523
+ }
13524
+ ],
13525
+
13526
+ // two globstars
13527
+ [
13528
+ // Use lookahead assertions so that we could match more than one `'/**'`
13529
+ /\\\/\\\*\\\*(?=\\\/|$)/g,
13530
+
13531
+ // Zero, one or several directories
13532
+ // should not use '*', or it will be replaced by the next replacer
13533
+
13534
+ // Check if it is not the last `'/**'`
13535
+ (_, index, str) => index + 6 < str.length
13536
+
13537
+ // case: /**/
13538
+ // > A slash followed by two consecutive asterisks then a slash matches
13539
+ // > zero or more directories.
13540
+ // > For example, "a/**/b" matches "a/b", "a/x/b", "a/x/y/b" and so on.
13541
+ // '/**/'
13542
+ ? '(?:\\/[^\\/]+)*'
13543
+
13544
+ // case: /**
13545
+ // > A trailing `"/**"` matches everything inside.
13546
+
13547
+ // #21: everything inside but it should not include the current folder
13548
+ : '\\/.+'
13549
+ ],
13550
+
13551
+ // normal intermediate wildcards
13552
+ [
13553
+ // Never replace escaped '*'
13554
+ // ignore rule '\*' will match the path '*'
13555
+
13556
+ // 'abc.*/' -> go
13557
+ // 'abc.*' -> skip this rule,
13558
+ // coz trailing single wildcard will be handed by [trailing wildcard]
13559
+ /(^|[^\\]+)(\\\*)+(?=.+)/g,
13560
+
13561
+ // '*.js' matches '.js'
13562
+ // '*.js' doesn't match 'abc'
13563
+ (_, p1, p2) => {
13564
+ // 1.
13565
+ // > An asterisk "*" matches anything except a slash.
13566
+ // 2.
13567
+ // > Other consecutive asterisks are considered regular asterisks
13568
+ // > and will match according to the previous rules.
13569
+ const unescaped = p2.replace(/\\\*/g, '[^\\/]*');
13570
+ return p1 + unescaped
13571
+ }
13572
+ ],
13573
+
13574
+ [
13575
+ // unescape, revert step 3 except for back slash
13576
+ // For example, if a user escape a '\\*',
13577
+ // after step 3, the result will be '\\\\\\*'
13578
+ /\\\\\\(?=[$.|*+(){^])/g,
13579
+ () => ESCAPE
13580
+ ],
13581
+
13582
+ [
13583
+ // '\\\\' -> '\\'
13584
+ /\\\\/g,
13585
+ () => ESCAPE
13586
+ ],
13587
+
13588
+ [
13589
+ // > The range notation, e.g. [a-zA-Z],
13590
+ // > can be used to match one of the characters in a range.
13591
+
13592
+ // `\` is escaped by step 3
13593
+ /(\\)?\[([^\]/]*?)(\\*)($|\])/g,
13594
+ (match, leadEscape, range, endEscape, close) => leadEscape === ESCAPE
13595
+ // '\\[bar]' -> '\\\\[bar\\]'
13596
+ ? `\\[${range}${cleanRangeBackSlash(endEscape)}${close}`
13597
+ : close === ']'
13598
+ ? endEscape.length % 2 === 0
13599
+ // A normal case, and it is a range notation
13600
+ // '[bar]'
13601
+ // '[bar\\\\]'
13602
+ ? `[${sanitizeRange(range)}${endEscape}]`
13603
+ // Invalid range notaton
13604
+ // '[bar\\]' -> '[bar\\\\]'
13605
+ : '[]'
13606
+ : '[]'
13607
+ ],
13608
+
13609
+ // ending
13610
+ [
13611
+ // 'js' will not match 'js.'
13612
+ // 'ab' will not match 'abc'
13613
+ /(?:[^*])$/,
13614
+
13615
+ // WTF!
13616
+ // https://git-scm.com/docs/gitignore
13617
+ // changes in [2.22.1](https://git-scm.com/docs/gitignore/2.22.1)
13618
+ // which re-fixes #24, #38
13619
+
13620
+ // > If there is a separator at the end of the pattern then the pattern
13621
+ // > will only match directories, otherwise the pattern can match both
13622
+ // > files and directories.
13623
+
13624
+ // 'js*' will not match 'a.js'
13625
+ // 'js/' will not match 'a.js'
13626
+ // 'js' will match 'a.js' and 'a.js/'
13627
+ match => /\/$/.test(match)
13628
+ // foo/ will not match 'foo'
13629
+ ? `${match}$`
13630
+ // foo matches 'foo' and 'foo/'
13631
+ : `${match}(?=$|\\/$)`
13632
+ ]
13633
+ ];
13634
+
13635
+ const REGEX_REPLACE_TRAILING_WILDCARD = /(^|\\\/)?\\\*$/;
13636
+ const MODE_IGNORE = 'regex';
13637
+ const MODE_CHECK_IGNORE = 'checkRegex';
13638
+ const UNDERSCORE = '_';
13639
+
13640
+ const TRAILING_WILD_CARD_REPLACERS = {
13641
+ [MODE_IGNORE] (_, p1) {
13642
+ const prefix = p1
13643
+ // '\^':
13644
+ // '/*' does not match EMPTY
13645
+ // '/*' does not match everything
13646
+
13647
+ // '\\\/':
13648
+ // 'abc/*' does not match 'abc/'
13649
+ ? `${p1}[^/]+`
13650
+
13651
+ // 'a*' matches 'a'
13652
+ // 'a*' matches 'aa'
13653
+ : '[^/]*';
13654
+
13655
+ return `${prefix}(?=$|\\/$)`
13656
+ },
13657
+
13658
+ [MODE_CHECK_IGNORE] (_, p1) {
13659
+ // When doing `git check-ignore`
13660
+ const prefix = p1
13661
+ // '\\\/':
13662
+ // 'abc/*' DOES match 'abc/' !
13663
+ ? `${p1}[^/]*`
13664
+
13665
+ // 'a*' matches 'a'
13666
+ // 'a*' matches 'aa'
13667
+ : '[^/]*';
13668
+
13669
+ return `${prefix}(?=$|\\/$)`
13670
+ }
13671
+ };
13672
+
13673
+ // @param {pattern}
13674
+ const makeRegexPrefix = pattern => REPLACERS.reduce(
13675
+ (prev, [matcher, replacer]) =>
13676
+ prev.replace(matcher, replacer.bind(pattern)),
13677
+ pattern
13678
+ );
13679
+
13680
+ const isString = subject => typeof subject === 'string';
13681
+
13682
+ // > A blank line matches no files, so it can serve as a separator for readability.
13683
+ const checkPattern = pattern => pattern
13684
+ && isString(pattern)
13685
+ && !REGEX_TEST_BLANK_LINE.test(pattern)
13686
+ && !REGEX_INVALID_TRAILING_BACKSLASH.test(pattern)
13687
+
13688
+ // > A line starting with # serves as a comment.
13689
+ && pattern.indexOf('#') !== 0;
13690
+
13691
+ const splitPattern = pattern => pattern
13692
+ .split(REGEX_SPLITALL_CRLF)
13693
+ .filter(Boolean);
13694
+
13695
+ class IgnoreRule {
13696
+ constructor (
13697
+ pattern,
13698
+ mark,
13699
+ body,
13700
+ ignoreCase,
13701
+ negative,
13702
+ prefix
13703
+ ) {
13704
+ this.pattern = pattern;
13705
+ this.mark = mark;
13706
+ this.negative = negative;
13707
+
13708
+ define(this, 'body', body);
13709
+ define(this, 'ignoreCase', ignoreCase);
13710
+ define(this, 'regexPrefix', prefix);
13711
+ }
13712
+
13713
+ get regex () {
13714
+ const key = UNDERSCORE + MODE_IGNORE;
13715
+
13716
+ if (this[key]) {
13717
+ return this[key]
13718
+ }
13719
+
13720
+ return this._make(MODE_IGNORE, key)
13721
+ }
13722
+
13723
+ get checkRegex () {
13724
+ const key = UNDERSCORE + MODE_CHECK_IGNORE;
13725
+
13726
+ if (this[key]) {
13727
+ return this[key]
13728
+ }
13729
+
13730
+ return this._make(MODE_CHECK_IGNORE, key)
13731
+ }
13732
+
13733
+ _make (mode, key) {
13734
+ const str = this.regexPrefix.replace(
13735
+ REGEX_REPLACE_TRAILING_WILDCARD,
13736
+
13737
+ // It does not need to bind pattern
13738
+ TRAILING_WILD_CARD_REPLACERS[mode]
13739
+ );
13740
+
13741
+ const regex = this.ignoreCase
13742
+ ? new RegExp(str, 'i')
13743
+ : new RegExp(str);
13744
+
13745
+ return define(this, key, regex)
13746
+ }
13747
+ }
13881
13748
 
13882
- const throwError = (message, Ctor) => {
13883
- throw new Ctor(message)
13884
- };
13749
+ const createRule = ({
13750
+ pattern,
13751
+ mark
13752
+ }, ignoreCase) => {
13753
+ let negative = false;
13754
+ let body = pattern;
13755
+
13756
+ // > An optional prefix "!" which negates the pattern;
13757
+ if (body.indexOf('!') === 0) {
13758
+ negative = true;
13759
+ body = body.substr(1);
13760
+ }
13761
+
13762
+ body = body
13763
+ // > Put a backslash ("\") in front of the first "!" for patterns that
13764
+ // > begin with a literal "!", for example, `"\!important!.txt"`.
13765
+ .replace(REGEX_REPLACE_LEADING_EXCAPED_EXCLAMATION, '!')
13766
+ // > Put a backslash ("\") in front of the first hash for patterns that
13767
+ // > begin with a hash.
13768
+ .replace(REGEX_REPLACE_LEADING_EXCAPED_HASH, '#');
13769
+
13770
+ const regexPrefix = makeRegexPrefix(body);
13771
+
13772
+ return new IgnoreRule(
13773
+ pattern,
13774
+ mark,
13775
+ body,
13776
+ ignoreCase,
13777
+ negative,
13778
+ regexPrefix
13779
+ )
13780
+ };
13781
+
13782
+ class RuleManager {
13783
+ constructor (ignoreCase) {
13784
+ this._ignoreCase = ignoreCase;
13785
+ this._rules = [];
13786
+ }
13787
+
13788
+ _add (pattern) {
13789
+ // #32
13790
+ if (pattern && pattern[KEY_IGNORE]) {
13791
+ this._rules = this._rules.concat(pattern._rules._rules);
13792
+ this._added = true;
13793
+ return
13794
+ }
13795
+
13796
+ if (isString(pattern)) {
13797
+ pattern = {
13798
+ pattern
13799
+ };
13800
+ }
13801
+
13802
+ if (checkPattern(pattern.pattern)) {
13803
+ const rule = createRule(pattern, this._ignoreCase);
13804
+ this._added = true;
13805
+ this._rules.push(rule);
13806
+ }
13807
+ }
13808
+
13809
+ // @param {Array<string> | string | Ignore} pattern
13810
+ add (pattern) {
13811
+ this._added = false;
13812
+
13813
+ makeArray(
13814
+ isString(pattern)
13815
+ ? splitPattern(pattern)
13816
+ : pattern
13817
+ ).forEach(this._add, this);
13818
+
13819
+ return this._added
13820
+ }
13821
+
13822
+ // Test one single path without recursively checking parent directories
13823
+ //
13824
+ // - checkUnignored `boolean` whether should check if the path is unignored,
13825
+ // setting `checkUnignored` to `false` could reduce additional
13826
+ // path matching.
13827
+ // - check `string` either `MODE_IGNORE` or `MODE_CHECK_IGNORE`
13828
+
13829
+ // @returns {TestResult} true if a file is ignored
13830
+ test (path, checkUnignored, mode) {
13831
+ let ignored = false;
13832
+ let unignored = false;
13833
+ let matchedRule;
13834
+
13835
+ this._rules.forEach(rule => {
13836
+ const {negative} = rule;
13837
+
13838
+ // | ignored : unignored
13839
+ // -------- | ---------------------------------------
13840
+ // negative | 0:0 | 0:1 | 1:0 | 1:1
13841
+ // -------- | ------- | ------- | ------- | --------
13842
+ // 0 | TEST | TEST | SKIP | X
13843
+ // 1 | TESTIF | SKIP | TEST | X
13844
+
13845
+ // - SKIP: always skip
13846
+ // - TEST: always test
13847
+ // - TESTIF: only test if checkUnignored
13848
+ // - X: that never happen
13849
+ if (
13850
+ unignored === negative && ignored !== unignored
13851
+ || negative && !ignored && !unignored && !checkUnignored
13852
+ ) {
13853
+ return
13854
+ }
13855
+
13856
+ const matched = rule[mode].test(path);
13857
+
13858
+ if (!matched) {
13859
+ return
13860
+ }
13861
+
13862
+ ignored = !negative;
13863
+ unignored = negative;
13864
+
13865
+ matchedRule = negative
13866
+ ? UNDEFINED
13867
+ : rule;
13868
+ });
13869
+
13870
+ const ret = {
13871
+ ignored,
13872
+ unignored
13873
+ };
13874
+
13875
+ if (matchedRule) {
13876
+ ret.rule = matchedRule;
13877
+ }
13878
+
13879
+ return ret
13880
+ }
13881
+ }
13885
13882
 
13886
- const checkPath = (path, originalPath, doThrow) => {
13887
- if (!isString(path)) {
13888
- return doThrow(
13889
- `path must be a string, but got \`${originalPath}\``,
13890
- TypeError
13891
- )
13892
- }
13893
-
13894
- // We don't know if we should ignore EMPTY, so throw
13895
- if (!path) {
13896
- return doThrow(`path must not be empty`, TypeError)
13897
- }
13898
-
13899
- // Check if it is a relative path
13900
- if (checkPath.isNotRelative(path)) {
13901
- const r = '`path.relative()`d';
13902
- return doThrow(
13903
- `path should be a ${r} string, but got "${originalPath}"`,
13904
- RangeError
13905
- )
13906
- }
13907
-
13908
- return true
13909
- };
13883
+ const throwError = (message, Ctor) => {
13884
+ throw new Ctor(message)
13885
+ };
13886
+
13887
+ const checkPath = (path, originalPath, doThrow) => {
13888
+ if (!isString(path)) {
13889
+ return doThrow(
13890
+ `path must be a string, but got \`${originalPath}\``,
13891
+ TypeError
13892
+ )
13893
+ }
13894
+
13895
+ // We don't know if we should ignore EMPTY, so throw
13896
+ if (!path) {
13897
+ return doThrow(`path must not be empty`, TypeError)
13898
+ }
13899
+
13900
+ // Check if it is a relative path
13901
+ if (checkPath.isNotRelative(path)) {
13902
+ const r = '`path.relative()`d';
13903
+ return doThrow(
13904
+ `path should be a ${r} string, but got "${originalPath}"`,
13905
+ RangeError
13906
+ )
13907
+ }
13908
+
13909
+ return true
13910
+ };
13911
+
13912
+ const isNotRelative = path => REGEX_TEST_INVALID_PATH.test(path);
13913
+
13914
+ checkPath.isNotRelative = isNotRelative;
13915
+
13916
+ // On windows, the following function will be replaced
13917
+ /* istanbul ignore next */
13918
+ checkPath.convert = p => p;
13919
+
13920
+
13921
+ class Ignore {
13922
+ constructor ({
13923
+ ignorecase = true,
13924
+ ignoreCase = ignorecase,
13925
+ allowRelativePaths = false
13926
+ } = {}) {
13927
+ define(this, KEY_IGNORE, true);
13928
+
13929
+ this._rules = new RuleManager(ignoreCase);
13930
+ this._strictPathCheck = !allowRelativePaths;
13931
+ this._initCache();
13932
+ }
13933
+
13934
+ _initCache () {
13935
+ // A cache for the result of `.ignores()`
13936
+ this._ignoreCache = Object.create(null);
13937
+
13938
+ // A cache for the result of `.test()`
13939
+ this._testCache = Object.create(null);
13940
+ }
13941
+
13942
+ add (pattern) {
13943
+ if (this._rules.add(pattern)) {
13944
+ // Some rules have just added to the ignore,
13945
+ // making the behavior changed,
13946
+ // so we need to re-initialize the result cache
13947
+ this._initCache();
13948
+ }
13949
+
13950
+ return this
13951
+ }
13952
+
13953
+ // legacy
13954
+ addPattern (pattern) {
13955
+ return this.add(pattern)
13956
+ }
13957
+
13958
+ // @returns {TestResult}
13959
+ _test (originalPath, cache, checkUnignored, slices) {
13960
+ const path = originalPath
13961
+ // Supports nullable path
13962
+ && checkPath.convert(originalPath);
13963
+
13964
+ checkPath(
13965
+ path,
13966
+ originalPath,
13967
+ this._strictPathCheck
13968
+ ? throwError
13969
+ : RETURN_FALSE
13970
+ );
13971
+
13972
+ return this._t(path, cache, checkUnignored, slices)
13973
+ }
13974
+
13975
+ checkIgnore (path) {
13976
+ // If the path doest not end with a slash, `.ignores()` is much equivalent
13977
+ // to `git check-ignore`
13978
+ if (!REGEX_TEST_TRAILING_SLASH.test(path)) {
13979
+ return this.test(path)
13980
+ }
13981
+
13982
+ const slices = path.split(SLASH).filter(Boolean);
13983
+ slices.pop();
13984
+
13985
+ if (slices.length) {
13986
+ const parent = this._t(
13987
+ slices.join(SLASH) + SLASH,
13988
+ this._testCache,
13989
+ true,
13990
+ slices
13991
+ );
13992
+
13993
+ if (parent.ignored) {
13994
+ return parent
13995
+ }
13996
+ }
13997
+
13998
+ return this._rules.test(path, false, MODE_CHECK_IGNORE)
13999
+ }
14000
+
14001
+ _t (
14002
+ // The path to be tested
14003
+ path,
14004
+
14005
+ // The cache for the result of a certain checking
14006
+ cache,
14007
+
14008
+ // Whether should check if the path is unignored
14009
+ checkUnignored,
14010
+
14011
+ // The path slices
14012
+ slices
14013
+ ) {
14014
+ if (path in cache) {
14015
+ return cache[path]
14016
+ }
14017
+
14018
+ if (!slices) {
14019
+ // path/to/a.js
14020
+ // ['path', 'to', 'a.js']
14021
+ slices = path.split(SLASH).filter(Boolean);
14022
+ }
14023
+
14024
+ slices.pop();
14025
+
14026
+ // If the path has no parent directory, just test it
14027
+ if (!slices.length) {
14028
+ return cache[path] = this._rules.test(path, checkUnignored, MODE_IGNORE)
14029
+ }
14030
+
14031
+ const parent = this._t(
14032
+ slices.join(SLASH) + SLASH,
14033
+ cache,
14034
+ checkUnignored,
14035
+ slices
14036
+ );
14037
+
14038
+ // If the path contains a parent directory, check the parent first
14039
+ return cache[path] = parent.ignored
14040
+ // > It is not possible to re-include a file if a parent directory of
14041
+ // > that file is excluded.
14042
+ ? parent
14043
+ : this._rules.test(path, checkUnignored, MODE_IGNORE)
14044
+ }
14045
+
14046
+ ignores (path) {
14047
+ return this._test(path, this._ignoreCache, false).ignored
14048
+ }
14049
+
14050
+ createFilter () {
14051
+ return path => !this.ignores(path)
14052
+ }
14053
+
14054
+ filter (paths) {
14055
+ return makeArray(paths).filter(this.createFilter())
14056
+ }
14057
+
14058
+ // @returns {TestResult}
14059
+ test (path) {
14060
+ return this._test(path, this._testCache, true)
14061
+ }
14062
+ }
13910
14063
 
13911
- const isNotRelative = path => REGEX_TEST_INVALID_PATH.test(path);
13912
-
13913
- checkPath.isNotRelative = isNotRelative;
13914
-
13915
- // On windows, the following function will be replaced
13916
- /* istanbul ignore next */
13917
- checkPath.convert = p => p;
13918
-
13919
-
13920
- class Ignore {
13921
- constructor ({
13922
- ignorecase = true,
13923
- ignoreCase = ignorecase,
13924
- allowRelativePaths = false
13925
- } = {}) {
13926
- define(this, KEY_IGNORE, true);
13927
-
13928
- this._rules = new RuleManager(ignoreCase);
13929
- this._strictPathCheck = !allowRelativePaths;
13930
- this._initCache();
13931
- }
13932
-
13933
- _initCache () {
13934
- // A cache for the result of `.ignores()`
13935
- this._ignoreCache = Object.create(null);
13936
-
13937
- // A cache for the result of `.test()`
13938
- this._testCache = Object.create(null);
13939
- }
13940
-
13941
- add (pattern) {
13942
- if (this._rules.add(pattern)) {
13943
- // Some rules have just added to the ignore,
13944
- // making the behavior changed,
13945
- // so we need to re-initialize the result cache
13946
- this._initCache();
13947
- }
13948
-
13949
- return this
13950
- }
13951
-
13952
- // legacy
13953
- addPattern (pattern) {
13954
- return this.add(pattern)
13955
- }
13956
-
13957
- // @returns {TestResult}
13958
- _test (originalPath, cache, checkUnignored, slices) {
13959
- const path = originalPath
13960
- // Supports nullable path
13961
- && checkPath.convert(originalPath);
13962
-
13963
- checkPath(
13964
- path,
13965
- originalPath,
13966
- this._strictPathCheck
13967
- ? throwError
13968
- : RETURN_FALSE
13969
- );
13970
-
13971
- return this._t(path, cache, checkUnignored, slices)
13972
- }
13973
-
13974
- checkIgnore (path) {
13975
- // If the path doest not end with a slash, `.ignores()` is much equivalent
13976
- // to `git check-ignore`
13977
- if (!REGEX_TEST_TRAILING_SLASH.test(path)) {
13978
- return this.test(path)
13979
- }
13980
-
13981
- const slices = path.split(SLASH).filter(Boolean);
13982
- slices.pop();
13983
-
13984
- if (slices.length) {
13985
- const parent = this._t(
13986
- slices.join(SLASH) + SLASH,
13987
- this._testCache,
13988
- true,
13989
- slices
13990
- );
13991
-
13992
- if (parent.ignored) {
13993
- return parent
13994
- }
13995
- }
13996
-
13997
- return this._rules.test(path, false, MODE_CHECK_IGNORE)
13998
- }
13999
-
14000
- _t (
14001
- // The path to be tested
14002
- path,
14003
-
14004
- // The cache for the result of a certain checking
14005
- cache,
14006
-
14007
- // Whether should check if the path is unignored
14008
- checkUnignored,
14009
-
14010
- // The path slices
14011
- slices
14012
- ) {
14013
- if (path in cache) {
14014
- return cache[path]
14015
- }
14016
-
14017
- if (!slices) {
14018
- // path/to/a.js
14019
- // ['path', 'to', 'a.js']
14020
- slices = path.split(SLASH).filter(Boolean);
14021
- }
14022
-
14023
- slices.pop();
14024
-
14025
- // If the path has no parent directory, just test it
14026
- if (!slices.length) {
14027
- return cache[path] = this._rules.test(path, checkUnignored, MODE_IGNORE)
14028
- }
14029
-
14030
- const parent = this._t(
14031
- slices.join(SLASH) + SLASH,
14032
- cache,
14033
- checkUnignored,
14034
- slices
14035
- );
14036
-
14037
- // If the path contains a parent directory, check the parent first
14038
- return cache[path] = parent.ignored
14039
- // > It is not possible to re-include a file if a parent directory of
14040
- // > that file is excluded.
14041
- ? parent
14042
- : this._rules.test(path, checkUnignored, MODE_IGNORE)
14043
- }
14044
-
14045
- ignores (path) {
14046
- return this._test(path, this._ignoreCache, false).ignored
14047
- }
14048
-
14049
- createFilter () {
14050
- return path => !this.ignores(path)
14051
- }
14052
-
14053
- filter (paths) {
14054
- return makeArray(paths).filter(this.createFilter())
14055
- }
14056
-
14057
- // @returns {TestResult}
14058
- test (path) {
14059
- return this._test(path, this._testCache, true)
14060
- }
14061
- }
14064
+ const factory = options => new Ignore(options);
14065
+
14066
+ const isPathValid = path =>
14067
+ checkPath(path && checkPath.convert(path), path, RETURN_FALSE);
14068
+
14069
+ /* istanbul ignore next */
14070
+ const setupWindows = () => {
14071
+ /* eslint no-control-regex: "off" */
14072
+ const makePosix = str => /^\\\\\?\\/.test(str)
14073
+ || /["<>|\u0000-\u001F]+/u.test(str)
14074
+ ? str
14075
+ : str.replace(/\\/g, '/');
14076
+
14077
+ checkPath.convert = makePosix;
14078
+
14079
+ // 'C:\\foo' <- 'C:\\foo' has been converted to 'C:/'
14080
+ // 'd:\\foo'
14081
+ const REGEX_TEST_WINDOWS_PATH_ABSOLUTE = /^[a-z]:\//i;
14082
+ checkPath.isNotRelative = path =>
14083
+ REGEX_TEST_WINDOWS_PATH_ABSOLUTE.test(path)
14084
+ || isNotRelative(path);
14085
+ };
14086
+
14087
+
14088
+ // Windows
14089
+ // --------------------------------------------------------------
14090
+ /* istanbul ignore next */
14091
+ if (
14092
+ // Detect `process` so that it can run in browsers.
14093
+ typeof process !== 'undefined'
14094
+ && process.platform === 'win32'
14095
+ ) {
14096
+ setupWindows();
14097
+ }
14062
14098
 
14063
- const factory = options => new Ignore(options);
14064
-
14065
- const isPathValid = path =>
14066
- checkPath(path && checkPath.convert(path), path, RETURN_FALSE);
14067
-
14068
-
14069
- // Windows
14070
- // --------------------------------------------------------------
14071
- /* istanbul ignore next */
14072
- if (
14073
- // Detect `process` so that it can run in browsers.
14074
- typeof process !== 'undefined'
14075
- && (
14076
- process.env && process.env.IGNORE_TEST_WIN32
14077
- || process.platform === 'win32'
14078
- )
14079
- ) {
14080
- /* eslint no-control-regex: "off" */
14081
- const makePosix = str => /^\\\\\?\\/.test(str)
14082
- || /["<>|\u0000-\u001F]+/u.test(str)
14083
- ? str
14084
- : str.replace(/\\/g, '/');
14085
-
14086
- checkPath.convert = makePosix;
14087
-
14088
- // 'C:\\foo' <- 'C:\\foo' has been converted to 'C:/'
14089
- // 'd:\\foo'
14090
- const REGEX_TEST_WINDOWS_PATH_ABSOLUTE = /^[a-z]:\//i;
14091
- checkPath.isNotRelative = path =>
14092
- REGEX_TEST_WINDOWS_PATH_ABSOLUTE.test(path)
14093
- || isNotRelative(path);
14094
- }
14099
+ // COMMONJS_EXPORTS ////////////////////////////////////////////////////////////
14095
14100
 
14096
- // COMMONJS_EXPORTS ////////////////////////////////////////////////////////////
14101
+ module.exports = factory;
14097
14102
 
14098
- ignore$1.exports = factory;
14103
+ // Although it is an anti-pattern,
14104
+ // it is still widely misused by a lot of libraries in github
14105
+ // Ref: https://github.com/search?q=ignore.default%28%29&type=code
14106
+ factory.default = factory;
14099
14107
 
14100
- // Although it is an anti-pattern,
14101
- // it is still widely misused by a lot of libraries in github
14102
- // Ref: https://github.com/search?q=ignore.default%28%29&type=code
14103
- factory.default = factory;
14108
+ module.exports.isPathValid = isPathValid;
14104
14109
 
14105
- ignore$1.exports.isPathValid = isPathValid;
14110
+ // For testing purposes
14111
+ define(module.exports, Symbol.for('setupWindows'), setupWindows);
14112
+ } (ignore$1));
14106
14113
  return ignore$1.exports;
14107
14114
  }
14108
14115