UNPKG

5.51 kBJavaScriptView Raw
1/*
2 MIT License http://www.opensource.org/licenses/mit-license.php
3 Author Tobias Koppers @sokra
4*/
5"use strict";
6
7const globToRegExp = require("./globToRegExp").globToRegExp;
8
9function parseType(type) {
10 const items = type.split("+");
11 const t = items.shift();
12 return {
13 type: t === "*" ? null : t,
14 features: items
15 };
16}
17
18function isTypeMatched(baseType, testedType) {
19 if(typeof baseType === "string") baseType = parseType(baseType);
20 if(typeof testedType === "string") testedType = parseType(testedType);
21 if(testedType.type && testedType.type !== baseType.type) return false;
22 return testedType.features.every(requiredFeature => {
23 return baseType.features.indexOf(requiredFeature) >= 0;
24 });
25}
26
27function isResourceTypeMatched(baseType, testedType) {
28 baseType = baseType.split("/");
29 testedType = testedType.split("/");
30 if(baseType.length !== testedType.length) return false;
31 for(let i = 0; i < baseType.length; i++) {
32 if(!isTypeMatched(baseType[i], testedType[i]))
33 return false;
34 }
35 return true;
36}
37
38function isResourceTypeSupported(context, type) {
39 return context.supportedResourceTypes && context.supportedResourceTypes.some(supportedType => {
40 return isResourceTypeMatched(supportedType, type);
41 });
42}
43
44function isEnvironment(context, env) {
45 return context.environments && context.environments.every(environment => {
46 return isTypeMatched(environment, env);
47 });
48}
49
50const globCache = {};
51
52function getGlobRegExp(glob) {
53 const regExp = globCache[glob] || (globCache[glob] = globToRegExp(glob));
54 return regExp;
55}
56
57function matchGlob(glob, relativePath) {
58 const regExp = getGlobRegExp(glob);
59 return regExp.exec(relativePath);
60}
61
62function isGlobMatched(glob, relativePath) {
63 return !!matchGlob(glob, relativePath);
64}
65
66function isConditionMatched(context, condition) {
67 const items = condition.split("|");
68 return items.some(function testFn(item) {
69 item = item.trim();
70 const inverted = /^!/.test(item);
71 if(inverted) return !testFn(item.substr(1));
72 if(/^[a-z]+:/.test(item)) {
73 // match named condition
74 const match = /^([a-z]+):\s*/.exec(item);
75 const value = item.substr(match[0].length);
76 const name = match[1];
77 switch(name) {
78 case "referrer":
79 return isGlobMatched(value, context.referrer);
80 default:
81 return false;
82 }
83 } else if(item.indexOf("/") >= 0) {
84 // match supported type
85 return isResourceTypeSupported(context, item);
86 } else {
87 // match environment
88 return isEnvironment(context, item);
89 }
90 });
91}
92
93function isKeyMatched(context, key) {
94 while(true) { //eslint-disable-line
95 const match = /^\[([^\]]+)\]\s*/.exec(key);
96 if(!match) return key;
97 key = key.substr(match[0].length);
98 const condition = match[1];
99 if(!isConditionMatched(context, condition)) {
100 return false;
101 }
102 }
103}
104
105function getField(context, configuration, field) {
106 let value;
107 Object.keys(configuration).forEach(key => {
108 const pureKey = isKeyMatched(context, key);
109 if(pureKey === field) {
110 value = configuration[key];
111 }
112 });
113 return value;
114}
115
116function getMain(context, configuration) {
117 return getField(context, configuration, "main");
118}
119
120function getExtensions(context, configuration) {
121 return getField(context, configuration, "extensions");
122}
123
124function matchModule(context, configuration, request) {
125 const modulesField = getField(context, configuration, "modules");
126 if(!modulesField) return request;
127 let newRequest = request;
128 const keys = Object.keys(modulesField);
129 let iteration = 0;
130 let match;
131 let index;
132 for(let i = 0; i < keys.length; i++) {
133 const key = keys[i];
134 const pureKey = isKeyMatched(context, key);
135 match = matchGlob(pureKey, newRequest);
136 if(match) {
137 const value = modulesField[key];
138 if(typeof value !== "string") {
139 return value;
140 } else if(/^\(.+\)$/.test(pureKey)) {
141 newRequest = newRequest.replace(getGlobRegExp(pureKey), value);
142 } else {
143 index = 1;
144 newRequest = value.replace(/(\/?\*)?\*/g, replaceMatcher);
145 }
146 i = -1;
147 if(iteration++ > keys.length) {
148 throw new Error("Request '" + request + "' matches recursively");
149 }
150 }
151 }
152 return newRequest;
153
154 function replaceMatcher(find) {
155 switch(find) {
156 case "/**":
157 {
158 const m = match[index++];
159 return m ? "/" + m : "";
160 }
161 case "**":
162 case "*":
163 return match[index++];
164 }
165 }
166}
167
168function matchType(context, configuration, relativePath) {
169 const typesField = getField(context, configuration, "types");
170 if(!typesField) return undefined;
171 let type;
172 Object.keys(typesField).forEach(key => {
173 const pureKey = isKeyMatched(context, key);
174 if(isGlobMatched(pureKey, relativePath)) {
175 const value = typesField[key];
176 if(!type && /\/\*$/.test(value))
177 throw new Error("value ('" + value + "') of key '" + key + "' contains '*', but there is no previous value defined");
178 type = value.replace(/\/\*$/, "/" + type);
179 }
180 });
181 return type;
182}
183
184exports.parseType = parseType;
185exports.isTypeMatched = isTypeMatched;
186exports.isResourceTypeSupported = isResourceTypeSupported;
187exports.isEnvironment = isEnvironment;
188exports.isGlobMatched = isGlobMatched;
189exports.isConditionMatched = isConditionMatched;
190exports.isKeyMatched = isKeyMatched;
191exports.getField = getField;
192exports.getMain = getMain;
193exports.getExtensions = getExtensions;
194exports.matchModule = matchModule;
195exports.matchType = matchType;