this repo has no description
at main 3.9 kB view raw
1{ 2 function makeCommand(action, selection, parts) { 3 4 const validParts = parts || []; 5 // Extract pure description (without attributes) 6 const description = validParts 7 .filter(part => part.type === 'text') 8 .map(part => part.value) 9 .join(' ') 10 .trim(); 11 12 // Collect all attributes 13 const attributes = validParts 14 .filter(part => part.type !== 'text') 15 .filter(part => part !== null); 16 17 const project = validParts 18 .filter(part => part.type === 'project') 19 .map(part => part.value) 20 .join('') 21 .trim(); 22 23 const tags = validParts 24 .filter(part => part.type === 'tag') 25 .map(part => part.value); 26 27 // Extract priority flag 28 const hasPriority = validParts.some(part => part.type === 'priority'); 29 30 // Extract due date 31 const dueDate = validParts 32 .filter(part => part.type === 'due') 33 .map(part => part.value)[0] || null; 34 35 return { 36 action: action, 37 selection: selection || [], 38 description: description || [], 39 attributes: attributes || [], 40 project: project, 41 tags: tags, 42 priority: hasPriority, 43 due: dueDate, 44 parts: parts || [], 45 reconstruct: function() { 46 const filterStr = this.filters.map(f => f.reconstruct()).join(','); 47 const partsStr = this.parts.map(p => p.reconstruct()).join(' '); 48 return [filterStr, this.type, partsStr].filter(Boolean).join(' '); 49 } 50 }; 51 } 52} 53 54Start = AddCommand / DoneCommand / ExplicitFilterCommand / ModifyCommand 55 56// ADD COMMAND 57AddCommand = selection:Selections? _? "add" _ parts:(Part / _)+ EOF { 58 return makeCommand('add', selection, parts.filter(p => p !== null)); 59} 60 61// DONE COMMAND 62DoneCommand = selection:Selections? _? "done" _? parts:(Part / _)* EOF { 63 return makeCommand('done', selection, parts.filter(p => p !== null)); 64} 65 66ExplicitFilterCommand = selection:Selections? _? "filter" _* moreFilters:Filters EOF { 67 return makeCommand('filter', selection, moreFilters); 68} 69 70ModifyCommand = selection:Selections? _? "modify" _* moreFilters:Filters EOF { 71 return makeCommand('modify', selection, moreFilters); 72} 73 74Filters = first:Part rest:(_ Part)* { 75 return [first, ...rest.map(r => r[1])]; 76} 77 78 79IdRange = start:Integer "-" end:Integer { 80 const ids = []; 81 for (let i = start; i <= end; i++) { 82 ids.push(i); 83 } 84 return ids; 85} 86 87SingleId = id:Integer { 88 return [id]; 89} 90 91Selections = first:Selection rest:(_ Selection)* { 92 return [first, ...rest.map(r => r[1])]; 93} 94 95Selection = IdFilter / Attribute 96 97IdFilter = first:(IdRange / SingleId) rest:("," (IdRange / SingleId))* trailing:"," ? { 98 const ids = [first, ...rest.map(r => r[1])].flat(); 99 return { 100 type: 'id', 101 ids: ids, 102 reconstruct: function() { return this.ids.join(','); } 103 }; 104} 105 106Part = Attribute / TextPart 107 108TextPart = chars:Word { 109 return { 110 type: "text", 111 value: chars, 112 reconstruct: function() { return this.value; } 113 }; 114} 115 116Attribute = Due / Tag / Project / Priority 117 118Due = ("due:" / "@") value:DateValue { 119 return { 120 type: "due", 121 value: value, 122 reconstruct: function() { return `@${this.value}`; } 123 }; 124} 125 126Project = ("pro:" / "project:" / "+") value:Word { 127 return { 128 type: "project", 129 value: value, 130 reconstruct: function() { return `+${this.value}`; } 131 }; 132} 133 134Priority = ("priority" / "!!") { 135 return { 136 type: "priority", 137 value: true, 138 reconstruct: function() { return `priority:${this.value}`; } 139 }; 140} 141 142Tag = "#" value:Word { 143 return { 144 type: "tag", 145 value: value, 146 reconstruct: function() { return `#${this.value}`; } 147 }; 148} 149 150Integer = digits:[0-9]+ { 151 return parseInt(digits.join(''), 10); 152} 153 154DateValue = chars:[0-9/-]+ { 155 return chars.join(''); 156} 157 158Word = chars:[a-zA-Z0-9_-]+ { 159 return chars.join(''); 160} 161 162_ = [ \t]+ { 163 return null; 164} 165 166EOF = !. 167 168