index.js 1.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  1. 'use strict';
  2. var isGlob = require('is-glob');
  3. var pathPosixDirname = require('path').posix.dirname;
  4. var isWin32 = require('os').platform() === 'win32';
  5. var slash = '/';
  6. var backslash = /\\/g;
  7. var escaped = /\\([!*?|[\](){}])/g;
  8. /**
  9. * @param {string} str
  10. * @param {Object} opts
  11. * @param {boolean} [opts.flipBackslashes=true]
  12. */
  13. module.exports = function globParent(str, opts) {
  14. var options = Object.assign({ flipBackslashes: true }, opts);
  15. // flip windows path separators
  16. if (options.flipBackslashes && isWin32 && str.indexOf(slash) < 0) {
  17. str = str.replace(backslash, slash);
  18. }
  19. // special case for strings ending in enclosure containing path separator
  20. if (isEnclosure(str)) {
  21. str += slash;
  22. }
  23. // preserves full path in case of trailing path separator
  24. str += 'a';
  25. // remove path parts that are globby
  26. do {
  27. str = pathPosixDirname(str);
  28. } while (isGlobby(str));
  29. // remove escape chars and return result
  30. return str.replace(escaped, '$1');
  31. };
  32. function isEnclosure(str) {
  33. var lastChar = str.slice(-1);
  34. var enclosureStart;
  35. switch (lastChar) {
  36. case '}':
  37. enclosureStart = '{';
  38. break;
  39. case ']':
  40. enclosureStart = '[';
  41. break;
  42. default:
  43. return false;
  44. }
  45. var foundIndex = str.indexOf(enclosureStart);
  46. if (foundIndex < 0) {
  47. return false;
  48. }
  49. return str.slice(foundIndex + 1, -1).includes(slash);
  50. }
  51. function isGlobby(str) {
  52. if (/\([^()]+$/.test(str)) {
  53. return true;
  54. }
  55. if (str[0] === '{' || str[0] === '[') {
  56. return true;
  57. }
  58. if (/[^\\][{[]/.test(str)) {
  59. return true;
  60. }
  61. return isGlob(str);
  62. }