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