Layout von Websiten mit Bootstrap und Foundation
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

scan.js 8.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383
  1. 'use strict';
  2. const utils = require('./utils');
  3. const {
  4. CHAR_ASTERISK, /* * */
  5. CHAR_AT, /* @ */
  6. CHAR_BACKWARD_SLASH, /* \ */
  7. CHAR_COMMA, /* , */
  8. CHAR_DOT, /* . */
  9. CHAR_EXCLAMATION_MARK, /* ! */
  10. CHAR_FORWARD_SLASH, /* / */
  11. CHAR_LEFT_CURLY_BRACE, /* { */
  12. CHAR_LEFT_PARENTHESES, /* ( */
  13. CHAR_LEFT_SQUARE_BRACKET, /* [ */
  14. CHAR_PLUS, /* + */
  15. CHAR_QUESTION_MARK, /* ? */
  16. CHAR_RIGHT_CURLY_BRACE, /* } */
  17. CHAR_RIGHT_PARENTHESES, /* ) */
  18. CHAR_RIGHT_SQUARE_BRACKET /* ] */
  19. } = require('./constants');
  20. const isPathSeparator = code => {
  21. return code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH;
  22. };
  23. const depth = token => {
  24. if (token.isPrefix !== true) {
  25. token.depth = token.isGlobstar ? Infinity : 1;
  26. }
  27. };
  28. /**
  29. * Quickly scans a glob pattern and returns an object with a handful of
  30. * useful properties, like `isGlob`, `path` (the leading non-glob, if it exists),
  31. * `glob` (the actual pattern), and `negated` (true if the path starts with `!`).
  32. *
  33. * ```js
  34. * const pm = require('picomatch');
  35. * console.log(pm.scan('foo/bar/*.js'));
  36. * { isGlob: true, input: 'foo/bar/*.js', base: 'foo/bar', glob: '*.js' }
  37. * ```
  38. * @param {String} `str`
  39. * @param {Object} `options`
  40. * @return {Object} Returns an object with tokens and regex source string.
  41. * @api public
  42. */
  43. const scan = (input, options) => {
  44. const opts = options || {};
  45. const length = input.length - 1;
  46. const scanToEnd = opts.parts === true || opts.scanToEnd === true;
  47. const slashes = [];
  48. const tokens = [];
  49. const parts = [];
  50. let str = input;
  51. let index = -1;
  52. let start = 0;
  53. let lastIndex = 0;
  54. let isBrace = false;
  55. let isBracket = false;
  56. let isGlob = false;
  57. let isExtglob = false;
  58. let isGlobstar = false;
  59. let braceEscaped = false;
  60. let backslashes = false;
  61. let negated = false;
  62. let finished = false;
  63. let braces = 0;
  64. let prev;
  65. let code;
  66. let token = { value: '', depth: 0, isGlob: false };
  67. const eos = () => index >= length;
  68. const peek = () => str.charCodeAt(index + 1);
  69. const advance = () => {
  70. prev = code;
  71. return str.charCodeAt(++index);
  72. };
  73. while (index < length) {
  74. code = advance();
  75. let next;
  76. if (code === CHAR_BACKWARD_SLASH) {
  77. backslashes = token.backslashes = true;
  78. code = advance();
  79. if (code === CHAR_LEFT_CURLY_BRACE) {
  80. braceEscaped = true;
  81. }
  82. continue;
  83. }
  84. if (braceEscaped === true || code === CHAR_LEFT_CURLY_BRACE) {
  85. braces++;
  86. while (eos() !== true && (code = advance())) {
  87. if (code === CHAR_BACKWARD_SLASH) {
  88. backslashes = token.backslashes = true;
  89. advance();
  90. continue;
  91. }
  92. if (code === CHAR_LEFT_CURLY_BRACE) {
  93. braces++;
  94. continue;
  95. }
  96. if (braceEscaped !== true && code === CHAR_DOT && (code = advance()) === CHAR_DOT) {
  97. isBrace = token.isBrace = true;
  98. isGlob = token.isGlob = true;
  99. finished = true;
  100. if (scanToEnd === true) {
  101. continue;
  102. }
  103. break;
  104. }
  105. if (braceEscaped !== true && code === CHAR_COMMA) {
  106. isBrace = token.isBrace = true;
  107. isGlob = token.isGlob = true;
  108. finished = true;
  109. if (scanToEnd === true) {
  110. continue;
  111. }
  112. break;
  113. }
  114. if (code === CHAR_RIGHT_CURLY_BRACE) {
  115. braces--;
  116. if (braces === 0) {
  117. braceEscaped = false;
  118. isBrace = token.isBrace = true;
  119. finished = true;
  120. break;
  121. }
  122. }
  123. }
  124. if (scanToEnd === true) {
  125. continue;
  126. }
  127. break;
  128. }
  129. if (code === CHAR_FORWARD_SLASH) {
  130. slashes.push(index);
  131. tokens.push(token);
  132. token = { value: '', depth: 0, isGlob: false };
  133. if (finished === true) continue;
  134. if (prev === CHAR_DOT && index === (start + 1)) {
  135. start += 2;
  136. continue;
  137. }
  138. lastIndex = index + 1;
  139. continue;
  140. }
  141. if (opts.noext !== true) {
  142. const isExtglobChar = code === CHAR_PLUS
  143. || code === CHAR_AT
  144. || code === CHAR_ASTERISK
  145. || code === CHAR_QUESTION_MARK
  146. || code === CHAR_EXCLAMATION_MARK;
  147. if (isExtglobChar === true && peek() === CHAR_LEFT_PARENTHESES) {
  148. isGlob = token.isGlob = true;
  149. isExtglob = token.isExtglob = true;
  150. finished = true;
  151. if (scanToEnd === true) {
  152. while (eos() !== true && (code = advance())) {
  153. if (code === CHAR_BACKWARD_SLASH) {
  154. backslashes = token.backslashes = true;
  155. code = advance();
  156. continue;
  157. }
  158. if (code === CHAR_RIGHT_PARENTHESES) {
  159. isGlob = token.isGlob = true;
  160. finished = true;
  161. break;
  162. }
  163. }
  164. continue;
  165. }
  166. break;
  167. }
  168. }
  169. if (code === CHAR_ASTERISK) {
  170. if (prev === CHAR_ASTERISK) isGlobstar = token.isGlobstar = true;
  171. isGlob = token.isGlob = true;
  172. finished = true;
  173. if (scanToEnd === true) {
  174. continue;
  175. }
  176. break;
  177. }
  178. if (code === CHAR_QUESTION_MARK) {
  179. isGlob = token.isGlob = true;
  180. finished = true;
  181. if (scanToEnd === true) {
  182. continue;
  183. }
  184. break;
  185. }
  186. if (code === CHAR_LEFT_SQUARE_BRACKET) {
  187. while (eos() !== true && (next = advance())) {
  188. if (next === CHAR_BACKWARD_SLASH) {
  189. backslashes = token.backslashes = true;
  190. advance();
  191. continue;
  192. }
  193. if (next === CHAR_RIGHT_SQUARE_BRACKET) {
  194. isBracket = token.isBracket = true;
  195. isGlob = token.isGlob = true;
  196. finished = true;
  197. if (scanToEnd === true) {
  198. continue;
  199. }
  200. break;
  201. }
  202. }
  203. }
  204. if (opts.nonegate !== true && code === CHAR_EXCLAMATION_MARK && index === start) {
  205. negated = token.negated = true;
  206. start++;
  207. continue;
  208. }
  209. if (opts.noparen !== true && code === CHAR_LEFT_PARENTHESES) {
  210. isGlob = token.isGlob = true;
  211. if (scanToEnd === true) {
  212. while (eos() !== true && (code = advance())) {
  213. if (code === CHAR_LEFT_PARENTHESES) {
  214. backslashes = token.backslashes = true;
  215. code = advance();
  216. continue;
  217. }
  218. if (code === CHAR_RIGHT_PARENTHESES) {
  219. finished = true;
  220. break;
  221. }
  222. }
  223. continue;
  224. }
  225. break;
  226. }
  227. if (isGlob === true) {
  228. finished = true;
  229. if (scanToEnd === true) {
  230. continue;
  231. }
  232. break;
  233. }
  234. }
  235. if (opts.noext === true) {
  236. isExtglob = false;
  237. isGlob = false;
  238. }
  239. let base = str;
  240. let prefix = '';
  241. let glob = '';
  242. if (start > 0) {
  243. prefix = str.slice(0, start);
  244. str = str.slice(start);
  245. lastIndex -= start;
  246. }
  247. if (base && isGlob === true && lastIndex > 0) {
  248. base = str.slice(0, lastIndex);
  249. glob = str.slice(lastIndex);
  250. } else if (isGlob === true) {
  251. base = '';
  252. glob = str;
  253. } else {
  254. base = str;
  255. }
  256. if (base && base !== '' && base !== '/' && base !== str) {
  257. if (isPathSeparator(base.charCodeAt(base.length - 1))) {
  258. base = base.slice(0, -1);
  259. }
  260. }
  261. if (opts.unescape === true) {
  262. if (glob) glob = utils.removeBackslashes(glob);
  263. if (base && backslashes === true) {
  264. base = utils.removeBackslashes(base);
  265. }
  266. }
  267. const state = {
  268. prefix,
  269. input,
  270. start,
  271. base,
  272. glob,
  273. isBrace,
  274. isBracket,
  275. isGlob,
  276. isExtglob,
  277. isGlobstar,
  278. negated
  279. };
  280. if (opts.tokens === true) {
  281. state.maxDepth = 0;
  282. if (!isPathSeparator(code)) {
  283. tokens.push(token);
  284. }
  285. state.tokens = tokens;
  286. }
  287. if (opts.parts === true || opts.tokens === true) {
  288. let prevIndex;
  289. for (let idx = 0; idx < slashes.length; idx++) {
  290. const n = prevIndex ? prevIndex + 1 : start;
  291. const i = slashes[idx];
  292. const value = input.slice(n, i);
  293. if (opts.tokens) {
  294. if (idx === 0 && start !== 0) {
  295. tokens[idx].isPrefix = true;
  296. tokens[idx].value = prefix;
  297. } else {
  298. tokens[idx].value = value;
  299. }
  300. depth(tokens[idx]);
  301. state.maxDepth += tokens[idx].depth;
  302. }
  303. if (idx !== 0 || value !== '') {
  304. parts.push(value);
  305. }
  306. prevIndex = i;
  307. }
  308. if (prevIndex && prevIndex + 1 < input.length) {
  309. const value = input.slice(prevIndex + 1);
  310. parts.push(value);
  311. if (opts.tokens) {
  312. tokens[tokens.length - 1].value = value;
  313. depth(tokens[tokens.length - 1]);
  314. state.maxDepth += tokens[tokens.length - 1].depth;
  315. }
  316. }
  317. state.slashes = slashes;
  318. state.parts = parts;
  319. }
  320. return state;
  321. };
  322. module.exports = scan;