UNPKG

4.28 kBJavaScriptView Raw
1/*
2 MIT License http://www.opensource.org/licenses/mit-license.php
3 Author Tobias Koppers @sokra
4*/
5"use strict";
6
7function globToRegExp(glob) {
8 // * [^\\\/]*
9 // /**/ /.+/
10 // ^* \./.+ (concord special)
11 // ? [^\\\/]
12 // [!...] [^...]
13 // [^...] [^...]
14 // / [\\\/]
15 // {...,...} (...|...)
16 // ?(...|...) (...|...)?
17 // +(...|...) (...|...)+
18 // *(...|...) (...|...)*
19 // @(...|...) (...|...)
20 if(/^\(.+\)$/.test(glob)) {
21 // allow to pass an RegExp in brackets
22 return new RegExp(glob.substr(1, glob.length - 2));
23 }
24 const tokens = tokenize(glob);
25 const process = createRoot();
26 const regExpStr = tokens.map(process).join("");
27 return new RegExp("^" + regExpStr + "$");
28}
29
30const SIMPLE_TOKENS = {
31 "@(": "one",
32 "?(": "zero-one",
33 "+(": "one-many",
34 "*(": "zero-many",
35 "|": "segment-sep",
36 "/**/": "any-path-segments",
37 "**": "any-path",
38 "*": "any-path-segment",
39 "?": "any-char",
40 "{": "or",
41 "/": "path-sep",
42 ",": "comma",
43 ")": "closing-segment",
44 "}": "closing-or"
45};
46
47function tokenize(glob) {
48 return glob.split(/([@?+*]\(|\/\*\*\/|\*\*|[?*]|\[[\!\^]?(?:[^\]\\]|\\.)+\]|\{|,|\/|[|)}])/g).map(item => {
49 if(!item)
50 return null;
51 const t = SIMPLE_TOKENS[item];
52 if(t) {
53 return {
54 type: t
55 };
56 }
57 if(item[0] === "[") {
58 if(item[1] === "^" || item[1] === "!") {
59 return {
60 type: "inverted-char-set",
61 value: item.substr(2, item.length - 3)
62 };
63 } else {
64 return {
65 type: "char-set",
66 value: item.substr(1, item.length - 2)
67 };
68 }
69 }
70 return {
71 type: "string",
72 value: item
73 };
74 }).filter(Boolean).concat({
75 type: "end"
76 });
77}
78
79function createRoot() {
80 const inOr = [];
81 const process = createSeqment();
82 let initial = true;
83 return function(token) {
84 switch(token.type) {
85 case "or":
86 inOr.push(initial);
87 return "(";
88 case "comma":
89 if(inOr.length) {
90 initial = inOr[inOr.length - 1];
91 return "|";
92 } else {
93 return process({
94 type: "string",
95 value: ","
96 }, initial);
97 }
98 case "closing-or":
99 if(inOr.length === 0)
100 throw new Error("Unmatched '}'");
101 inOr.pop();
102 return ")";
103 case "end":
104 if(inOr.length)
105 throw new Error("Unmatched '{'");
106 return process(token, initial);
107 default:
108 {
109 const result = process(token, initial);
110 initial = false;
111 return result;
112 }
113 }
114 };
115}
116
117function createSeqment() {
118 const inSeqment = [];
119 const process = createSimple();
120 return function(token, initial) {
121 switch(token.type) {
122 case "one":
123 case "one-many":
124 case "zero-many":
125 case "zero-one":
126 inSeqment.push(token.type);
127 return "(";
128 case "segment-sep":
129 if(inSeqment.length) {
130 return "|";
131 } else {
132 return process({
133 type: "string",
134 value: "|"
135 }, initial);
136 }
137 case "closing-segment":
138 {
139 const segment = inSeqment.pop();
140 switch(segment) {
141 case "one":
142 return ")";
143 case "one-many":
144 return ")+";
145 case "zero-many":
146 return ")*";
147 case "zero-one":
148 return ")?";
149 }
150 throw new Error("Unexcepted segment " + segment);
151 }
152 case "end":
153 if(inSeqment.length > 0) {
154 throw new Error("Unmatched segment, missing ')'");
155 }
156 return process(token, initial);
157 default:
158 return process(token, initial);
159 }
160 };
161}
162
163function createSimple() {
164 return function(token, initial) {
165 switch(token.type) {
166 case "path-sep":
167 return "[\\\\/]+";
168 case "any-path-segments":
169 return "[\\\\/]+(?:(.+)[\\\\/]+)?";
170 case "any-path":
171 return "(.*)";
172 case "any-path-segment":
173 if(initial) {
174 return "\\.[\\\\/]+(?:.*[\\\\/]+)?([^\\\\/]+)";
175 } else {
176 return "([^\\\\/]*)";
177 }
178 case "any-char":
179 return "[^\\\\/]";
180 case "inverted-char-set":
181 return "[^" + token.value + "]";
182 case "char-set":
183 return "[" + token.value + "]";
184 case "string":
185 return token.value.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
186 case "end":
187 return "";
188 default:
189 throw new Error("Unsupported token '" + token.type + "'");
190 }
191 };
192}
193
194exports.globToRegExp = globToRegExp;