Projekt

Obecné

Profil

Stáhnout (4.18 KB) Statistiky
| Větev: | Revize:
1
/*
2
	MIT License http://www.opensource.org/licenses/mit-license.php
3
	Author Tobias Koppers @sokra
4
*/
5
"use strict";
6

    
7
function 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

    
30
const 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

    
47
function 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

    
79
function 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

    
117
function 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

    
163
function 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

    
194
exports.globToRegExp = globToRegExp;
(36-36/37)