UNPKG

6.01 kBJavaScriptView Raw
1const path = require('path');
2const Rule = require('./Rule');
3const VAR = require('./VAR');
4
5
6
7function Match(option, rules) {
8 this.option = option;
9 this.rules = [];
10 this.init(rules);
11}
12
13Match.prototype.init = function (release) {
14 release = release || [];
15 if (!Array.isArray(release)) {
16 switch (typeof release) {
17 case 'string':
18 case 'object':
19 release = [release];
20 break;
21 default:
22 throw new Error('Invalid release rule');
23 break;
24 }
25 }
26 const option = this.option;
27 const symbol = option.symbol;
28 let rules = [];
29 release.forEach(rule => {
30 const ruleType = typeof rule;
31 if (ruleType === 'string') {
32 rules.push(rule);
33 } else if (Array.isArray(rule)) {
34 if (rule.every(r => typeof r === 'string')) {
35 throw new Error(`Invalid rule: array rule elements can only be a string`);
36 }
37 rules = rules.concat(rule);
38 } else if (ruleType === 'object') {
39 Object.keys(rule).map(key => {
40 const value = rule[key];
41 if (typeof value !== 'boolean') {
42 key = key
43 .replace(new RegExp(
44 `^(\\${symbol.negation}?)\\${symbol.module}`
45 ), `$1${symbol.alias}`)
46 .replace(new RegExp(
47 `^(\\${symbol.negation}?)(\\${symbol.regexp}|\\${symbol.match})`
48 ), `$1/$2`)
49 }
50 const item = {};
51 item[key] = value;
52 rules = rules.concat(this.stringifyRules(item));
53 });
54 } else {
55 throw new Error(`Invalid rule type: ${ruleType}`);
56 }
57 });
58 rules.forEach(rule => {
59 if (!rule) {
60 throw new Error('empty rule');
61 }
62 if (
63 rule.charAt(0) === symbol.module
64 || (
65 rule.charAt(0) === symbol.negation
66 && rule.charAt(1) === symbol.module
67 )
68 ) {
69 const isModuleNegation = rule.charAt(0) === symbol.negation;
70 const moduleName = rule.replace(new RegExp(`^\\${symbol.negation}`), '').slice(1);
71 const moduleRule = option.module[moduleName];
72 if (!moduleRule) {
73 throw new Error(`not exist module ${moduleName}`)
74 }
75 const moduleMatch = new Match(option, moduleRule);
76 moduleMatch.rules.forEach(rule => {
77 isModuleNegation && rule.setNegation(true)
78 this.rules.push(rule);
79 });
80 } else {
81 const relation = rule.indexOf(symbol.relation);
82 let base = '';
83 let children = rule;
84 if (relation > -1) {
85 base = rule.slice(0, relation);
86 children = rule.slice(relation + 1);
87 }
88 children.split(symbol.separation).forEach(child => {
89 let prefix = base;
90 if (prefix && child.charAt(0) === symbol.negation) {
91 prefix = symbol.negation + prefix.replace(new RegExp(`^\\${symbol.negation}`), '');
92 child = child.slice(1);
93 }
94 this.rules.push(new Rule(path.join(prefix, child), option));
95 });
96 }
97 });
98};
99
100Match.prototype.test = function (path) {
101 const matchMode = this.option.match;
102 let release = false;
103 let matched = false;
104 this.rules.forEach(rule => {
105 const stat = rule.test(path);
106 if (stat > -1) {
107 if (matched) {
108 if (matchMode === VAR.MATCH_MODE.WARN) {
109 console.warn(`path[${path}] match repeat by rule[${rule.toString()}]`);
110 } else if (matchMode === VAR.MATCH_MODE.STRICT) {
111 throw new Error(`path[${path}] must match once, repeat by rule[${rule.toString()}]`);
112 }
113 }
114 matched = true;
115 release = !!stat;
116 }
117 });
118 return matched
119 ? release
120 ? 1 : 0
121 : -1;
122};
123
124Match.prototype.stringifyRules = function(rule, base) {
125 const option = this.option;
126 const symbol = option.symbol;
127
128 const prefix = base || '';
129 const prefixNonNegation = prefix.replace(new RegExp(`^\\${symbol.negation}`), '');
130
131 let rules = [];
132 Object.keys(rule).forEach(key => {
133 const keyPrefix = key.charAt(0) === symbol.negation
134 ? prefixNonNegation
135 ? path.join(symbol.negation + prefixNonNegation, key.slice(1))
136 : (symbol.negation + key.slice(1))
137 : path.join(prefix, key);
138 const keyPrefixNonNegation = keyPrefix.replace(new RegExp(`^\\${symbol.negation}`), '');
139
140 const value = rule[key];
141 const valueType = typeof value;
142 if (valueType === 'string' || Array.isArray(value)) {
143 (Array.isArray(value) ? value : [value]).forEach(subRule => {
144 if (typeof subRule !== 'string' || subRule.length === 0) {
145 throw new Error(`Invalid rule: array rule elements can only be a string`);
146 }
147 rules.push(
148 subRule.charAt(0) === symbol.negation
149 ? path.join(symbol.negation + keyPrefixNonNegation, subRule.slice(1))
150 : path.join(keyPrefix, subRule)
151 );
152 });
153 } else if (valueType === 'object') {
154 rules = rules.concat(this.stringifyRules(value, keyPrefix));
155 } else if (valueType === 'boolean') {
156 rules.push(value ? keyPrefix : symbol.negation + keyPrefixNonNegation);
157 } else {
158 throw new Error('Invalid rule type');
159 }
160 });
161 return rules;
162};
163
164Match.prototype.toString = function() {
165 return this.rules.map(rule => rule.toString()).join('\n')
166};
167
168
169exports = module.exports = Match;