html-validate 9.5.5 → 9.6.1

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