UNPKG

2.69 kBJavaScriptView Raw
1const extend = require('./utils').extend;
2
3function isFlag(token) {
4 return token.slice(0, 1) === '[' && token.slice(-1) === ']';
5}
6function isAlternation(token) {
7 return token.slice(0, 1) === '(' && token.slice(-1) === ')';
8}
9function removeEmptyStrings(texts) {
10 return texts.filter(text => text !== '');
11}
12function createPermutations(tokens, index) {
13 if (index === tokens.length) {
14 return [{ text: '', flags: {}, alternations: [] }];
15 }
16
17 const token = tokens[index];
18 const tail = createPermutations(tokens, index + 1);
19 if (isFlag(token)) {
20 const flag = token.slice(1, -1);
21 return tail
22 .map(pattern => {
23 const flags = {};
24 flags[flag] = true;
25 return {
26 text: `${flag} ${pattern.text}`,
27 flags: extend(flags, pattern.flags),
28 alternations: pattern.alternations
29 };
30 })
31 .concat(
32 tail.map(pattern => {
33 const flags = {};
34 flags[flag] = false;
35 return {
36 text: pattern.text,
37 flags: extend(flags, pattern.flags),
38 alternations: pattern.alternations
39 };
40 })
41 );
42 } else if (isAlternation(token)) {
43 return token
44 .substr(1, token.length - 2) // Remove parentheses
45 .split(/\|/)
46 .reduce(
47 (result, alternation) =>
48 result.concat(
49 tail.map(({ text, flags, alternations }) => ({
50 // Make sure that an empty alternation doesn't produce two spaces:
51 text: alternation ? alternation + text : text.replace(/^ /, ''),
52
53 flags,
54 alternations: [alternation, ...alternations]
55 }))
56 ),
57 []
58 );
59 } else {
60 return tail.map(({ text, flags, alternations }) => ({
61 text: token + text,
62 flags,
63 alternations
64 }));
65 }
66}
67
68function expandAssertion(pattern) {
69 pattern = pattern.replace(/(\[[^\]]+\]) ?/g, '$1');
70 const splitRegex = /\[[^\]]+\]|\([^)]+\)/g;
71 let tokens = [];
72 let m;
73 let lastIndex = 0;
74 while ((m = splitRegex.exec(pattern))) {
75 tokens.push(pattern.slice(lastIndex, m.index));
76 tokens.push(pattern.slice(m.index, splitRegex.lastIndex));
77 lastIndex = splitRegex.lastIndex;
78 }
79 tokens.push(pattern.slice(lastIndex));
80 tokens = removeEmptyStrings(tokens);
81 const permutations = createPermutations(tokens, 0);
82 permutations.forEach(permutation => {
83 permutation.text = permutation.text.trim();
84 if (permutation.text === '') {
85 // This can only happen if the pattern only contains flags
86 throw new Error('Assertion patterns must not only contain flags');
87 }
88 });
89 return permutations;
90}
91
92module.exports = expandAssertion;