| /* |
| MIT License http://www.opensource.org/licenses/mit-license.php |
| Author Tobias Koppers @sokra |
| */ |
| "use strict"; |
| |
| function globToRegExp(glob) { |
| // * [^\\\/]* |
| // /**/ /.+/ |
| // ^* \./.+ (concord special) |
| // ? [^\\\/] |
| // [!...] [^...] |
| // [^...] [^...] |
| // / [\\\/] |
| // {...,...} (...|...) |
| // ?(...|...) (...|...)? |
| // +(...|...) (...|...)+ |
| // *(...|...) (...|...)* |
| // @(...|...) (...|...) |
| if (/^\(.+\)$/.test(glob)) { |
| // allow to pass an RegExp in brackets |
| return new RegExp(glob.substr(1, glob.length - 2)); |
| } |
| const tokens = tokenize(glob); |
| const process = createRoot(); |
| const regExpStr = tokens.map(process).join(""); |
| return new RegExp("^" + regExpStr + "$"); |
| } |
| |
| const SIMPLE_TOKENS = { |
| "@(": "one", |
| "?(": "zero-one", |
| "+(": "one-many", |
| "*(": "zero-many", |
| "|": "segment-sep", |
| "/**/": "any-path-segments", |
| "**": "any-path", |
| "*": "any-path-segment", |
| "?": "any-char", |
| "{": "or", |
| "/": "path-sep", |
| ",": "comma", |
| ")": "closing-segment", |
| "}": "closing-or" |
| }; |
| |
| function tokenize(glob) { |
| return glob |
| .split( |
| /([@?+*]\(|\/\*\*\/|\*\*|[?*]|\[[!^]?(?:[^\]\\]|\\.)+\]|\{|,|\/|[|)}])/g |
| ) |
| .map(item => { |
| if (!item) return null; |
| const t = SIMPLE_TOKENS[item]; |
| if (t) { |
| return { |
| type: t |
| }; |
| } |
| if (item[0] === "[") { |
| if (item[1] === "^" || item[1] === "!") { |
| return { |
| type: "inverted-char-set", |
| value: item.substr(2, item.length - 3) |
| }; |
| } else { |
| return { |
| type: "char-set", |
| value: item.substr(1, item.length - 2) |
| }; |
| } |
| } |
| return { |
| type: "string", |
| value: item |
| }; |
| }) |
| .filter(Boolean) |
| .concat({ |
| type: "end" |
| }); |
| } |
| |
| function createRoot() { |
| const inOr = []; |
| const process = createSeqment(); |
| let initial = true; |
| return function(token) { |
| switch (token.type) { |
| case "or": |
| inOr.push(initial); |
| return "("; |
| case "comma": |
| if (inOr.length) { |
| initial = inOr[inOr.length - 1]; |
| return "|"; |
| } else { |
| return process( |
| { |
| type: "string", |
| value: "," |
| }, |
| initial |
| ); |
| } |
| case "closing-or": |
| if (inOr.length === 0) throw new Error("Unmatched '}'"); |
| inOr.pop(); |
| return ")"; |
| case "end": |
| if (inOr.length) throw new Error("Unmatched '{'"); |
| return process(token, initial); |
| default: { |
| const result = process(token, initial); |
| initial = false; |
| return result; |
| } |
| } |
| }; |
| } |
| |
| function createSeqment() { |
| const inSeqment = []; |
| const process = createSimple(); |
| return function(token, initial) { |
| switch (token.type) { |
| case "one": |
| case "one-many": |
| case "zero-many": |
| case "zero-one": |
| inSeqment.push(token.type); |
| return "("; |
| case "segment-sep": |
| if (inSeqment.length) { |
| return "|"; |
| } else { |
| return process( |
| { |
| type: "string", |
| value: "|" |
| }, |
| initial |
| ); |
| } |
| case "closing-segment": { |
| const segment = inSeqment.pop(); |
| switch (segment) { |
| case "one": |
| return ")"; |
| case "one-many": |
| return ")+"; |
| case "zero-many": |
| return ")*"; |
| case "zero-one": |
| return ")?"; |
| } |
| throw new Error("Unexcepted segment " + segment); |
| } |
| case "end": |
| if (inSeqment.length > 0) { |
| throw new Error("Unmatched segment, missing ')'"); |
| } |
| return process(token, initial); |
| default: |
| return process(token, initial); |
| } |
| }; |
| } |
| |
| function createSimple() { |
| return function(token, initial) { |
| switch (token.type) { |
| case "path-sep": |
| return "[\\\\/]+"; |
| case "any-path-segments": |
| return "[\\\\/]+(?:(.+)[\\\\/]+)?"; |
| case "any-path": |
| return "(.*)"; |
| case "any-path-segment": |
| if (initial) { |
| return "\\.[\\\\/]+(?:.*[\\\\/]+)?([^\\\\/]+)"; |
| } else { |
| return "([^\\\\/]*)"; |
| } |
| case "any-char": |
| return "[^\\\\/]"; |
| case "inverted-char-set": |
| return "[^" + token.value + "]"; |
| case "char-set": |
| return "[" + token.value + "]"; |
| case "string": |
| return token.value.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"); |
| case "end": |
| return ""; |
| default: |
| throw new Error("Unsupported token '" + token.type + "'"); |
| } |
| }; |
| } |
| |
| exports.globToRegExp = globToRegExp; |