imdone-core 1.54.10 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.dependency-cruiser.cjs +412 -0
- package/.github/workflows/ci.yml +2 -2
- package/.imdoneignore +2 -1
- package/README.md +2 -2
- package/_index.md +7 -0
- package/build.js +57 -0
- package/esm-migration.md +446 -0
- package/lib/FileProjectContext.js +13 -0
- package/lib/ProjectContext.js +19 -18
- package/lib/adapters/date-time.js +3 -8
- package/lib/adapters/environment.js +3 -0
- package/lib/adapters/file-gateway.js +133 -106
- package/lib/adapters/git-download.js +36 -16
- package/lib/adapters/index.js +9 -0
- package/lib/adapters/logger.js +136 -0
- package/lib/adapters/markdown.js +31 -19
- package/lib/adapters/parsers/DateLanguageParser.js +11 -9
- package/lib/adapters/parsers/content-transformer.js +35 -30
- package/lib/adapters/parsers/file/LocalFileParserFactory.js +8 -9
- package/lib/adapters/parsers/file/ReadStreamCodeParser.js +8 -8
- package/lib/adapters/parsers/file/ReadStreamMarkdownParser.js +4 -4
- package/lib/adapters/parsers/file/ReadStreamTaskParser.js +5 -3
- package/lib/adapters/parsers/file/index.js +4 -0
- package/lib/adapters/parsers/function-parser.js +1 -5
- package/lib/adapters/parsers/index.js +5 -0
- package/lib/adapters/parsers/task/CardContentParser.js +23 -32
- package/lib/adapters/parsers/task/CheckStyleTaskParser.js +2 -2
- package/lib/adapters/parsers/task/CodeStyleTaskParser.js +2 -2
- package/lib/adapters/parsers/task/HashStyleTaskParser.js +3 -3
- package/lib/adapters/parsers/task/MarkdownStyleTaskParser.js +2 -2
- package/lib/adapters/parsers/task/TaskParser.js +1 -1
- package/lib/adapters/parsers/task/index.js +6 -0
- package/lib/adapters/storage/config.js +15 -20
- package/lib/adapters/storage/index.js +2 -0
- package/lib/adapters/storage/tags.js +11 -12
- package/lib/adapters/yaml.js +8 -5
- package/lib/card.js +25 -26
- package/lib/checksum.js +22 -0
- package/lib/cli.js +114 -0
- package/lib/config.js +106 -71
- package/lib/constants.js +21 -50
- package/lib/context/ApplicationContext.js +7 -4
- package/lib/context/index.js +1 -0
- package/lib/default-settings.js +3 -3
- package/lib/domain/entities/View.js +4 -11
- package/lib/domain/entities/index.js +1 -0
- package/lib/domain/index.js +2 -0
- package/lib/domain/usecases/GetViewsUsecase.js +6 -12
- package/lib/domain/usecases/SaveViewUsecase.js +8 -14
- package/lib/domain/usecases/index.js +2 -0
- package/lib/file.js +1158 -1162
- package/lib/get-tasks-to-modify.js +117 -0
- package/lib/index.js +23 -0
- package/lib/languages.js +4 -5
- package/lib/list.js +46 -95
- package/lib/migrate-config.js +5 -5
- package/lib/mixins/index.js +2 -0
- package/lib/mixins/repo-fs-store.js +224 -289
- package/lib/mixins/repo-watched-fs-store.js +158 -147
- package/lib/plugins/archive-plugin.js +10 -8
- package/lib/plugins/default-board-actions-plugin.js +2 -2
- package/lib/plugins/default-board-properties-plugin.js +7 -7
- package/lib/plugins/default-plugins.js +7 -0
- package/lib/plugins/epic-plugin.js +6 -5
- package/lib/plugins/extension-plugin.js +24 -17
- package/lib/plugins/index.js +9 -0
- package/lib/plugins/persist-tags-plugin.js +4 -3
- package/lib/plugins/plugin-manager.js +89 -52
- package/lib/plugins/plugin-registry.js +12 -16
- package/lib/project-factory.js +21 -24
- package/lib/project.js +97 -144
- package/lib/repository.js +1323 -1555
- package/lib/task.js +562 -580
- package/lib/tools.js +39 -113
- package/lib/usecases/actions.js +32 -0
- package/lib/usecases/get-project-tags.js +3 -12
- package/lib/usecases/get-tasks-in-file.js +4 -7
- package/lib/usecases/index.js +4 -0
- package/package.json +44 -66
- package/scripts/delete-markdown-indexes.js +87 -0
- package/scripts/generate-index.js +35 -0
- package/{index-markdown.js → scripts/index-markdown.js} +7 -7
- package/tsconfig.json +15 -0
- package/types/FileProjectContext.d.ts +4 -0
- package/types/ProjectContext.d.ts +9 -0
- package/types/adapters/date-time.d.ts +2 -0
- package/types/adapters/environment.d.ts +1 -0
- package/types/adapters/file-gateway.d.ts +51 -0
- package/types/adapters/git-download.d.ts +1 -0
- package/types/adapters/index.d.ts +9 -0
- package/types/adapters/logger.d.ts +24 -0
- package/types/adapters/markdown.d.ts +13 -0
- package/types/adapters/parsers/DateLanguageParser.d.ts +1 -0
- package/types/adapters/parsers/content-transformer.d.ts +10 -0
- package/types/adapters/parsers/file/LocalFileParserFactory.d.ts +5 -0
- package/types/adapters/parsers/file/ReadStreamCodeParser.d.ts +13 -0
- package/types/adapters/parsers/file/ReadStreamMarkdownParser.d.ts +7 -0
- package/types/adapters/parsers/file/ReadStreamTaskParser.d.ts +19 -0
- package/types/adapters/parsers/file/index.d.ts +4 -0
- package/types/adapters/parsers/function-parser.d.ts +1 -0
- package/types/adapters/parsers/index.d.ts +5 -0
- package/types/adapters/parsers/task/CardContentParser.d.ts +45 -0
- package/types/adapters/parsers/task/CheckStyleTaskParser.d.ts +12 -0
- package/types/adapters/parsers/task/CodeStyleTaskParser.d.ts +14 -0
- package/types/adapters/parsers/task/HashStyleTaskParser.d.ts +13 -0
- package/types/adapters/parsers/task/MarkdownStyleTaskParser.d.ts +14 -0
- package/types/adapters/parsers/task/TaskParser.d.ts +7 -0
- package/types/adapters/parsers/task/index.d.ts +6 -0
- package/types/adapters/storage/config.d.ts +6 -0
- package/types/adapters/storage/index.d.ts +2 -0
- package/types/adapters/storage/tags.d.ts +3 -0
- package/types/adapters/yaml.d.ts +2 -0
- package/types/card.d.ts +166 -0
- package/types/checksum.d.ts +8 -0
- package/types/config.d.ts +61 -0
- package/types/constants.d.ts +46 -0
- package/types/context/ApplicationContext.d.ts +24 -0
- package/types/context/index.d.ts +1 -0
- package/types/default-settings.d.ts +2 -0
- package/types/domain/entities/FileProjectContext.d.ts +5 -0
- package/types/domain/entities/View.d.ts +17 -0
- package/types/domain/entities/index.d.ts +1 -0
- package/types/domain/index.d.ts +2 -0
- package/types/domain/usecases/GetViewsUsecase.d.ts +4 -0
- package/types/domain/usecases/SaveViewUsecase.d.ts +8 -0
- package/types/domain/usecases/index.d.ts +2 -0
- package/types/file.d.ts +344 -0
- package/types/get-tasks-to-modify.d.ts +3 -0
- package/types/index.d.ts +23 -0
- package/types/languages.d.ts +649 -0
- package/types/list.d.ts +30 -0
- package/types/migrate-config.d.ts +1 -0
- package/types/mixins/index.d.ts +2 -0
- package/types/mixins/repo-fs-store.d.ts +2 -0
- package/types/mixins/repo-watched-fs-store.d.ts +2 -0
- package/types/plugins/archive-plugin.d.ts +8 -0
- package/types/plugins/default-board-actions-plugin.d.ts +9 -0
- package/types/plugins/default-board-properties-plugin.d.ts +16 -0
- package/types/plugins/default-plugins.d.ts +6 -0
- package/types/plugins/epic-plugin.d.ts +19 -0
- package/types/plugins/extension-plugin.d.ts +15 -0
- package/types/plugins/index.d.ts +9 -0
- package/types/plugins/persist-tags-plugin.d.ts +4 -0
- package/types/plugins/plugin-manager.d.ts +68 -0
- package/types/plugins/plugin-registry.d.ts +1 -0
- package/types/project-factory.d.ts +14 -0
- package/types/project.d.ts +158 -0
- package/types/repository.d.ts +996 -0
- package/types/task.d.ts +202 -0
- package/types/tools.d.ts +29 -0
- package/types/usecases/actions.d.ts +7 -0
- package/types/usecases/get-imdone-url.d.ts +1 -0
- package/types/usecases/get-project-tags.d.ts +1 -0
- package/types/usecases/get-tasks-in-file.d.ts +4 -0
- package/types/usecases/index.d.ts +4 -0
- package/vitest.config.js +13 -0
- package/cli.js +0 -74
- package/index.js +0 -1
- package/lib/adapters/readers/FileSystemProjectReader.js +0 -45
- package/lib/context/StreamingApplicationContext.js +0 -31
- package/lib/controlers/SaveViewController.js +0 -10
- package/lib/domain/entities/FileProjectContext.js +0 -10
- package/lib/domain/usecases/OpenProjectUsecase.js +0 -13
package/lib/repository.js
CHANGED
|
@@ -1,1746 +1,1514 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
1
|
+
import _isFunction from 'lodash.isfunction'
|
|
2
|
+
import _isUndefined from 'lodash.isundefined'
|
|
3
|
+
import _isString from 'lodash.isstring'
|
|
4
|
+
import _omit from 'lodash.omit'
|
|
5
|
+
import _reject from 'lodash.reject'
|
|
6
|
+
import _noop from 'lodash.noop'
|
|
7
|
+
import _some from 'lodash.some'
|
|
8
|
+
import _remove from 'lodash.remove'
|
|
9
|
+
import _groupBy from 'lodash.groupby'
|
|
10
|
+
import _where from 'lodash.where'
|
|
11
|
+
import _union from 'lodash.union'
|
|
12
|
+
import Emitter from 'events'
|
|
13
|
+
import { languages } from './languages.js'
|
|
14
|
+
import util from 'util'
|
|
15
|
+
import { parallel, eachLimit, eachSeries, series } from 'async'
|
|
16
|
+
import path from 'path'
|
|
17
|
+
import ignore from 'ignore'
|
|
18
|
+
import { File } from './file.js'
|
|
19
|
+
import eol from 'eol'
|
|
20
|
+
import { tools } from './tools.js'
|
|
21
|
+
const { inMixinsNoop } = tools
|
|
22
|
+
import { constants } from './constants.js'
|
|
23
|
+
import debug from 'debug'
|
|
24
|
+
const log = debug('imdone-core:Repository')
|
|
25
|
+
import { List } from './list.js'
|
|
26
|
+
import monquery from 'monquery'
|
|
27
|
+
import sift from 'sift'
|
|
28
|
+
import { sort } from 'fast-sort'
|
|
29
|
+
import JSONfns from 'json-fns'
|
|
30
|
+
import { Task } from './task.js'
|
|
31
|
+
import { newCard } from './card.js'
|
|
32
|
+
import { replaceDateLanguage } from './adapters/parsers/DateLanguageParser.js'
|
|
33
|
+
import { getRawTask, isNumber, LIST_NAME_PATTERN } from './adapters/parsers/task/CardContentParser.js'
|
|
34
|
+
import { interpolate } from './adapters/parsers/content-transformer.js'
|
|
35
|
+
import XRegExp from 'xregexp'
|
|
36
|
+
import { appContext } from './context/ApplicationContext.js'
|
|
37
|
+
import { computeChecksum } from './checksum.js'
|
|
38
|
+
import { getTasksToModify } from './get-tasks-to-modify.js'
|
|
39
|
+
import { logger } from './adapters/logger.js'
|
|
40
|
+
const { ERRORS, ASYNC_LIMIT, DEFAULT_FILE_PATTERN} = constants
|
|
41
|
+
const DEFAULT_SORT = [{ asc: u => isNumber(u.order) ? u.order : Infinity }, { asc: u => u.text }]
|
|
42
|
+
|
|
43
|
+
function getTasksByList (
|
|
44
|
+
repo,
|
|
45
|
+
tasksAry,
|
|
46
|
+
noSort,
|
|
47
|
+
populateFiltered
|
|
48
|
+
) {
|
|
49
|
+
if (!repo) return []
|
|
50
|
+
var tasks = {}
|
|
51
|
+
var allTasks = noSort ? tasksAry : sort(tasksAry).by(DEFAULT_SORT)
|
|
52
|
+
allTasks.forEach(function (task) {
|
|
53
|
+
if (!tasks[task.list]) tasks[task.list] = []
|
|
54
|
+
tasks[task.list].push(task)
|
|
55
|
+
})
|
|
56
|
+
var lists = repo.getLists()
|
|
57
|
+
lists.forEach((list) => {
|
|
58
|
+
if (list.filter && populateFiltered)
|
|
59
|
+
return Repository.populateFilteredList(list, tasksAry)
|
|
60
|
+
list.tasks = tasks[list.name] || []
|
|
61
|
+
})
|
|
62
|
+
return lists
|
|
63
|
+
}
|
|
48
64
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
function Repository(_path, config) {
|
|
60
|
-
var self = this
|
|
61
|
-
|
|
62
|
-
events.EventEmitter.call(this)
|
|
63
|
-
// path is the root path of the repository
|
|
64
|
-
this.config = config
|
|
65
|
-
this.path = _path
|
|
66
|
-
this.files = []
|
|
67
|
-
this.languages = languages
|
|
68
|
-
this.allMeta = {}
|
|
69
|
-
this.metaKeys = new Set()
|
|
70
|
-
this.allTags = new Set()
|
|
71
|
-
this.allTopics = new Set()
|
|
72
|
-
this.allContexts = new Set()
|
|
65
|
+
function populateFilteredList (list, tasks) {
|
|
66
|
+
try {
|
|
67
|
+
list.tasks = Repository.query(tasks, list.filter).map((task) => {
|
|
68
|
+
task.filteredListName = list.name
|
|
69
|
+
return task
|
|
70
|
+
})
|
|
71
|
+
} catch (e) {
|
|
72
|
+
list.tasks = []
|
|
73
|
+
}
|
|
73
74
|
}
|
|
74
75
|
|
|
75
|
-
|
|
76
|
+
function regexQuery (tasks, queryString) {
|
|
77
|
+
return tasks
|
|
78
|
+
.map((task) => {
|
|
79
|
+
const escapedQueryString = tools.escapeRegExp(queryString.trim());
|
|
76
80
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
}
|
|
81
|
+
// Regex to match occurrences not part of a URL and not already surrounded by `==`
|
|
82
|
+
const regex = new RegExp(
|
|
83
|
+
`(?<!https?:\\/\\/[^\\s]*?)\\b${escapedQueryString}\\b(?![^\\s]*\\/)(?<!==)(?!==)`,
|
|
84
|
+
'gi'
|
|
85
|
+
);
|
|
80
86
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
return cb(err)
|
|
87
|
-
}
|
|
88
|
-
this.config = config
|
|
89
|
-
this.files = []
|
|
90
|
-
this.allMeta = {}
|
|
91
|
-
this.metaKeys = new Set()
|
|
92
|
-
this.allTags = new Set()
|
|
93
|
-
this.allTopics = new Set()
|
|
94
|
-
this.allContexts = new Set()
|
|
95
|
-
this.readFiles((err, files) => {
|
|
96
|
-
if (err) {
|
|
97
|
-
this.emit('initialized', { ok: false })
|
|
98
|
-
return cb(err)
|
|
99
|
-
}
|
|
100
|
-
this.emit('initialized', { ok: true, lists: this.getTasksByList() })
|
|
101
|
-
if (cb) cb(err, files)
|
|
102
|
-
})
|
|
103
|
-
})
|
|
104
|
-
}
|
|
87
|
+
// Regex to detect Markdown links `[title](url)` where `queryString` is in title or URL
|
|
88
|
+
const markdownLinkRegex = new RegExp(
|
|
89
|
+
`\\[([^\\]]*${escapedQueryString}[^\\]]*)\\]\\(([^)]+${escapedQueryString}[^)]*)\\)`,
|
|
90
|
+
'gi'
|
|
91
|
+
);
|
|
105
92
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
* @method destroy
|
|
109
|
-
* @return
|
|
110
|
-
*/
|
|
111
|
-
Repository.prototype.destroy = function () {
|
|
112
|
-
this.destroyed = true
|
|
113
|
-
this.removeAllListeners()
|
|
114
|
-
}
|
|
93
|
+
let match = task.content.match(regex) || task.content.match(markdownLinkRegex);
|
|
94
|
+
task.match = match;
|
|
115
95
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
return this.getPath()
|
|
123
|
-
}
|
|
96
|
+
if (match && queryString.trim() && task.interpretedContent) {
|
|
97
|
+
// Replace standalone occurrences
|
|
98
|
+
task.interpretedContent = task.interpretedContent.replace(
|
|
99
|
+
regex,
|
|
100
|
+
'==$&=='
|
|
101
|
+
);
|
|
124
102
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
103
|
+
// Replace Markdown links where queryString is in title or URL
|
|
104
|
+
task.interpretedContent = task.interpretedContent.replace(
|
|
105
|
+
markdownLinkRegex,
|
|
106
|
+
(match) => `==${match}==`
|
|
107
|
+
);
|
|
128
108
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
}
|
|
109
|
+
task.updateDescriptionData();
|
|
110
|
+
}
|
|
132
111
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
}
|
|
112
|
+
return task;
|
|
113
|
+
})
|
|
114
|
+
.filter(({ match }) => match);
|
|
115
|
+
};
|
|
136
116
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
117
|
+
|
|
118
|
+
function parseHideListsFromQueryString (queryString) {
|
|
119
|
+
const hideLists = []
|
|
120
|
+
const regex = `hide:(\\s*((${LIST_NAME_PATTERN},?\\s?)+))?`
|
|
121
|
+
queryString = queryString.replaceAll(
|
|
122
|
+
// hide lists example `hide: list1, list2`
|
|
123
|
+
new XRegExp(regex, 'g'),
|
|
124
|
+
(match, allLists, lists) => {
|
|
125
|
+
lists && lists.split(',').forEach((list) => {
|
|
126
|
+
hideLists.push(list.trim())
|
|
127
|
+
})
|
|
128
|
+
return ''
|
|
145
129
|
}
|
|
146
|
-
|
|
147
|
-
|
|
130
|
+
).trim()
|
|
131
|
+
return {
|
|
132
|
+
hideLists,
|
|
133
|
+
queryString,
|
|
148
134
|
}
|
|
149
135
|
}
|
|
150
136
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
* @method createListeners
|
|
161
|
-
* @return
|
|
162
|
-
*/
|
|
163
|
-
Repository.prototype.createListeners = function () {
|
|
164
|
-
if (this.taskListener) return
|
|
165
|
-
var self = this
|
|
166
|
-
/**
|
|
167
|
-
* Description
|
|
168
|
-
* @method taskFoundListener
|
|
169
|
-
* @param {} task
|
|
170
|
-
* @return
|
|
171
|
-
*/
|
|
172
|
-
this.taskListener = function (event, task) {
|
|
173
|
-
if (!self.listExists(task.list) && self.config.includeList(task.list)) {
|
|
174
|
-
const list = new List({ name: task.list })
|
|
175
|
-
self.addList(list)
|
|
176
|
-
self.emit('list.found', list)
|
|
177
|
-
self.saveConfig()
|
|
137
|
+
function parseSortFromQueryString (queryString) {
|
|
138
|
+
const sort = []
|
|
139
|
+
queryString = queryString.replace(
|
|
140
|
+
/\s([+-])([A-Za-z.]+)/g,
|
|
141
|
+
(match, order, attr) => {
|
|
142
|
+
const direction = order === '+' ? 'asc' : 'desc'
|
|
143
|
+
const sortString = `{ "${direction}": "function (o) { return o.${attr};}" }`
|
|
144
|
+
sort.push(JSONfns.parse(sortString))
|
|
145
|
+
return ''
|
|
178
146
|
}
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
self.allMeta = self.addAllMeta(task.allMeta)
|
|
184
|
-
self.emit(event, task)
|
|
147
|
+
)
|
|
148
|
+
return {
|
|
149
|
+
sort,
|
|
150
|
+
queryString,
|
|
185
151
|
}
|
|
152
|
+
}
|
|
186
153
|
|
|
187
|
-
|
|
188
|
-
|
|
154
|
+
function parseSortFromMongoQuery (mongoQuery) {
|
|
155
|
+
const sort = []
|
|
156
|
+
for (const [key, value] of Object.entries(mongoQuery.sort)) {
|
|
157
|
+
if (value > 0) sort.push({ asc: key })
|
|
158
|
+
else sort.push({ desc: key })
|
|
189
159
|
}
|
|
160
|
+
return sort
|
|
161
|
+
}
|
|
190
162
|
|
|
191
|
-
|
|
192
|
-
|
|
163
|
+
// function sortByQuery (tasks, queryString = '') {
|
|
164
|
+
// queryString = replaceDateLanguage(queryString)
|
|
165
|
+
// let { sort } = Repository.parseSortFromQueryString(queryString)
|
|
166
|
+
// if (!sort || sort.length === 0) sort = DEFAULT_SORT
|
|
167
|
+
// sort(tasks).by(sort)
|
|
168
|
+
// }
|
|
169
|
+
|
|
170
|
+
function filterCards (tasks, _queryString = '') {
|
|
171
|
+
let query
|
|
172
|
+
_queryString = replaceDateLanguage(_queryString)
|
|
173
|
+
let { sort: userSort, queryString } = Repository.parseSortFromQueryString(_queryString);
|
|
174
|
+
const hideListsQuery = Repository.parseHideListsFromQueryString(queryString);
|
|
175
|
+
queryString = hideListsQuery.queryString;
|
|
176
|
+
const hideLists = hideListsQuery.hideLists;
|
|
177
|
+
try {
|
|
178
|
+
query = monquery(queryString)
|
|
179
|
+
} catch (e) {
|
|
180
|
+
log(`Unable to parse ${_queryString} using monquery`)
|
|
181
|
+
}
|
|
182
|
+
let result = []
|
|
183
|
+
if (query) result = tasks.filter(sift.default(query))
|
|
184
|
+
if (!query || result.length === 0) {
|
|
185
|
+
result = Repository.regexQuery(tasks, queryString)
|
|
186
|
+
}
|
|
187
|
+
if (!userSort || userSort.length === 0) userSort = DEFAULT_SORT
|
|
188
|
+
const sorted = sort(result).by(userSort)
|
|
189
|
+
return {
|
|
190
|
+
result: sorted,
|
|
191
|
+
query,
|
|
192
|
+
sort: userSort,
|
|
193
|
+
hideLists
|
|
193
194
|
}
|
|
194
195
|
}
|
|
195
196
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
197
|
+
function query (tasks, queryString) {
|
|
198
|
+
return Repository.filterCards(tasks, queryString).result
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function replaceDatesInQuery (query) {
|
|
202
|
+
return Repository.filterObjectValues(query, (key, value) => {
|
|
203
|
+
let date = Date.parse(value)
|
|
204
|
+
if (date && /(\d{4})-(\d{2})-(\d{2})/.test(value)) {
|
|
205
|
+
return date
|
|
202
206
|
}
|
|
203
|
-
|
|
207
|
+
return value
|
|
204
208
|
})
|
|
205
|
-
return allMeta
|
|
206
209
|
}
|
|
207
210
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
cb = tools.cb(cb);
|
|
216
|
-
if (this.listExists(list.name)) return cb();
|
|
217
|
-
|
|
218
|
-
try {
|
|
219
|
-
list = _omit(list, 'tasks');
|
|
220
|
-
this.config.lists.push(new List(list));
|
|
221
|
-
|
|
222
|
-
if (!list.filter && !/[a-z]/.test(list.name)) {
|
|
223
|
-
const codeList = list.name.replace(/\s+/g, '-').toUpperCase();
|
|
224
|
-
if (!this.config.code.include_lists.find((name) => name === codeList)) {
|
|
225
|
-
this.config.code.include_lists.push(codeList);
|
|
211
|
+
function filterObjectValues (o, cb) {
|
|
212
|
+
if (o && typeof o === 'object') {
|
|
213
|
+
for (const [key, value] of Object.entries(o)) {
|
|
214
|
+
if (value && typeof value === 'object') {
|
|
215
|
+
Repository.filterObjectValues(value, cb)
|
|
216
|
+
} else {
|
|
217
|
+
o[key] = cb(key, value)
|
|
226
218
|
}
|
|
227
219
|
}
|
|
220
|
+
}
|
|
221
|
+
return o
|
|
222
|
+
}
|
|
228
223
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
224
|
+
// Emits task.found, list.found, file.update and file.delete, file.processed, files.saved
|
|
225
|
+
export class Repository extends Emitter {
|
|
226
|
+
|
|
227
|
+
constructor(_path, config) {
|
|
228
|
+
super()
|
|
229
|
+
this.config = config
|
|
230
|
+
this.path = _path
|
|
231
|
+
this.files = []
|
|
232
|
+
this.languages = languages
|
|
233
|
+
this.allMeta = {}
|
|
234
|
+
this.metaKeys = new Set()
|
|
235
|
+
this.allTags = new Set()
|
|
236
|
+
this.allTopics = new Set()
|
|
237
|
+
this.allContexts = new Set()
|
|
234
238
|
}
|
|
235
|
-
};
|
|
236
239
|
|
|
237
|
-
|
|
238
|
-
return new Promise((resolve, reject) => {
|
|
239
|
-
var fn = (err) => {
|
|
240
|
-
if (err) return cb && cb(err) || reject(err)
|
|
241
|
-
this.emit('list.modified', list)
|
|
242
|
-
resolve()
|
|
243
|
-
}
|
|
244
|
-
if (!this.listExists(list)) return fn()
|
|
240
|
+
static getTasksByList = getTasksByList
|
|
245
241
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
}
|
|
250
|
-
this.setLists(lists)
|
|
251
|
-
this.saveConfig(fn)
|
|
252
|
-
})
|
|
253
|
-
}
|
|
242
|
+
static populateFilteredList = populateFilteredList
|
|
243
|
+
|
|
244
|
+
static regexQuery = regexQuery
|
|
254
245
|
|
|
255
|
-
|
|
256
|
-
* Description
|
|
257
|
-
* @method getPath
|
|
258
|
-
* @return MemberExpression
|
|
259
|
-
*/
|
|
260
|
-
Repository.prototype.getPath = function () {
|
|
261
|
-
return this.path
|
|
262
|
-
}
|
|
246
|
+
static parseHideListsFromQueryString = parseHideListsFromQueryString
|
|
263
247
|
|
|
264
|
-
|
|
265
|
-
* Description
|
|
266
|
-
* @method getConfig
|
|
267
|
-
* @return MemberExpression
|
|
268
|
-
*/
|
|
269
|
-
Repository.prototype.getConfig = function () {
|
|
270
|
-
return this.config
|
|
271
|
-
}
|
|
248
|
+
static parseSortFromQueryString = parseSortFromQueryString
|
|
272
249
|
|
|
273
|
-
|
|
274
|
-
* Description
|
|
275
|
-
* @method getLists
|
|
276
|
-
* @return MemberExpression
|
|
277
|
-
*/
|
|
278
|
-
Repository.prototype.getLists = function () {
|
|
279
|
-
const config = this.getConfig()
|
|
280
|
-
return config ? config.lists.map(obj => ({...obj})) : []
|
|
281
|
-
}
|
|
250
|
+
static parseSortFromMongoQuery = parseSortFromMongoQuery
|
|
282
251
|
|
|
283
|
-
|
|
284
|
-
return _reject(this.getLists(), 'hidden')
|
|
285
|
-
}
|
|
252
|
+
// static sortByQuery = sortByQuery
|
|
286
253
|
|
|
287
|
-
|
|
288
|
-
return this.getVisibleLists.find((list) => list.name === name)
|
|
289
|
-
}
|
|
254
|
+
static filterCards = filterCards
|
|
290
255
|
|
|
291
|
-
|
|
292
|
-
* Description
|
|
293
|
-
* @method setLists
|
|
294
|
-
* @param {} lists
|
|
295
|
-
* @return ThisExpression
|
|
296
|
-
*/
|
|
297
|
-
Repository.prototype.setLists = function (lists) {
|
|
298
|
-
this.config.lists = lists.map((list) => {
|
|
299
|
-
return new List(list)
|
|
300
|
-
})
|
|
301
|
-
return this
|
|
302
|
-
}
|
|
256
|
+
static query = query
|
|
303
257
|
|
|
304
|
-
|
|
305
|
-
* Description
|
|
306
|
-
* @method listExists
|
|
307
|
-
* @param {} name
|
|
308
|
-
* @return BinaryExpression
|
|
309
|
-
*/
|
|
310
|
-
Repository.prototype.listExists = function (name) {
|
|
311
|
-
return this.getConfig().listExists(name)
|
|
312
|
-
}
|
|
258
|
+
static replaceDatesInQuery = replaceDatesInQuery
|
|
313
259
|
|
|
314
|
-
|
|
315
|
-
* Save the config file (Implemented in mixins)
|
|
316
|
-
*
|
|
317
|
-
* @method saveConfig
|
|
318
|
-
* @param {} cb
|
|
319
|
-
* @return
|
|
320
|
-
*/
|
|
321
|
-
Repository.prototype.saveConfig = function (cb) {
|
|
322
|
-
inMixinsNoop(cb)
|
|
323
|
-
}
|
|
260
|
+
static filterObjectValues = filterObjectValues
|
|
324
261
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
* @method loadConfig
|
|
329
|
-
* @return MemberExpression
|
|
330
|
-
*/
|
|
331
|
-
Repository.prototype.loadConfig = function (cb) {
|
|
332
|
-
inMixinsNoop(cb)
|
|
333
|
-
}
|
|
262
|
+
init () {
|
|
263
|
+
inMixinsNoop()
|
|
264
|
+
}
|
|
334
265
|
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
this.
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
const tasks = fastSort(file.tasks).desc(u => u.line)
|
|
349
|
-
async.eachSeries(
|
|
350
|
-
tasks,
|
|
351
|
-
(task, cb) => {
|
|
352
|
-
if (!Task.isTask(task)) return cb()
|
|
353
|
-
task.replaceMetaSep(oldMetaSep, newMetaSep)
|
|
354
|
-
this.modifyTask(task, false, cb)
|
|
355
|
-
},
|
|
356
|
-
(err) => {
|
|
357
|
-
if (err) return cb(err)
|
|
358
|
-
if (!file.isModified() || file.getContent().trim() === '') return cb()
|
|
359
|
-
this.writeFile(file, (err, file) => {
|
|
360
|
-
this.resetFile(file)
|
|
361
|
-
if (err) return cb(err)
|
|
362
|
-
cb(null, file)
|
|
363
|
-
})
|
|
364
|
-
}
|
|
365
|
-
)
|
|
366
|
-
},
|
|
367
|
-
cb
|
|
368
|
-
)
|
|
369
|
-
}
|
|
266
|
+
// READY Refactor to use async/await
|
|
267
|
+
// #esm-migration #urgent #important
|
|
268
|
+
// <!--
|
|
269
|
+
// order:-240
|
|
270
|
+
// -->
|
|
271
|
+
async refresh () {
|
|
272
|
+
this.files = []
|
|
273
|
+
this.allMeta = {}
|
|
274
|
+
this.metaKeys = new Set()
|
|
275
|
+
this.allTags = new Set()
|
|
276
|
+
this.allTopics = new Set()
|
|
277
|
+
this.allContexts = new Set()
|
|
278
|
+
this.config.dirty = true
|
|
370
279
|
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
var fullPath = path.join(this.path, file)
|
|
383
|
-
return fullPath
|
|
384
|
-
} catch (e) {
|
|
385
|
-
throw new Error(
|
|
386
|
-
util.format(
|
|
387
|
-
'Error getting full path for file:%s and repo path:%s',
|
|
388
|
-
file,
|
|
389
|
-
this.path
|
|
390
|
-
)
|
|
391
|
-
)
|
|
280
|
+
let files = await this.getFilesInPath(false)
|
|
281
|
+
try {
|
|
282
|
+
const config = await this.loadConfig()
|
|
283
|
+
this.config = config
|
|
284
|
+
files = await this.readFiles()
|
|
285
|
+
this.emit('initialized', { ok: true, lists: this.getTasksByList() })
|
|
286
|
+
} catch (err) {
|
|
287
|
+
this.emit('initialized', { ok: false })
|
|
288
|
+
throw err
|
|
289
|
+
}
|
|
290
|
+
return files
|
|
392
291
|
}
|
|
393
|
-
}
|
|
394
292
|
|
|
395
|
-
/**
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
if (path.sep === '\\') {
|
|
404
|
-
fullPath = fullPath.replace(/\//g, path.sep)
|
|
405
|
-
}
|
|
406
|
-
if (!fullPath.startsWith(this.path)) return fullPath
|
|
407
|
-
try {
|
|
408
|
-
var relPath = path.relative(this.path, fullPath)
|
|
409
|
-
return relPath
|
|
410
|
-
} catch (e) {
|
|
411
|
-
throw new Error(
|
|
412
|
-
util.format(
|
|
413
|
-
'Error getting relative path for file:%s and repo path:%s',
|
|
414
|
-
fullPath,
|
|
415
|
-
this.path
|
|
416
|
-
)
|
|
417
|
-
)
|
|
293
|
+
/**
|
|
294
|
+
* Description
|
|
295
|
+
* @method destroy
|
|
296
|
+
* @return
|
|
297
|
+
*/
|
|
298
|
+
async destroy () {
|
|
299
|
+
this.destroyed = true
|
|
300
|
+
this.removeAllListeners()
|
|
418
301
|
}
|
|
419
|
-
}
|
|
420
302
|
|
|
421
|
-
/**
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
Repository.prototype.fileOK = function (file, includeDirs, cb) {
|
|
430
|
-
if (_isFunction(includeDirs)) cb = includeDirs
|
|
431
|
-
cb(null, true)
|
|
432
|
-
}
|
|
303
|
+
/**
|
|
304
|
+
* Description
|
|
305
|
+
* @method getId
|
|
306
|
+
* @return CallExpression
|
|
307
|
+
*/
|
|
308
|
+
getId () {
|
|
309
|
+
return this.getPath()
|
|
310
|
+
}
|
|
433
311
|
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
this.ignore = ignore().add(ignores)
|
|
438
|
-
}
|
|
312
|
+
getProject () {
|
|
313
|
+
return this.project
|
|
314
|
+
}
|
|
439
315
|
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
*
|
|
443
|
-
* @method shouldInclude
|
|
444
|
-
* @param {} relPath
|
|
445
|
-
* @return exclude
|
|
446
|
-
*/
|
|
447
|
-
Repository.prototype.shouldInclude = function (relPath) {
|
|
448
|
-
relPath = this.getRelativePath(relPath)
|
|
449
|
-
let include = true
|
|
450
|
-
if (this.config.markdownOnly && relPath) {
|
|
451
|
-
include = File.isMarkdown(relPath)
|
|
452
|
-
}
|
|
453
|
-
if (this.ignore) {
|
|
454
|
-
try {
|
|
455
|
-
include = include && (relPath === '' || !this.ignore.ignores(relPath))
|
|
456
|
-
} catch (e) {
|
|
457
|
-
console.error(
|
|
458
|
-
`Failed to check ignore status for dir: [${relPath}] in: [${this.path}]. It will be included.`,
|
|
459
|
-
e
|
|
460
|
-
)
|
|
461
|
-
}
|
|
316
|
+
getDisplayName () {
|
|
317
|
+
return path.basename(this.path)
|
|
462
318
|
}
|
|
463
319
|
|
|
464
|
-
|
|
465
|
-
|
|
320
|
+
emitFileUpdate (file, force) {
|
|
321
|
+
if (force || this.shouldEmitFileUpdate(file)) this.emit('file.update', file)
|
|
322
|
+
}
|
|
466
323
|
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
* @param {} file
|
|
472
|
-
* @return MemberExpression
|
|
473
|
-
*/
|
|
474
|
-
Repository.prototype.addFile = function (file, cb) {
|
|
475
|
-
if (this.destroyed) return cb(new Error('destroyed'))
|
|
476
|
-
var self = this
|
|
477
|
-
this.fileOK(file, function (err, ok) {
|
|
478
|
-
if (err) return cb(err)
|
|
479
|
-
if (ok) {
|
|
480
|
-
var index = self.files.findIndex(({ path }) => path === file.path)
|
|
324
|
+
shouldEmitFileUpdate (file) {
|
|
325
|
+
if (this.moving) return
|
|
326
|
+
if (this.lastMovedFiles) {
|
|
327
|
+
var index = this.lastMovedFiles.indexOf(file)
|
|
481
328
|
if (index > -1) {
|
|
482
|
-
|
|
329
|
+
this.lastMovedFiles.splice(index, 1)
|
|
483
330
|
} else {
|
|
484
|
-
|
|
331
|
+
if (file && file.updated) return true
|
|
485
332
|
}
|
|
333
|
+
} else {
|
|
334
|
+
if (file && file.updated) return true
|
|
486
335
|
}
|
|
487
|
-
|
|
488
|
-
})
|
|
489
|
-
}
|
|
490
|
-
|
|
491
|
-
/**
|
|
492
|
-
* Remove a file from the files refrence array
|
|
493
|
-
*
|
|
494
|
-
* @method removeFile
|
|
495
|
-
* @param {} file
|
|
496
|
-
* @return MemberExpression
|
|
497
|
-
*/
|
|
498
|
-
Repository.prototype.removeFile = function (file) {
|
|
499
|
-
if (!File.isFile(file)) throw new Error(ERRORS.NOT_A_FILE)
|
|
500
|
-
_remove(this.files, f => f.path === file.path)
|
|
501
|
-
|
|
502
|
-
return this.files
|
|
503
|
-
}
|
|
504
|
-
|
|
505
|
-
/**
|
|
506
|
-
* Description
|
|
507
|
-
* @method getFile
|
|
508
|
-
* @param {} path
|
|
509
|
-
* @return CallExpression
|
|
510
|
-
*/
|
|
511
|
-
Repository.prototype.getFile = function (path) {
|
|
512
|
-
path = this.getRelativePath(path)
|
|
513
|
-
return this.files.find((file) => file.path === path)
|
|
514
|
-
}
|
|
336
|
+
}
|
|
515
337
|
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
return this.getTasks().find((existingTask) => {
|
|
521
|
-
return existingTask.meta.id && existingTask.meta.id[0] == task.meta.id[0]
|
|
338
|
+
emitConfigUpdate (data) {
|
|
339
|
+
if (this.savingConfig) return
|
|
340
|
+
process.nextTick(() => {
|
|
341
|
+
this.emit('config.update', data)
|
|
522
342
|
})
|
|
523
|
-
} else {
|
|
524
|
-
let task = this.getTasks().find((task) => task.id === id)
|
|
525
|
-
if (!task) return
|
|
526
|
-
return this.getFile(task.source.path)
|
|
527
|
-
.getTasks()
|
|
528
|
-
.find((task) => task.id === id)
|
|
529
343
|
}
|
|
530
|
-
}
|
|
531
|
-
|
|
532
|
-
/**
|
|
533
|
-
* Description
|
|
534
|
-
* @method getFileForTask
|
|
535
|
-
* @param {} task
|
|
536
|
-
* @return CallExpression
|
|
537
|
-
*/
|
|
538
|
-
Repository.prototype.getFileForTask = function (task) {
|
|
539
|
-
return this.getFile(task.getSource().path)
|
|
540
|
-
}
|
|
541
|
-
|
|
542
|
-
/**
|
|
543
|
-
* Descriptione
|
|
544
|
-
* @method getFiles
|
|
545
|
-
* @param {} paths
|
|
546
|
-
* @return CallExpression
|
|
547
|
-
*/
|
|
548
|
-
Repository.prototype.getFiles = function (paths) {
|
|
549
|
-
if (_isUndefined(paths)) return fastSort(this.files).asc(u => u.path)
|
|
550
|
-
return this.files.filter((file) => {
|
|
551
|
-
return paths.includes(file.path)
|
|
552
|
-
})
|
|
553
|
-
}
|
|
554
344
|
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
345
|
+
// READY Refactor createListeners to use async/await
|
|
346
|
+
// #esm-migration
|
|
347
|
+
// <!--
|
|
348
|
+
// order:-120
|
|
349
|
+
// -->
|
|
350
|
+
createListeners () {
|
|
351
|
+
if (this.taskListener) return
|
|
352
|
+
|
|
353
|
+
this.taskListener = async (event, task) => {
|
|
354
|
+
if (!this.listExists(task.list) && this.config.includeList(task.list)) {
|
|
355
|
+
const list = new List({ name: task.list })
|
|
356
|
+
await this.addList(list)
|
|
357
|
+
this.emit('list.found', list)
|
|
358
|
+
await this.saveConfig()
|
|
359
|
+
}
|
|
360
|
+
Object.keys(task.allMeta).forEach(key => this.metaKeys.add(key))
|
|
361
|
+
task.topics.forEach(topic => this.allTopics.add(topic))
|
|
362
|
+
task.allTags.forEach(tag => this.allTags.add(tag))
|
|
363
|
+
task.allContext.forEach(context => this.allContexts.add(context))
|
|
364
|
+
this.allMeta = this.addAllMeta(task.allMeta)
|
|
365
|
+
this.emit(event, task)
|
|
366
|
+
}
|
|
559
367
|
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
file.removeListener('task.modified', this.taskModifiedListener)
|
|
564
|
-
}
|
|
368
|
+
this.taskFoundListener = (task) => {
|
|
369
|
+
this.taskListener('task.found', task)
|
|
370
|
+
}
|
|
565
371
|
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
var self = this
|
|
569
|
-
var extract = (file) => {
|
|
570
|
-
file.on('task.found', self.taskFoundListener)
|
|
571
|
-
file.on('task.modified', self.taskModifiedListener)
|
|
572
|
-
const fileContent = file.content
|
|
573
|
-
file.extractAndTransformTasks(self.getConfig())
|
|
574
|
-
if (!file.isModified() || fileContent === file.content) {
|
|
575
|
-
this.resetFile(file)
|
|
576
|
-
return cb(null, file)
|
|
372
|
+
this.taskModifiedListener = (task) => {
|
|
373
|
+
this.taskListener('task.modified', task)
|
|
577
374
|
}
|
|
578
|
-
file.extractTasks(self.getConfig())
|
|
579
|
-
self.writeFile(file, (err, file) => {
|
|
580
|
-
this.resetFile(file)
|
|
581
|
-
if (err) return cb(err)
|
|
582
|
-
cb(null, file)
|
|
583
|
-
})
|
|
584
375
|
}
|
|
585
376
|
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
377
|
+
addAllMeta (meta) {
|
|
378
|
+
const allMeta = Object.assign({}, this.allMeta)
|
|
379
|
+
Object.keys(meta).forEach((key) => {
|
|
380
|
+
if (!allMeta[key]) {
|
|
381
|
+
allMeta[key] = meta[key]
|
|
382
|
+
return
|
|
383
|
+
}
|
|
384
|
+
allMeta[key] = _union(allMeta[key], meta[key])
|
|
590
385
|
})
|
|
591
|
-
|
|
592
|
-
}
|
|
593
|
-
|
|
594
|
-
/**
|
|
595
|
-
* Implemented in mixins
|
|
596
|
-
* @method writeFile
|
|
597
|
-
* @param {} file
|
|
598
|
-
* @param {} cb
|
|
599
|
-
* @return
|
|
600
|
-
*/
|
|
601
|
-
Repository.prototype.writeFile = function (file, cb) {
|
|
602
|
-
inMixinsNoop(cb)
|
|
603
|
-
}
|
|
604
|
-
|
|
605
|
-
/**
|
|
606
|
-
* Implemented in mixins
|
|
607
|
-
* @method getFilesInPath
|
|
608
|
-
* @param {} includeDirs
|
|
609
|
-
* @return CallExpression
|
|
610
|
-
*/
|
|
611
|
-
|
|
612
|
-
Repository.prototype.getFilesInPath = function (includeDirs, cb) {
|
|
613
|
-
inMixinsNoop(cb)
|
|
614
|
-
}
|
|
386
|
+
return allMeta
|
|
387
|
+
}
|
|
615
388
|
|
|
616
|
-
/**
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
inMixinsNoop(cb)
|
|
625
|
-
}
|
|
389
|
+
/**
|
|
390
|
+
* Description
|
|
391
|
+
* @method addList
|
|
392
|
+
* @param {} list
|
|
393
|
+
* @return
|
|
394
|
+
*/
|
|
395
|
+
async addList (list) {
|
|
396
|
+
if (this.listExists(list.name)) return;
|
|
626
397
|
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
* @method readFile
|
|
630
|
-
* @param {} file
|
|
631
|
-
* @param {} cb
|
|
632
|
-
* @return
|
|
633
|
-
*/
|
|
634
|
-
Repository.prototype.readFile = function (file, cb) {
|
|
635
|
-
const checksum = this.checksum || function () {}
|
|
636
|
-
cb = tools.cb(cb)
|
|
637
|
-
if (!File.isFile(file)) return cb(new Error(ERRORS.NOT_A_FILE))
|
|
638
|
-
if (file.deleted) return cb(null, file)
|
|
639
|
-
var self = this
|
|
640
|
-
|
|
641
|
-
var currentChecksum = file.checksum
|
|
642
|
-
const filePath = file.path
|
|
643
|
-
if (!/\.\.(\/|\\)/.test(filePath)) {
|
|
644
|
-
this.readFileContent(file, (err, file) => {
|
|
645
|
-
if (err) return cb(new Error('Unable to read file:' + filePath))
|
|
646
|
-
// BACKLOG Allow user to assign a module for content transformation
|
|
647
|
-
// <!--
|
|
648
|
-
// order:-800
|
|
649
|
-
// -->
|
|
650
|
-
file.checksum = checksum(file.getContent())
|
|
651
|
-
file.updated = currentChecksum !== file.checksum
|
|
652
|
-
if (file.updated)
|
|
653
|
-
self.extractTasks(file, (err) => {
|
|
654
|
-
if (err) return cb(err)
|
|
655
|
-
self.addFile(file, (err) => {
|
|
656
|
-
if (err) log('error:', err)
|
|
657
|
-
log(`File added. repo: ${self.getPath()} file-path: ${file.path}`)
|
|
658
|
-
if (err) return cb(err)
|
|
659
|
-
cb(null, file)
|
|
660
|
-
})
|
|
661
|
-
})
|
|
662
|
-
else cb(null, file)
|
|
663
|
-
})
|
|
664
|
-
} else return cb(new Error('Unable to read file:' + file))
|
|
665
|
-
}
|
|
398
|
+
list = _omit(list, 'tasks');
|
|
399
|
+
this.config.lists.push(new List(list));
|
|
666
400
|
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
* @param {} cb
|
|
672
|
-
* @return
|
|
673
|
-
*/
|
|
674
|
-
Repository.prototype.readFiles = function (files, cb) {
|
|
675
|
-
if (arguments.length === 0) {
|
|
676
|
-
cb = _noop
|
|
677
|
-
files = undefined
|
|
678
|
-
} else if (_isFunction(files)) {
|
|
679
|
-
cb = files
|
|
680
|
-
files = undefined
|
|
681
|
-
} else if (files && !Array.isArray(files))
|
|
682
|
-
return cb(new Error('files must be an array of files or undefined'))
|
|
683
|
-
|
|
684
|
-
cb = tools.cb(cb)
|
|
685
|
-
|
|
686
|
-
var self = this
|
|
687
|
-
|
|
688
|
-
this.allMeta = {}
|
|
689
|
-
this.metaKeys = new Set()
|
|
690
|
-
this.allTags = new Set()
|
|
691
|
-
this.allContexts = new Set()
|
|
692
|
-
|
|
693
|
-
var exec = function (files) {
|
|
694
|
-
var completed = 0
|
|
695
|
-
if (files.length < 1) return cb(null, [])
|
|
696
|
-
async.eachLimit(
|
|
697
|
-
files,
|
|
698
|
-
ASYNC_LIMIT,
|
|
699
|
-
function (file, cb) {
|
|
700
|
-
self.emit('file.reading', { path: file.path })
|
|
701
|
-
self.readFile(file, function (err, file) {
|
|
702
|
-
if (err) return cb(err)
|
|
703
|
-
completed++
|
|
704
|
-
self.emit('file.read', {
|
|
705
|
-
path: file.path,
|
|
706
|
-
completed: completed,
|
|
707
|
-
})
|
|
708
|
-
cb()
|
|
709
|
-
})
|
|
710
|
-
},
|
|
711
|
-
function (err) {
|
|
712
|
-
cb(err, files)
|
|
401
|
+
if (!list.filter && !/[a-z]/.test(list.name)) {
|
|
402
|
+
const codeList = list.name.replace(/\s+/g, '-').toUpperCase();
|
|
403
|
+
if (!this.config.code.include_lists.find((name) => name === codeList)) {
|
|
404
|
+
this.config.code.include_lists.push(codeList);
|
|
713
405
|
}
|
|
714
|
-
)
|
|
715
|
-
}
|
|
716
|
-
|
|
717
|
-
if (files === undefined) {
|
|
718
|
-
if (this.files && this.files.length > 0) {
|
|
719
|
-
exec(this.files)
|
|
720
|
-
} else {
|
|
721
|
-
this.getFilesInPath(false, (err, files) => {
|
|
722
|
-
if (err) return cb(err)
|
|
723
|
-
self.files = files
|
|
724
|
-
const filesToInclude = files.map((file) => file.path)
|
|
725
|
-
const fileStats = {
|
|
726
|
-
count: filesToInclude.length,
|
|
727
|
-
files: filesToInclude,
|
|
728
|
-
}
|
|
729
|
-
this.emit('files.found', fileStats)
|
|
730
|
-
exec(files)
|
|
731
|
-
})
|
|
732
406
|
}
|
|
733
|
-
} else exec(files)
|
|
734
|
-
}
|
|
735
|
-
|
|
736
|
-
/**
|
|
737
|
-
* Implemented in mixins
|
|
738
|
-
* @method deleteFile
|
|
739
|
-
* @param {} path
|
|
740
|
-
* @param {} cb
|
|
741
|
-
* @return
|
|
742
|
-
*/
|
|
743
|
-
Repository.prototype.deleteFile = function (path, cb) {
|
|
744
|
-
inMixinsNoop(cb)
|
|
745
|
-
}
|
|
746
|
-
|
|
747
|
-
/**
|
|
748
|
-
* Description
|
|
749
|
-
* @method hasDefaultFile
|
|
750
|
-
* @return CallExpression
|
|
751
|
-
*/
|
|
752
|
-
Repository.prototype.hasDefaultFile = function () {
|
|
753
|
-
return _some(this.getFiles(), function (file) {
|
|
754
|
-
var regex = new RegExp(DEFAULT_FILE_PATTERN, 'i')
|
|
755
|
-
return regex.test(file.path)
|
|
756
|
-
})
|
|
757
|
-
}
|
|
758
|
-
|
|
759
|
-
/**
|
|
760
|
-
* Description
|
|
761
|
-
* @method getDefaultFile
|
|
762
|
-
* @return file
|
|
763
|
-
*/
|
|
764
|
-
Repository.prototype.getDefaultFile = function () {
|
|
765
|
-
var files = fastSort(this.getFiles()).asc(u => u.path)
|
|
766
|
-
var file = files.reverse().find((file) => {
|
|
767
|
-
var regex = new RegExp(DEFAULT_FILE_PATTERN, 'i')
|
|
768
|
-
return regex.test(file.path)
|
|
769
|
-
})
|
|
770
|
-
return file
|
|
771
|
-
}
|
|
772
|
-
|
|
773
|
-
Repository.prototype.getList = function (name) {
|
|
774
|
-
return this.getLists().find((list) => list.name === name)
|
|
775
|
-
}
|
|
776
407
|
|
|
408
|
+
await this.saveConfig()
|
|
409
|
+
this.emit('list.modified', list);
|
|
410
|
+
};
|
|
777
411
|
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
412
|
+
// READY Refactor removeList to use async/await
|
|
413
|
+
// #esm-migration
|
|
414
|
+
// <!--
|
|
415
|
+
// order:-220
|
|
416
|
+
// -->
|
|
417
|
+
async removeList (list) {
|
|
418
|
+
if (!this.listExists(list)) return
|
|
781
419
|
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
420
|
+
var lists = _reject(this.getLists(), { name: list })
|
|
421
|
+
if (this.config.code && this.config.code.include_lists) {
|
|
422
|
+
this.config.code.include_lists = _reject(this.config.code.include_lists, list)
|
|
423
|
+
}
|
|
424
|
+
this.setLists(lists)
|
|
425
|
+
await this.saveConfig()
|
|
426
|
+
this.emit('list.modified', list)
|
|
788
427
|
}
|
|
789
428
|
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
429
|
+
/**
|
|
430
|
+
* Description
|
|
431
|
+
* @method getPath
|
|
432
|
+
* @return MemberExpression
|
|
433
|
+
*/
|
|
434
|
+
getPath () {
|
|
435
|
+
return this.path
|
|
436
|
+
}
|
|
796
437
|
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
438
|
+
/**
|
|
439
|
+
* Description
|
|
440
|
+
* @method getConfig
|
|
441
|
+
* @return MemberExpression
|
|
442
|
+
*/
|
|
443
|
+
getConfig () {
|
|
444
|
+
return this.config
|
|
803
445
|
}
|
|
804
446
|
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
447
|
+
/**
|
|
448
|
+
* Description
|
|
449
|
+
* @method getLists
|
|
450
|
+
* @return MemberExpression
|
|
451
|
+
*/
|
|
452
|
+
getLists () {
|
|
453
|
+
const config = this.getConfig()
|
|
454
|
+
return config ? config.lists.map(obj => ({...obj})) : []
|
|
455
|
+
}
|
|
811
456
|
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
* @param {} name
|
|
816
|
-
* @param {} pos
|
|
817
|
-
* @param {} cb
|
|
818
|
-
* @return
|
|
819
|
-
*/
|
|
820
|
-
Repository.prototype.moveList = function (name, pos, cb) {
|
|
821
|
-
var self = this
|
|
822
|
-
cb = tools.cb(cb)
|
|
823
|
-
var list = this.getList(name)
|
|
824
|
-
// Only modify the lists if the list name exists
|
|
825
|
-
var fn = function (err) {
|
|
826
|
-
if (!err) self.emit('list.modified', name)
|
|
827
|
-
cb(err)
|
|
828
|
-
}
|
|
829
|
-
|
|
830
|
-
if (list) {
|
|
831
|
-
_remove(this.getLists(), { name: name })
|
|
832
|
-
this.getLists().splice(pos, 0, list)
|
|
833
|
-
this.saveConfig(fn)
|
|
834
|
-
} else cb()
|
|
835
|
-
}
|
|
457
|
+
getVisibleLists () {
|
|
458
|
+
return _reject(this.getLists(), 'hidden')
|
|
459
|
+
}
|
|
836
460
|
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
var list = this.getList(name)
|
|
841
|
-
if (!list) return reject(new Error('List not found'))
|
|
842
|
-
list.ignore = !list.ignore
|
|
843
|
-
await this.updateList(list.id, list)
|
|
844
|
-
this.saveConfig((err) => {
|
|
845
|
-
if (err) reject(err)
|
|
846
|
-
self.emit('list.modified', name)
|
|
847
|
-
resolve()
|
|
848
|
-
})
|
|
849
|
-
});
|
|
850
|
-
}
|
|
461
|
+
isListVisible (name) {
|
|
462
|
+
return this.getVisibleLists.find((list) => list.name === name)
|
|
463
|
+
}
|
|
851
464
|
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
this.
|
|
860
|
-
|
|
861
|
-
self.emit('list.modified', name)
|
|
862
|
-
resolve()
|
|
465
|
+
/**
|
|
466
|
+
* Description
|
|
467
|
+
* @method setLists
|
|
468
|
+
* @param {} lists
|
|
469
|
+
* @return ThisExpression
|
|
470
|
+
*/
|
|
471
|
+
setLists (lists) {
|
|
472
|
+
this.config.lists = lists.map((list) => {
|
|
473
|
+
return new List(list)
|
|
863
474
|
})
|
|
864
|
-
|
|
865
|
-
}
|
|
866
|
-
|
|
867
|
-
Repository.prototype.updateList = function(id, {name, hidden, ignore, filter}) {
|
|
868
|
-
return new Promise((resolve, reject) => {
|
|
869
|
-
const lists = this.getLists()
|
|
870
|
-
const list = this.getListById(id, lists)
|
|
871
|
-
const oldName = list.name
|
|
872
|
-
const hasFilter = list.filter
|
|
873
|
-
list.name = name
|
|
874
|
-
list.hidden = hidden
|
|
875
|
-
list.ignore = ignore
|
|
876
|
-
if (hasFilter !== undefined) list.filter = filter
|
|
877
|
-
this.setLists(lists)
|
|
878
|
-
|
|
879
|
-
if (oldName === name || hasFilter) {
|
|
880
|
-
this.saveConfig(err => {
|
|
881
|
-
if (err) return reject(err)
|
|
882
|
-
resolve()
|
|
883
|
-
})
|
|
884
|
-
} else {
|
|
885
|
-
this.moveTasksBetweenLists(oldName, name, err => {
|
|
886
|
-
if (err) return reject(err)
|
|
887
|
-
resolve()
|
|
888
|
-
})
|
|
889
|
-
}
|
|
890
|
-
})
|
|
891
|
-
}
|
|
892
|
-
|
|
893
|
-
Repository.prototype.moveTasksBetweenLists = function(oldName, newName, cb) {
|
|
894
|
-
cb = tools.cb(cb)
|
|
895
|
-
// Modify the tasks
|
|
896
|
-
const tasksToModify = this.getTasksInList(oldName)
|
|
475
|
+
return this
|
|
476
|
+
}
|
|
897
477
|
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
478
|
+
/**
|
|
479
|
+
* Description
|
|
480
|
+
* @method listExists
|
|
481
|
+
* @param {} name
|
|
482
|
+
* @return BinaryExpression
|
|
483
|
+
*/
|
|
484
|
+
listExists (name) {
|
|
485
|
+
return this.getConfig().listExists(name)
|
|
905
486
|
}
|
|
906
487
|
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
return (cb) => {
|
|
917
|
-
this.readFileContent(file, (err) => {
|
|
918
|
-
if (err) return cb(err)
|
|
919
|
-
try {
|
|
920
|
-
tasks.forEach((task) => {
|
|
921
|
-
task.list = newName
|
|
922
|
-
file.modifyTask(task, this.getConfig(), true)
|
|
923
|
-
})
|
|
924
|
-
} catch (err) {
|
|
925
|
-
return cb(err)
|
|
926
|
-
}
|
|
927
|
-
cb()
|
|
928
|
-
})
|
|
929
|
-
}
|
|
930
|
-
})
|
|
488
|
+
/**
|
|
489
|
+
* Save the config file (Implemented in mixins)
|
|
490
|
+
*
|
|
491
|
+
* @method saveConfig
|
|
492
|
+
* @return
|
|
493
|
+
*/
|
|
494
|
+
async saveConfig () {
|
|
495
|
+
inMixinsNoop()
|
|
496
|
+
}
|
|
931
497
|
|
|
932
|
-
|
|
498
|
+
/**
|
|
499
|
+
* Load the config file (Implemented in mixins)
|
|
500
|
+
*
|
|
501
|
+
* @method loadConfig
|
|
502
|
+
* @return MemberExpression
|
|
503
|
+
*/
|
|
504
|
+
// READY Refactor loadConfig to use async/await
|
|
505
|
+
// #esm-migration #urgent
|
|
933
506
|
// <!--
|
|
934
|
-
// order:-
|
|
507
|
+
// order:-160
|
|
935
508
|
// -->
|
|
509
|
+
async loadConfig () {
|
|
510
|
+
inMixinsNoop()
|
|
511
|
+
}
|
|
936
512
|
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
513
|
+
async migrateTasksByConfig (oldConfig, newConfig) {
|
|
514
|
+
return new Promise((resolve, reject) => {
|
|
515
|
+
if (!oldConfig || !newConfig) return resolve()
|
|
516
|
+
const oldMetaSep = oldConfig.getMetaSep()
|
|
517
|
+
const newMetaSep = newConfig.getMetaSep()
|
|
518
|
+
if (oldMetaSep === newMetaSep) return resolve()
|
|
519
|
+
eachLimit(
|
|
520
|
+
this.getFiles(),
|
|
521
|
+
ASYNC_LIMIT,
|
|
522
|
+
(file, cb) => {
|
|
523
|
+
const tasks = sort(file.tasks).desc(u => u.line)
|
|
524
|
+
eachSeries(
|
|
525
|
+
tasks,
|
|
526
|
+
async (task, cb) => {
|
|
527
|
+
if (!Task.isTask(task)) return cb()
|
|
528
|
+
try {
|
|
529
|
+
task.replaceMetaSep(oldMetaSep, newMetaSep)
|
|
530
|
+
await this.modifyTask(task, false)
|
|
531
|
+
cb()
|
|
532
|
+
} catch (err) {
|
|
533
|
+
cb(err)
|
|
534
|
+
}
|
|
535
|
+
},
|
|
536
|
+
async (err) => {
|
|
537
|
+
if (err) return cb(err)
|
|
538
|
+
if (!file.isModified() || file.getContent().trim() === '') return cb()
|
|
539
|
+
try {
|
|
540
|
+
const file = await this.writeFile(file)
|
|
541
|
+
this.resetFile(file)
|
|
542
|
+
cb(null, file)
|
|
543
|
+
} catch (err) {
|
|
544
|
+
cb(err)
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
)
|
|
548
|
+
},
|
|
549
|
+
(err) => {
|
|
550
|
+
if (err) return reject(err)
|
|
551
|
+
resolve()
|
|
969
552
|
}
|
|
970
|
-
|
|
971
|
-
})
|
|
972
|
-
})
|
|
973
|
-
})
|
|
974
|
-
}
|
|
975
|
-
|
|
976
|
-
Repository.prototype.writeAndAdd = function (file, emit, cb) {
|
|
977
|
-
this.writeFile(file, emit, (err, file) => {
|
|
978
|
-
if (err) return cb(new Error('Unable to write file:' + file.path))
|
|
979
|
-
this.addFile(file, (err) => {
|
|
980
|
-
if (err) return cb(new Error('Unable to add file:' + file.path))
|
|
981
|
-
cb(null, file)
|
|
553
|
+
)
|
|
982
554
|
})
|
|
983
|
-
}
|
|
984
|
-
}
|
|
555
|
+
}
|
|
985
556
|
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
return
|
|
557
|
+
/**
|
|
558
|
+
* Get the full path from a relative path
|
|
559
|
+
*
|
|
560
|
+
* @method getFullPath
|
|
561
|
+
* @param {} file
|
|
562
|
+
* @return String
|
|
563
|
+
*/
|
|
564
|
+
getFullPath (file) {
|
|
565
|
+
if (File.isFile(file)) file = file.path
|
|
566
|
+
if (file.indexOf(this.path) === 0) return file
|
|
567
|
+
try {
|
|
568
|
+
var fullPath = path.join(this.path, file)
|
|
569
|
+
return fullPath
|
|
570
|
+
} catch (e) {
|
|
571
|
+
throw new Error(
|
|
572
|
+
util.format(
|
|
573
|
+
'Error getting full path for file:%s and repo path:%s',
|
|
574
|
+
file,
|
|
575
|
+
this.path
|
|
576
|
+
)
|
|
577
|
+
)
|
|
999
578
|
}
|
|
1000
|
-
self.writeAndExtract(file, true, cb)
|
|
1001
|
-
}
|
|
1002
|
-
if (!file.getContent()) {
|
|
1003
|
-
self.readFileContent(file, function (err, file) {
|
|
1004
|
-
if (err) return cb(err)
|
|
1005
|
-
execute(file)
|
|
1006
|
-
})
|
|
1007
|
-
} else {
|
|
1008
|
-
execute(file)
|
|
1009
579
|
}
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
}
|
|
580
|
+
|
|
581
|
+
/**
|
|
582
|
+
* Get the relative path from repository root
|
|
583
|
+
*
|
|
584
|
+
* @method getRelativePath
|
|
585
|
+
* @param {} fullPath
|
|
586
|
+
* @return String
|
|
587
|
+
*/
|
|
588
|
+
getRelativePath (fullPath) {
|
|
589
|
+
if (path.sep === '\\') {
|
|
590
|
+
fullPath = fullPath.replace(/\//g, path.sep)
|
|
591
|
+
}
|
|
592
|
+
if (!fullPath.startsWith(this.path)) return fullPath
|
|
593
|
+
try {
|
|
594
|
+
var relPath = path.relative(this.path, fullPath)
|
|
595
|
+
return relPath
|
|
596
|
+
} catch (e) {
|
|
597
|
+
throw new Error(
|
|
598
|
+
util.format(
|
|
599
|
+
'Error getting relative path for file:%s and repo path:%s',
|
|
600
|
+
fullPath,
|
|
601
|
+
this.path
|
|
602
|
+
)
|
|
1034
603
|
)
|
|
1035
|
-
},
|
|
1036
|
-
(err) => {
|
|
1037
|
-
cb(err)
|
|
1038
604
|
}
|
|
1039
|
-
|
|
1040
|
-
}
|
|
605
|
+
}
|
|
1041
606
|
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
607
|
+
/**
|
|
608
|
+
* Is this file OK? Implemented in mixins
|
|
609
|
+
*
|
|
610
|
+
* @method fileOK
|
|
611
|
+
* @param {} file
|
|
612
|
+
* @param {} includeDirs
|
|
613
|
+
* @return stat
|
|
614
|
+
*/
|
|
615
|
+
// READY Refactor fileOK to use async/await
|
|
616
|
+
// #esm-migration #urgent
|
|
617
|
+
async fileOK (file, includeDirs) {
|
|
618
|
+
inMixinsNoop()
|
|
1054
619
|
}
|
|
1055
|
-
}
|
|
1056
620
|
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
this.readFileContent(file, (err, file) => {
|
|
1062
|
-
if (err) return cb(err)
|
|
1063
|
-
file.modifyTaskFromContent(task, content, this.getConfig())
|
|
1064
|
-
this.writeAndExtract(file, true, cb)
|
|
1065
|
-
})
|
|
1066
|
-
} else {
|
|
1067
|
-
file.modifyTaskFromContent(task, content, this.getConfig())
|
|
1068
|
-
this.writeAndExtract(file, true, cb)
|
|
621
|
+
setIgnores (ignores) {
|
|
622
|
+
// logger.info('ignore patterns:', ignores)
|
|
623
|
+
this.ignorePatterns = ignores
|
|
624
|
+
this.ignore = ignore().add(ignores)
|
|
1069
625
|
}
|
|
1070
|
-
}
|
|
1071
626
|
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
627
|
+
/**
|
|
628
|
+
* Should the relative path be included.
|
|
629
|
+
*
|
|
630
|
+
* @method shouldInclude
|
|
631
|
+
* @param {} relPath
|
|
632
|
+
* @return exclude
|
|
633
|
+
*/
|
|
634
|
+
shouldInclude (relPath) {
|
|
635
|
+
relPath = this.getRelativePath(relPath)
|
|
636
|
+
let include = true
|
|
637
|
+
if (this.config.markdownOnly && relPath) {
|
|
638
|
+
include = File.isMarkdown(relPath)
|
|
639
|
+
}
|
|
640
|
+
if (this.ignore) {
|
|
641
|
+
try {
|
|
642
|
+
include = include && (relPath === '' || !this.ignore.ignores(relPath))
|
|
643
|
+
} catch (e) {
|
|
644
|
+
logger.error(
|
|
645
|
+
`Failed to check ignore status for dir: [${relPath}] in: [${this.path}]. It will be included.`,
|
|
646
|
+
e
|
|
647
|
+
)
|
|
648
|
+
}
|
|
649
|
+
}
|
|
1093
650
|
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
const interpretedTaskPrefix = _template(config.getTaskPrefix())({
|
|
1097
|
-
date: new Date(),
|
|
1098
|
-
}).trimEnd()
|
|
1099
|
-
const lines = eol.split(content)
|
|
1100
|
-
const text = lines[0]
|
|
1101
|
-
const taskSyntax = config.getNewCardSyntax()
|
|
1102
|
-
const taskPrefix = interpretedTaskPrefix ? `${interpretedTaskPrefix} ` : ''
|
|
1103
|
-
let fileContent = file.getContent()
|
|
1104
|
-
const journalTemplate = this.getConfig().journalTemplate
|
|
1105
|
-
fileContent = fileContent.trim()
|
|
1106
|
-
? fileContent
|
|
1107
|
-
: journalTemplate
|
|
1108
|
-
&& journalTemplate.trim()
|
|
1109
|
-
? journalTemplate + String(eol.lf)
|
|
1110
|
-
: '';
|
|
1111
|
-
|
|
1112
|
-
const length = fileContent.length
|
|
1113
|
-
const fileIsEmpty = length < 1
|
|
1114
|
-
const crlf = String(eol.crlf)
|
|
1115
|
-
let sep = fileContent.indexOf(crlf) > -1 ? crlf : String(eol.lf)
|
|
1116
|
-
if (fileContent.endsWith(sep) || fileIsEmpty) sep = ''
|
|
1117
|
-
const order = appContext().projectContext.getOrder(list)
|
|
1118
|
-
const description = lines.length > 1 ? Task.padDescription(lines.slice(1), taskPrefix) : []
|
|
1119
|
-
const { orderMeta, tokenPrefix } = config
|
|
1120
|
-
const rawTask = getRawTask({tokenPrefix, orderMeta, list, order, text, type: taskSyntax})
|
|
1121
|
-
const taskContent = config.orderMeta
|
|
1122
|
-
? this.getTaskContent({
|
|
1123
|
-
description,
|
|
1124
|
-
order,
|
|
1125
|
-
text,
|
|
1126
|
-
taskPrefix,
|
|
1127
|
-
taskSyntax,
|
|
1128
|
-
})
|
|
1129
|
-
: description.join(eol.lf)
|
|
651
|
+
return include
|
|
652
|
+
}
|
|
1130
653
|
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
654
|
+
/**
|
|
655
|
+
* Add or replace a file in the files reference array
|
|
656
|
+
*
|
|
657
|
+
* @method addFile
|
|
658
|
+
* @param {} file
|
|
659
|
+
* @return MemberExpression
|
|
660
|
+
*/
|
|
661
|
+
// READY Refactor addFile to use async/await
|
|
662
|
+
// #esm-migration #urgent
|
|
663
|
+
async addFile (file) {
|
|
664
|
+
if (this.destroyed) throw new Error('destroyed')
|
|
665
|
+
const ok = await this.fileOK(file)
|
|
666
|
+
if (!ok) return this.files
|
|
667
|
+
let index = this.files.findIndex(({ path }) => path === file.path)
|
|
668
|
+
if (index > -1) {
|
|
669
|
+
this.files[index] = file
|
|
670
|
+
} else {
|
|
671
|
+
this.files.push(file)
|
|
672
|
+
}
|
|
1138
673
|
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
const task = file.getTasks().find(task => task.text === text && task.list === list)
|
|
1142
|
-
cb(null, file, task)
|
|
1143
|
-
})
|
|
1144
|
-
}
|
|
674
|
+
return this.files
|
|
675
|
+
}
|
|
1145
676
|
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
677
|
+
/**
|
|
678
|
+
* Remove a file from the files reference array
|
|
679
|
+
*
|
|
680
|
+
* @method removeFile
|
|
681
|
+
* @param {} file
|
|
682
|
+
* @return MemberExpression
|
|
683
|
+
*/
|
|
684
|
+
removeFile (file) {
|
|
685
|
+
if (!File.isFile(file)) throw new Error(ERRORS.NOT_A_FILE)
|
|
686
|
+
_remove(this.files, f => f.path === file.path)
|
|
1150
687
|
|
|
1151
|
-
|
|
1152
|
-
this.readFileContent(file, (err, file) => {
|
|
1153
|
-
if (err) return cb(err)
|
|
1154
|
-
this.appendTask({file, content, list}, cb)
|
|
1155
|
-
})
|
|
1156
|
-
} else {
|
|
1157
|
-
const modifiedTime = new Date()
|
|
1158
|
-
const createdTime = new Date()
|
|
1159
|
-
file = new File({
|
|
1160
|
-
repoId: this.path,
|
|
1161
|
-
filePath: relPath,
|
|
1162
|
-
content: '',
|
|
1163
|
-
modifiedTime,
|
|
1164
|
-
createdTime,
|
|
1165
|
-
project: this.project,
|
|
1166
|
-
})
|
|
1167
|
-
this.appendTask({file, content, list}, cb)
|
|
688
|
+
return this.files
|
|
1168
689
|
}
|
|
1169
|
-
}
|
|
1170
690
|
|
|
1171
|
-
/**
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
cb = writeFile
|
|
1181
|
-
writeFile = false
|
|
1182
|
-
}
|
|
1183
|
-
cb = tools.cb(cb)
|
|
1184
|
-
const config = this.getConfig()
|
|
1185
|
-
log(
|
|
1186
|
-
'Modifying Task... text:%s list:%s order:%d path:%s id:%s line:%d',
|
|
1187
|
-
task.text,
|
|
1188
|
-
task.list,
|
|
1189
|
-
task.order,
|
|
1190
|
-
task.source.path,
|
|
1191
|
-
task.id,
|
|
1192
|
-
task.line
|
|
1193
|
-
)
|
|
1194
|
-
var self = this
|
|
1195
|
-
let beforeModifyContent
|
|
1196
|
-
var file = this.getFileForTask(task)
|
|
1197
|
-
try {
|
|
1198
|
-
beforeModifyContent = file.getContent()
|
|
1199
|
-
} catch (e) {
|
|
1200
|
-
console.error(
|
|
1201
|
-
`Can't get file for task: {text:'${task.text}', path:'${task.source.path}', line:${task.line}}`
|
|
1202
|
-
)
|
|
691
|
+
/**
|
|
692
|
+
* Description
|
|
693
|
+
* @method getFile
|
|
694
|
+
* @param {} path
|
|
695
|
+
* @return CallExpression
|
|
696
|
+
*/
|
|
697
|
+
getFile (path) {
|
|
698
|
+
path = this.getRelativePath(path)
|
|
699
|
+
return this.files.find((file) => file.path === path)
|
|
1203
700
|
}
|
|
1204
701
|
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
702
|
+
getTask (id) {
|
|
703
|
+
if (Task.isTask(id)) {
|
|
704
|
+
let task = id
|
|
705
|
+
if (!task.meta.id) return
|
|
706
|
+
return this.getTasks().find((existingTask) => {
|
|
707
|
+
return existingTask.meta.id && existingTask.meta.id[0] == task.meta.id[0]
|
|
708
|
+
})
|
|
709
|
+
} else {
|
|
710
|
+
let task = this.getTasks().find((task) => task.id === id)
|
|
711
|
+
if (!task) return
|
|
712
|
+
return this.getFile(task.source.path)
|
|
713
|
+
.getTasks()
|
|
714
|
+
.find((task) => task.id === id)
|
|
715
|
+
}
|
|
716
|
+
}
|
|
1212
717
|
|
|
1213
|
-
|
|
718
|
+
/**
|
|
719
|
+
* Description
|
|
720
|
+
* @method getFileForTask
|
|
721
|
+
* @param {} task
|
|
722
|
+
* @return CallExpression
|
|
723
|
+
*/
|
|
724
|
+
getFileForTask (task) {
|
|
725
|
+
return this.getFile(task.getSource().path)
|
|
1214
726
|
}
|
|
1215
727
|
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
728
|
+
/**
|
|
729
|
+
* Descriptione
|
|
730
|
+
* @method getFiles
|
|
731
|
+
* @param {} paths
|
|
732
|
+
* @return CallExpression
|
|
733
|
+
*/
|
|
734
|
+
getFiles (paths) {
|
|
735
|
+
if (_isUndefined(paths)) return sort(this.files).asc(u => u.path)
|
|
736
|
+
return this.files.filter((file) => {
|
|
737
|
+
return paths.includes(file.path)
|
|
1220
738
|
})
|
|
1221
|
-
} else {
|
|
1222
|
-
modifyTransformExtract(cb)
|
|
1223
739
|
}
|
|
1224
|
-
}
|
|
1225
740
|
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
}
|
|
741
|
+
getFilesWithTasks () {
|
|
742
|
+
const files = this.files.filter((file) => file.getTasks().length > 0)
|
|
743
|
+
return sort(files).asc(u => u.path)
|
|
744
|
+
}
|
|
1231
745
|
|
|
1232
|
-
|
|
1233
|
-
|
|
746
|
+
resetFile (file) {
|
|
747
|
+
file.reset()
|
|
748
|
+
file.removeListener('task.found', this.taskFoundListener)
|
|
749
|
+
file.removeListener('task.modified', this.taskModifiedListener)
|
|
750
|
+
}
|
|
1234
751
|
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
752
|
+
// READY refactor extractTasks to use async/await
|
|
753
|
+
// #esm-migration #urgent #important
|
|
754
|
+
// <!--
|
|
755
|
+
// order:-100
|
|
756
|
+
// -->
|
|
757
|
+
async extractTasks (file) {
|
|
758
|
+
if (file.content === null) {
|
|
759
|
+
await this.readFileContent(file)
|
|
760
|
+
}
|
|
761
|
+
file.on('task.found', this.taskFoundListener)
|
|
762
|
+
file.on('task.modified', this.taskModifiedListener)
|
|
763
|
+
const fileContent = file.content
|
|
764
|
+
file.extractAndTransformTasks(this.getConfig())
|
|
765
|
+
if (!file.isModified() || fileContent === file.content) {
|
|
766
|
+
this.resetFile(file)
|
|
767
|
+
return file
|
|
768
|
+
}
|
|
769
|
+
file.extractTasks(this.getConfig())
|
|
770
|
+
if (file.modified) await this.writeFile(file)
|
|
771
|
+
this.resetFile(file)
|
|
772
|
+
return file
|
|
773
|
+
}
|
|
1250
774
|
|
|
1251
|
-
|
|
775
|
+
/**
|
|
776
|
+
* Implemented in mixins
|
|
777
|
+
* @method writeFile
|
|
778
|
+
* @param {} file
|
|
779
|
+
* @param {} cb
|
|
780
|
+
* @return
|
|
781
|
+
*/
|
|
782
|
+
async writeFile (file) {
|
|
783
|
+
inMixinsNoop()
|
|
784
|
+
}
|
|
1252
785
|
|
|
1253
|
-
|
|
1254
|
-
|
|
786
|
+
/**
|
|
787
|
+
* Implemented in mixins
|
|
788
|
+
* @method getFilesInPath
|
|
789
|
+
* @param {} includeDirs
|
|
790
|
+
* @return CallExpression
|
|
791
|
+
*/
|
|
1255
792
|
|
|
1256
|
-
|
|
793
|
+
async getFilesInPath (includeDirs) {
|
|
794
|
+
inMixinsNoop()
|
|
795
|
+
}
|
|
1257
796
|
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
797
|
+
/**
|
|
798
|
+
* Implemented in mixins
|
|
799
|
+
* @method readFileContent
|
|
800
|
+
* @param {} file
|
|
801
|
+
* @return
|
|
802
|
+
*/
|
|
803
|
+
async readFileContent (file) {
|
|
804
|
+
inMixinsNoop()
|
|
1266
805
|
}
|
|
1267
|
-
return closestIndexWithOrder
|
|
1268
|
-
}
|
|
1269
806
|
|
|
1270
|
-
|
|
807
|
+
// READY Refactor readFile to use async/await
|
|
808
|
+
// #esm-migration #important #urgent
|
|
809
|
+
// <!--
|
|
810
|
+
// order:-30
|
|
811
|
+
// -->
|
|
812
|
+
async readFile(file) {
|
|
813
|
+
if (!File.isFile(file)) throw new Error(ERRORS.NOT_A_FILE)
|
|
814
|
+
if (file.deleted) return file
|
|
1271
815
|
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
return taskBeforeHasOrder(taskList, newPos)
|
|
1276
|
-
&& taskAfterHasOrder(taskList, newPos)
|
|
1277
|
-
&& parseFloat(taskBefore.order) !== parseFloat(taskAfter.order)
|
|
1278
|
-
}
|
|
816
|
+
var currentChecksum = file.checksum
|
|
817
|
+
const filePath = file.path
|
|
818
|
+
if (/\.\.(\/|\\)/.test(filePath)) throw new Error('Unable to read file:' + file)
|
|
1279
819
|
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
820
|
+
await this.readFileContent(file)
|
|
821
|
+
file.checksum = computeChecksum(file.getContent())
|
|
822
|
+
file.updated = currentChecksum !== file.checksum
|
|
823
|
+
if (!file.updated) return file
|
|
1284
824
|
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
return taskAfter && isNumber(taskAfter.order)
|
|
1288
|
-
}
|
|
1289
|
-
function lastTaskHasOrder(taskList) {
|
|
1290
|
-
const lastTask = taskList[taskList.length - 1]
|
|
1291
|
-
return lastTask && isNumber(lastTask.order)
|
|
1292
|
-
}
|
|
825
|
+
await this.extractTasks(file)
|
|
826
|
+
await this.addFile()
|
|
1293
827
|
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
} else {
|
|
1326
|
-
for (let index = start; index < end; index++) {
|
|
1327
|
-
newOrder += increment
|
|
1328
|
-
if (index === newPos) {
|
|
1329
|
-
task.order = newOrder
|
|
1330
|
-
tasksToModify.push(task)
|
|
1331
|
-
newOrder += increment
|
|
828
|
+
return file
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
/**
|
|
832
|
+
* Description
|
|
833
|
+
* @method readFiles
|
|
834
|
+
* @param {} files
|
|
835
|
+
* @param {} cb
|
|
836
|
+
* @return
|
|
837
|
+
*/
|
|
838
|
+
// READY Refactor readFiles to use async/await
|
|
839
|
+
// #esm-migration #urgent #important
|
|
840
|
+
// <!--
|
|
841
|
+
// order:-10
|
|
842
|
+
// -->
|
|
843
|
+
readFiles (files = this.files) {
|
|
844
|
+
this.allMeta = {}
|
|
845
|
+
this.metaKeys = new Set()
|
|
846
|
+
this.allTags = new Set()
|
|
847
|
+
this.allContexts = new Set()
|
|
848
|
+
|
|
849
|
+
return new Promise(async (resolve, reject) => {
|
|
850
|
+
|
|
851
|
+
if (files.length < 1) {
|
|
852
|
+
files = this.files = await this.getFilesInPath(false)
|
|
853
|
+
const filesToInclude = files.map((file) => file.path)
|
|
854
|
+
const fileStats = {
|
|
855
|
+
count: filesToInclude.length,
|
|
856
|
+
files: filesToInclude,
|
|
857
|
+
}
|
|
858
|
+
this.emit('files.found', fileStats)
|
|
1332
859
|
}
|
|
860
|
+
let completed = 0
|
|
861
|
+
|
|
862
|
+
if (files.length < 1) return resolve(files)
|
|
863
|
+
eachLimit(
|
|
864
|
+
files,
|
|
865
|
+
ASYNC_LIMIT,
|
|
866
|
+
async (file) => {
|
|
867
|
+
this.emit('file.reading', { path: file.path })
|
|
868
|
+
await this.readFile(file)
|
|
869
|
+
completed++
|
|
870
|
+
this.emit('file.read', {path: file.path, completed: completed})
|
|
871
|
+
},
|
|
872
|
+
function (err) {
|
|
873
|
+
if (err) return reject(err)
|
|
874
|
+
resolve(files)
|
|
875
|
+
}
|
|
876
|
+
)
|
|
877
|
+
})
|
|
878
|
+
}
|
|
1333
879
|
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
880
|
+
/**
|
|
881
|
+
* Implemented in mixins
|
|
882
|
+
* @method deleteFile
|
|
883
|
+
* @param {} path
|
|
884
|
+
* @param {} cb
|
|
885
|
+
* @return
|
|
886
|
+
*/
|
|
887
|
+
async deleteFile (path, cb) {
|
|
888
|
+
inMixinsNoop(cb)
|
|
1338
889
|
}
|
|
1339
890
|
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
891
|
+
/**
|
|
892
|
+
* Description
|
|
893
|
+
* @method hasDefaultFile
|
|
894
|
+
* @return CallExpression
|
|
895
|
+
*/
|
|
896
|
+
hasDefaultFile () {
|
|
897
|
+
return _some(this.getFiles(), function (file) {
|
|
898
|
+
var regex = new RegExp(DEFAULT_FILE_PATTERN, 'i')
|
|
899
|
+
return regex.test(file.path)
|
|
900
|
+
})
|
|
1343
901
|
}
|
|
1344
902
|
|
|
1345
|
-
|
|
1346
|
-
|
|
903
|
+
/**
|
|
904
|
+
* Description
|
|
905
|
+
* @method getDefaultFile
|
|
906
|
+
* @return file
|
|
907
|
+
*/
|
|
908
|
+
getDefaultFile () {
|
|
909
|
+
var files = sort(this.getFiles()).asc(u => u.path)
|
|
910
|
+
var file = files.reverse().find((file) => {
|
|
911
|
+
var regex = new RegExp(DEFAULT_FILE_PATTERN, 'i')
|
|
912
|
+
return regex.test(file.path)
|
|
913
|
+
})
|
|
914
|
+
return file
|
|
915
|
+
}
|
|
1347
916
|
|
|
1348
|
-
|
|
917
|
+
getList (name) {
|
|
918
|
+
return this.getLists().find((list) => list.name === name)
|
|
919
|
+
}
|
|
1349
920
|
|
|
1350
|
-
function tasksHaveSameOrder(taskA, taskB) {
|
|
1351
|
-
return taskA && taskB && taskA.order + "" === taskB.order + ""
|
|
1352
|
-
}
|
|
1353
921
|
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
task = newCard(task, this.project, true)
|
|
922
|
+
getListById(id, lists = this.getLists()) {
|
|
923
|
+
return lists.find((list) => list.id === id)
|
|
1357
924
|
}
|
|
1358
|
-
task = this.getTask(task.id)
|
|
1359
925
|
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
926
|
+
// READY Refactor hideList to use async/await
|
|
927
|
+
// #esm-migration
|
|
928
|
+
// <!--
|
|
929
|
+
// order:-150
|
|
930
|
+
// -->
|
|
931
|
+
async hideList (name) {
|
|
932
|
+
await this.setListHidden(name)
|
|
933
|
+
}
|
|
1367
934
|
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
935
|
+
// READY Refactor showList to use async/await
|
|
936
|
+
// #esm-migration
|
|
937
|
+
// <!--
|
|
938
|
+
// order:-230
|
|
939
|
+
// -->
|
|
940
|
+
async showList (name) {
|
|
941
|
+
await this.setListHidden(name, false)
|
|
942
|
+
}
|
|
1371
943
|
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
})
|
|
1379
|
-
|
|
1380
|
-
const tasksToModify = getTasksToModify(task, toListTasks, newPos)
|
|
1381
|
-
task.updateOrderMeta(this.config)
|
|
1382
|
-
toListTasks.splice(newPos, 0, task)
|
|
1383
|
-
|
|
1384
|
-
const tasksToModifySorted = fastSort(tasksToModify).by([{ desc: u => u.line }, { asc: u => u.path }])
|
|
1385
|
-
async.eachSeries(
|
|
1386
|
-
tasksToModifySorted,
|
|
1387
|
-
(task, cb) => {
|
|
1388
|
-
this.modifyTask(task, true, cb)
|
|
1389
|
-
},
|
|
1390
|
-
(err) => {
|
|
1391
|
-
if (err)
|
|
1392
|
-
return cb([
|
|
1393
|
-
new Error(
|
|
1394
|
-
'moveTasks: Error while modifying tasks in the current list'
|
|
1395
|
-
),
|
|
1396
|
-
err,
|
|
1397
|
-
])
|
|
1398
|
-
cb(null, task)
|
|
944
|
+
async setListHidden (name, hidden = true) {
|
|
945
|
+
const list = this.getList(name)
|
|
946
|
+
if (list) {
|
|
947
|
+
list.hidden = hidden
|
|
948
|
+
await this.saveConfig()
|
|
949
|
+
this.emit('list.modified', name)
|
|
1399
950
|
}
|
|
1400
|
-
|
|
1401
|
-
}
|
|
951
|
+
}
|
|
1402
952
|
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
tasks.map((task, i) => {
|
|
1424
|
-
return function (cb) {
|
|
1425
|
-
const foundTask = self.getTasks().find(({source, line}) => task.source.path === source.path && task.line === line)
|
|
1426
|
-
if (foundTask) {
|
|
1427
|
-
if (listsModified.indexOf(foundTask.list) < 0) listsModified.push(foundTask.list)
|
|
1428
|
-
self.moveTask({ task: foundTask, newList, newPos: newPos + i, noEmit: true }, cb)
|
|
1429
|
-
} else {
|
|
1430
|
-
cb()
|
|
1431
|
-
}
|
|
1432
|
-
}
|
|
1433
|
-
}),
|
|
1434
|
-
function (err) {
|
|
1435
|
-
if (err) {
|
|
1436
|
-
console.error('Error occurred while moving tasks:', err)
|
|
1437
|
-
}
|
|
1438
|
-
self.saveModifiedFiles(function (err, results) {
|
|
1439
|
-
if (err)
|
|
1440
|
-
console.error('Error occurred while saving modified files:', err)
|
|
1441
|
-
self.lastMovedFiles = results
|
|
1442
|
-
var tasksByList = listsModified.map((list) => {
|
|
1443
|
-
return {
|
|
1444
|
-
list: list,
|
|
1445
|
-
tasks: self.getTasksInList(list),
|
|
1446
|
-
}
|
|
1447
|
-
})
|
|
1448
|
-
self.moving = false
|
|
1449
|
-
cb(err, tasksByList)
|
|
1450
|
-
if (!err && !noEmit) self.emit('tasks.moved', tasks)
|
|
1451
|
-
})
|
|
953
|
+
/**
|
|
954
|
+
* Description
|
|
955
|
+
* @method moveList
|
|
956
|
+
* @param {} name
|
|
957
|
+
* @param {} pos
|
|
958
|
+
* @param {} cb
|
|
959
|
+
* @return
|
|
960
|
+
*/
|
|
961
|
+
// READY Refactor moveList to use async/await
|
|
962
|
+
// #esm-migration
|
|
963
|
+
// <!--
|
|
964
|
+
// order:-190
|
|
965
|
+
// -->
|
|
966
|
+
async moveList (name, pos) {
|
|
967
|
+
var list = this.getList(name)
|
|
968
|
+
if (list) {
|
|
969
|
+
_remove(this.getLists(), { name: name })
|
|
970
|
+
this.getLists().splice(pos, 0, list)
|
|
971
|
+
await this.saveConfig()
|
|
972
|
+
this.emit('list.modified', name)
|
|
1452
973
|
}
|
|
1453
|
-
|
|
1454
|
-
}
|
|
974
|
+
}
|
|
1455
975
|
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
976
|
+
// READY Refactor toggleListIgnore to use async/await
|
|
977
|
+
// #esm-migration
|
|
978
|
+
// <!--
|
|
979
|
+
// order:-250
|
|
980
|
+
// -->
|
|
981
|
+
async toggleListIgnore (name) {
|
|
982
|
+
var list = this.getList(name)
|
|
983
|
+
if (!list) return reject(new Error('List not found'))
|
|
984
|
+
list.ignore = !list.ignore
|
|
985
|
+
await this.updateList(list.id, list)
|
|
986
|
+
await this.saveConfig()
|
|
987
|
+
this.emit('list.modified', name)
|
|
988
|
+
}
|
|
1464
989
|
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
990
|
+
async toggleList (name) {
|
|
991
|
+
const list = this.getList(name)
|
|
992
|
+
if (!list) throw new Error('List not found')
|
|
993
|
+
list.hidden = !list.hidden
|
|
994
|
+
await this.updateList(list.id, list)
|
|
995
|
+
await this.saveConfig()
|
|
996
|
+
this.emit('list.modified', name)
|
|
997
|
+
}
|
|
1472
998
|
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
999
|
+
// READY Refactor updateList to use async/await
|
|
1000
|
+
// #esm-migration
|
|
1001
|
+
// <!--
|
|
1002
|
+
// order:-90
|
|
1003
|
+
// -->
|
|
1004
|
+
async updateList(id, {name, hidden, ignore, filter}) {
|
|
1005
|
+
const lists = this.getLists()
|
|
1006
|
+
const list = this.getListById(id, lists)
|
|
1007
|
+
const oldName = list.name
|
|
1008
|
+
const hasFilter = list.filter
|
|
1009
|
+
list.name = name
|
|
1010
|
+
list.hidden = hidden
|
|
1011
|
+
list.ignore = ignore
|
|
1012
|
+
if (hasFilter !== undefined) list.filter = filter
|
|
1013
|
+
this.setLists(lists)
|
|
1014
|
+
|
|
1015
|
+
if (oldName === name || hasFilter) {
|
|
1016
|
+
return await this.saveConfig()
|
|
1481
1017
|
}
|
|
1482
|
-
})
|
|
1483
1018
|
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
async.parallel(funcs, (err) => {
|
|
1487
|
-
this.savingFiles = false
|
|
1488
|
-
if (err) return cb(err)
|
|
1489
|
-
self.emit('files.saved', filesToSave)
|
|
1490
|
-
cb()
|
|
1491
|
-
})
|
|
1492
|
-
}
|
|
1019
|
+
await this.moveTasksBetweenLists(oldName, name)
|
|
1020
|
+
}
|
|
1493
1021
|
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1022
|
+
getTasksByFile(tasks) {
|
|
1023
|
+
const tasksByFile = {} // path: [files]
|
|
1024
|
+
tasks.forEach((task) => {
|
|
1025
|
+
const filePath = task.path
|
|
1026
|
+
if (!tasksByFile[filePath]) {
|
|
1027
|
+
tasksByFile[filePath] = { file: this.getFileForTask(task), tasks: [] }
|
|
1028
|
+
}
|
|
1029
|
+
tasksByFile[filePath].tasks.push(task)
|
|
1030
|
+
tasksByFile[filePath].tasks = sort(tasksByFile[filePath].tasks).desc(u => u.line)
|
|
1031
|
+
})
|
|
1032
|
+
return tasksByFile
|
|
1033
|
+
}
|
|
1034
|
+
// READY Refactor moveTasksBetweenLists to use async/await
|
|
1035
|
+
// <!--
|
|
1036
|
+
// #esm-migration #needs-testing
|
|
1037
|
+
// order:-80
|
|
1038
|
+
// -->
|
|
1039
|
+
// ## Tasks
|
|
1040
|
+
// - [x] Refactor
|
|
1041
|
+
// - [ ] Test
|
|
1042
|
+
async moveTasksBetweenLists(oldName, newName) {
|
|
1043
|
+
return new Promise((resolve, reject) => {
|
|
1044
|
+
const tasksToModify = this.getTasksInList(oldName)
|
|
1045
|
+
const tasksByFile = this.getTasksByFile(tasksToModify) // { <path/to/file>: {file, tasks} }
|
|
1046
|
+
|
|
1047
|
+
const modifyTasksFunctions = Object.values(tasksByFile).map(({ file, tasks }) => {
|
|
1048
|
+
return async () => {
|
|
1049
|
+
await this.readFileContent(file)
|
|
1050
|
+
tasks.forEach((task) => {
|
|
1051
|
+
task.list = newName
|
|
1052
|
+
file.modifyTask(task, this.getConfig(), true)
|
|
1053
|
+
file.modified = true
|
|
1054
|
+
})
|
|
1055
|
+
return file
|
|
1056
|
+
}
|
|
1057
|
+
})
|
|
1505
1058
|
|
|
1506
|
-
|
|
1507
|
-
|
|
1059
|
+
if (modifyTasksFunctions.length < 1) return resolve()
|
|
1060
|
+
this.moving = true
|
|
1061
|
+
parallel(modifyTasksFunctions, async (err, files) => {
|
|
1062
|
+
this.moving = false
|
|
1063
|
+
if (err) {
|
|
1064
|
+
files.forEach(file => this.resetFile(file))
|
|
1065
|
+
return reject(err)
|
|
1066
|
+
}
|
|
1067
|
+
try {
|
|
1068
|
+
await this.saveConfig()
|
|
1069
|
+
await this.saveModifiedFiles()
|
|
1070
|
+
resolve(files)
|
|
1071
|
+
} catch (err) {
|
|
1072
|
+
reject(err)
|
|
1073
|
+
}
|
|
1074
|
+
})
|
|
1075
|
+
})
|
|
1076
|
+
}
|
|
1508
1077
|
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1078
|
+
// READY Migrate writeAndExtract to use async/await
|
|
1079
|
+
// #esm-migration
|
|
1080
|
+
// <!--
|
|
1081
|
+
// order:-80
|
|
1082
|
+
// -->
|
|
1083
|
+
async writeAndExtract (file, emit) {
|
|
1084
|
+
try {
|
|
1085
|
+
await this.writeFile(file, emit)
|
|
1086
|
+
} catch (err) {
|
|
1087
|
+
new Error('Unable to write file:' + file.path, {cause: err})
|
|
1088
|
+
}
|
|
1512
1089
|
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
) {
|
|
1519
|
-
if (!repo) return []
|
|
1520
|
-
var tasks = {}
|
|
1521
|
-
var allTasks = noSort ? tasksAry : fastSort(tasksAry).by(DEFAULT_SORT)
|
|
1522
|
-
allTasks.forEach(function (task) {
|
|
1523
|
-
if (!tasks[task.list]) tasks[task.list] = []
|
|
1524
|
-
tasks[task.list].push(task)
|
|
1525
|
-
})
|
|
1526
|
-
var lists = repo.getLists()
|
|
1527
|
-
lists.forEach((list) => {
|
|
1528
|
-
if (list.filter && populateFiltered)
|
|
1529
|
-
return Repository.populateFilteredList(list, tasksAry)
|
|
1530
|
-
list.tasks = tasks[list.name] || []
|
|
1531
|
-
})
|
|
1532
|
-
return lists
|
|
1533
|
-
}
|
|
1090
|
+
try {
|
|
1091
|
+
await this.extractTasks(file)
|
|
1092
|
+
} catch (err) {
|
|
1093
|
+
new Error('Unable to extract tasks for file:' + file.path, { cause: err })
|
|
1094
|
+
}
|
|
1534
1095
|
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
list.tasks = []
|
|
1096
|
+
try {
|
|
1097
|
+
await this.addFile(file)
|
|
1098
|
+
} catch (err) {
|
|
1099
|
+
new Error('Unable to add file after extracting tasks: ' + file.path, { cause: err })
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1102
|
+
return file
|
|
1543
1103
|
}
|
|
1544
|
-
}
|
|
1545
1104
|
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
var allTasks = fastSort(tasks).by(DEFAULT_SORT)
|
|
1557
|
-
if (isNumber(offset) && isNumber(limit))
|
|
1558
|
-
return allTasks.slice(offset, offset + limit)
|
|
1559
|
-
return allTasks
|
|
1560
|
-
}
|
|
1105
|
+
// READY Refactor writeAndAdd to use async/await
|
|
1106
|
+
// #esm-migration
|
|
1107
|
+
// <!--
|
|
1108
|
+
// order:-70
|
|
1109
|
+
// -->
|
|
1110
|
+
async writeAndAdd (file, emit) {
|
|
1111
|
+
await this.writeFile(file, emit)
|
|
1112
|
+
await this.addFile(file)
|
|
1113
|
+
return file
|
|
1114
|
+
}
|
|
1561
1115
|
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1116
|
+
// READY Refactor deleteTask to use async/await
|
|
1117
|
+
// #esm-migration
|
|
1118
|
+
// <!--
|
|
1119
|
+
// order:-130
|
|
1120
|
+
// -->
|
|
1121
|
+
async deleteTask (task, cb) {
|
|
1122
|
+
let file = this.getFileForTask(task)
|
|
1123
|
+
if (!file) return
|
|
1570
1124
|
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
}
|
|
1125
|
+
if (!file.getContent()) {
|
|
1126
|
+
file = await this.readFileContent(file)
|
|
1127
|
+
}
|
|
1574
1128
|
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1129
|
+
file.deleteTask(task, this.getConfig())
|
|
1130
|
+
if (file.getContentForFile().trim() === '' && file.isMarkDownFile()) {
|
|
1131
|
+
if (file.deleted) return
|
|
1132
|
+
logger.log('Deleting empty file:', file.path)
|
|
1133
|
+
this.deleteFile(file.path)
|
|
1134
|
+
file.deleted = true
|
|
1135
|
+
return
|
|
1136
|
+
}
|
|
1137
|
+
await this.writeAndExtract(file, true)
|
|
1138
|
+
}
|
|
1139
|
+
|
|
1140
|
+
// READY Refactor deleteTasks to use async/await
|
|
1141
|
+
// #esm-migration
|
|
1142
|
+
// <!--
|
|
1143
|
+
// order:-140
|
|
1144
|
+
// -->
|
|
1145
|
+
async deleteTasks(tasks) {
|
|
1146
|
+
const files = {}
|
|
1147
|
+
tasks.forEach((task) => {
|
|
1148
|
+
if (!files[task.source.path]) {
|
|
1149
|
+
files[task.source.path] = []
|
|
1150
|
+
}
|
|
1151
|
+
files[task.source.path].push(task)
|
|
1152
|
+
files[task.source.path] = sort(files[task.source.path]).desc(u => u.line)
|
|
1589
1153
|
})
|
|
1590
|
-
})
|
|
1591
|
-
}
|
|
1592
1154
|
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1155
|
+
await Promise.all(
|
|
1156
|
+
Object.keys(files).map(async (path) => {
|
|
1157
|
+
const tasksInFile = files[path]
|
|
1158
|
+
if (!tasksInFile) return
|
|
1159
|
+
for (const task of tasksInFile) {
|
|
1160
|
+
const taskToDelete = newCard(task, this.project, true)
|
|
1161
|
+
await this.deleteTask(taskToDelete)
|
|
1162
|
+
}
|
|
1163
|
+
})
|
|
1164
|
+
)
|
|
1597
1165
|
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
`(?<!https?:\\/\\/[^\\s]*?)\\b${escapedQueryString}\\b(?![^\\s]*\\/)(?<!==)(?!==)`,
|
|
1601
|
-
'gi'
|
|
1602
|
-
);
|
|
1166
|
+
this.emit('tasks.updated', tasks)
|
|
1167
|
+
}
|
|
1603
1168
|
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1169
|
+
// READY Refactor modifyTaskFromHtml to use async/await
|
|
1170
|
+
// #esm-migration
|
|
1171
|
+
// <!--
|
|
1172
|
+
// order:-170
|
|
1173
|
+
// -->
|
|
1174
|
+
async modifyTaskFromHtml (task, html) {
|
|
1175
|
+
var file = this.getFileForTask(task)
|
|
1176
|
+
if (!file.getContent()) {
|
|
1177
|
+
file = await this.readFileContent(file)
|
|
1178
|
+
}
|
|
1179
|
+
file.modifyTaskFromHtml(task, html)
|
|
1180
|
+
return await this.writeAndExtract(file, true)
|
|
1181
|
+
}
|
|
1609
1182
|
|
|
1610
|
-
|
|
1611
|
-
|
|
1183
|
+
// READY Refactor modifyTaskFromContent to use async/await
|
|
1184
|
+
// #esm-migration
|
|
1185
|
+
// <!--
|
|
1186
|
+
// order:-180
|
|
1187
|
+
// -->
|
|
1188
|
+
async modifyTaskFromContent (task, content, cb) {
|
|
1189
|
+
var file = this.getFileForTask(task)
|
|
1190
|
+
if (!file.getContent()) {
|
|
1191
|
+
file = await this.readFileContent(file)
|
|
1192
|
+
}
|
|
1193
|
+
|
|
1194
|
+
file.modifyTaskFromContent(task, content, this.getConfig())
|
|
1195
|
+
return await this.writeAndExtract(file, true)
|
|
1196
|
+
}
|
|
1612
1197
|
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1198
|
+
getTaskContent({
|
|
1199
|
+
description,
|
|
1200
|
+
order,
|
|
1201
|
+
text,
|
|
1202
|
+
taskPrefix,
|
|
1203
|
+
taskSyntax,
|
|
1204
|
+
}) {
|
|
1205
|
+
const task = newCard(
|
|
1206
|
+
{
|
|
1207
|
+
description,
|
|
1208
|
+
meta: {},
|
|
1209
|
+
order,
|
|
1210
|
+
text,
|
|
1211
|
+
beforeText: taskPrefix,
|
|
1212
|
+
type: taskSyntax,
|
|
1213
|
+
},
|
|
1214
|
+
this.project
|
|
1215
|
+
)
|
|
1216
|
+
task.updateOrderMeta(this.config)
|
|
1217
|
+
return task.description.join(eol.lf)
|
|
1218
|
+
}
|
|
1619
1219
|
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1220
|
+
// READY Refactor appendTask to use async/await
|
|
1221
|
+
// #esm-migration
|
|
1222
|
+
// <!--
|
|
1223
|
+
// order:-300
|
|
1224
|
+
// -->
|
|
1225
|
+
async appendTask({file, content, list}) {
|
|
1226
|
+
const config = this.getConfig()
|
|
1227
|
+
const interpretedTaskPrefix = interpolate(
|
|
1228
|
+
config.getTaskPrefix(),
|
|
1229
|
+
{ date: new Date() }
|
|
1230
|
+
).content.trimEnd()
|
|
1231
|
+
const lines = eol.split(content)
|
|
1232
|
+
const text = lines[0]
|
|
1233
|
+
const taskSyntax = config.getNewCardSyntax()
|
|
1234
|
+
const taskPrefix = interpretedTaskPrefix ? `${interpretedTaskPrefix} ` : ''
|
|
1235
|
+
let fileContent = file.getContent()
|
|
1236
|
+
const journalTemplate = this.getConfig().journalTemplate
|
|
1237
|
+
fileContent = fileContent.trim()
|
|
1238
|
+
? fileContent
|
|
1239
|
+
: journalTemplate
|
|
1240
|
+
&& journalTemplate.trim()
|
|
1241
|
+
? journalTemplate + String(eol.lf)
|
|
1242
|
+
: '';
|
|
1243
|
+
|
|
1244
|
+
const length = fileContent.length
|
|
1245
|
+
const fileIsEmpty = length < 1
|
|
1246
|
+
const crlf = String(eol.crlf)
|
|
1247
|
+
let sep = fileContent.indexOf(crlf) > -1 ? crlf : String(eol.lf)
|
|
1248
|
+
if (fileContent.endsWith(sep) || fileIsEmpty) sep = ''
|
|
1249
|
+
const order = appContext().projectContext.getOrder(list)
|
|
1250
|
+
const description = lines.length > 1 ? Task.padDescription(lines.slice(1), taskPrefix) : []
|
|
1251
|
+
const { orderMeta, tokenPrefix } = config
|
|
1252
|
+
const rawTask = getRawTask({tokenPrefix, orderMeta, list, order, text, type: taskSyntax})
|
|
1253
|
+
const taskContent = config.orderMeta
|
|
1254
|
+
? this.getTaskContent({
|
|
1255
|
+
description,
|
|
1256
|
+
order,
|
|
1257
|
+
text,
|
|
1258
|
+
taskPrefix,
|
|
1259
|
+
taskSyntax,
|
|
1260
|
+
})
|
|
1261
|
+
: description.join(eol.lf)
|
|
1625
1262
|
|
|
1626
|
-
|
|
1627
|
-
}
|
|
1263
|
+
let appendContent = File.trimBlankLines(
|
|
1264
|
+
`${taskPrefix}${rawTask}${eol.lf}${taskContent}`
|
|
1265
|
+
)
|
|
1266
|
+
|
|
1267
|
+
fileContent = `${fileContent}${sep}`
|
|
1268
|
+
const cardTerminator = "\n".repeat(2)
|
|
1269
|
+
file.setContent(`${fileContent}${appendContent}${cardTerminator}`)
|
|
1628
1270
|
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
}
|
|
1271
|
+
await this.writeAndExtract(file)
|
|
1272
|
+
const task = file.getTasks().find(task => task.text === text && task.list === list)
|
|
1273
|
+
return { file, task }
|
|
1274
|
+
}
|
|
1633
1275
|
|
|
1276
|
+
// READY Refactor addTaskToFile to use async/await
|
|
1277
|
+
// #esm-migration
|
|
1278
|
+
// <!--
|
|
1279
|
+
// order:-290
|
|
1280
|
+
// -->
|
|
1281
|
+
async addTaskToFile (filePath, list, content) {
|
|
1282
|
+
const relPath = this.getRelativePath(filePath)
|
|
1283
|
+
let file = this.getFile(relPath)
|
|
1634
1284
|
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1285
|
+
if (file) {
|
|
1286
|
+
await this.readFileContent(file)
|
|
1287
|
+
return this.appendTask({file, content, list})
|
|
1288
|
+
} else {
|
|
1289
|
+
const modifiedTime = new Date()
|
|
1290
|
+
const createdTime = new Date()
|
|
1291
|
+
file = new File({
|
|
1292
|
+
repoId: this.path,
|
|
1293
|
+
filePath: relPath,
|
|
1294
|
+
content: '',
|
|
1295
|
+
modifiedTime,
|
|
1296
|
+
createdTime,
|
|
1297
|
+
project: this.project,
|
|
1644
1298
|
})
|
|
1645
|
-
return
|
|
1299
|
+
return this.appendTask({file, content, list})
|
|
1646
1300
|
}
|
|
1647
|
-
).trim()
|
|
1648
|
-
return {
|
|
1649
|
-
hideLists,
|
|
1650
|
-
queryString,
|
|
1651
1301
|
}
|
|
1652
|
-
}
|
|
1653
1302
|
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1303
|
+
/**
|
|
1304
|
+
* Description
|
|
1305
|
+
* @method modifyTask
|
|
1306
|
+
* @param {} task
|
|
1307
|
+
* @return CallExpression
|
|
1308
|
+
*/
|
|
1309
|
+
// READY Refactor modifyTask to use async/await
|
|
1310
|
+
// #esm-migration #important #urgent
|
|
1311
|
+
// <!--
|
|
1312
|
+
// order:-60
|
|
1313
|
+
// -->
|
|
1314
|
+
async modifyTask (task, writeFile = false) {
|
|
1315
|
+
if (!Task.isTask(task)) return
|
|
1316
|
+
const config = this.getConfig()
|
|
1317
|
+
log(
|
|
1318
|
+
'Modifying Task... text:%s list:%s order:%d path:%s id:%s line:%d',
|
|
1319
|
+
task.text,
|
|
1320
|
+
task.list,
|
|
1321
|
+
task.order,
|
|
1322
|
+
task.source.path,
|
|
1323
|
+
task.id,
|
|
1324
|
+
task.line
|
|
1325
|
+
)
|
|
1326
|
+
let beforeModifyContent
|
|
1327
|
+
const file = this.getFileForTask(task)
|
|
1328
|
+
try {
|
|
1329
|
+
beforeModifyContent = file.getContent()
|
|
1330
|
+
} catch (e) {
|
|
1331
|
+
logger.error(`Can't get file for task: {text:'${task.text}', path:'${task.source.path}', line:${task.line}}`)
|
|
1332
|
+
throw e
|
|
1663
1333
|
}
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1334
|
+
|
|
1335
|
+
if (!beforeModifyContent) await this.readFileContent(file)
|
|
1336
|
+
file.modifyTask(task, config, true)
|
|
1337
|
+
file.extractTasks(config)
|
|
1338
|
+
file.transformTask({config, modify:true, task})
|
|
1339
|
+
file.extractTasks(config)
|
|
1340
|
+
|
|
1341
|
+
if (!writeFile || beforeModifyContent === file.getContent()) return task
|
|
1342
|
+
|
|
1343
|
+
return await this.writeAndAdd(file)
|
|
1668
1344
|
}
|
|
1669
|
-
}
|
|
1670
1345
|
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1346
|
+
// READY Refactor moveTask to use async/await
|
|
1347
|
+
// #esm-migration
|
|
1348
|
+
// <!--
|
|
1349
|
+
// order:-200
|
|
1350
|
+
// -->
|
|
1351
|
+
async moveTask ({ task, newList, newPos }) {
|
|
1352
|
+
if (!Task.isTask(task)) {
|
|
1353
|
+
task = newCard(task, this.project, true)
|
|
1354
|
+
}
|
|
1355
|
+
task = this.getTask(task.id)
|
|
1356
|
+
|
|
1357
|
+
var toListTasks = this.getTasksInList(newList)
|
|
1358
|
+
if (toListTasks === undefined)
|
|
1359
|
+
throw new Error(ERRORS.LIST_NOT_FOUND, newList)
|
|
1360
|
+
|
|
1361
|
+
var fromListTasks = this.getTasksInList(task.list)
|
|
1362
|
+
if (fromListTasks === undefined)
|
|
1363
|
+
throw new Error(ERRORS.LIST_NOT_FOUND, task.list)
|
|
1364
|
+
|
|
1365
|
+
var sameList = newList == task.list
|
|
1366
|
+
if (!sameList) task.oldList = task.list
|
|
1367
|
+
task.list = newList
|
|
1368
|
+
|
|
1369
|
+
// Move the task to the correct position in the list
|
|
1370
|
+
fromListTasks = _reject(fromListTasks, function (_task) {
|
|
1371
|
+
return _task.equals(task)
|
|
1372
|
+
})
|
|
1373
|
+
toListTasks = _reject(toListTasks, function (_task) {
|
|
1374
|
+
return _task.equals(task)
|
|
1375
|
+
})
|
|
1376
|
+
|
|
1377
|
+
const tasksToModify = getTasksToModify(task, toListTasks, newPos)
|
|
1378
|
+
task.updateOrderMeta(this.config)
|
|
1379
|
+
toListTasks.splice(newPos, 0, task)
|
|
1380
|
+
|
|
1381
|
+
const tasksToModifySorted = sort(tasksToModify).by([{ desc: u => u.line }, { asc: u => u.path }])
|
|
1382
|
+
|
|
1383
|
+
await eachSeries(
|
|
1384
|
+
tasksToModifySorted,
|
|
1385
|
+
async (task) => {
|
|
1386
|
+
await this.modifyTask(task, true)
|
|
1387
|
+
},
|
|
1388
|
+
)
|
|
1389
|
+
|
|
1390
|
+
return task
|
|
1676
1391
|
}
|
|
1677
|
-
return sort
|
|
1678
|
-
}
|
|
1679
1392
|
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1393
|
+
// READY Refactor moveTasks to use async/await
|
|
1394
|
+
// #esm-migration #important
|
|
1395
|
+
// <!--
|
|
1396
|
+
// order:-350
|
|
1397
|
+
// -->
|
|
1398
|
+
async moveTasks (tasks, newList, newPos = 0, noEmit = false) {
|
|
1399
|
+
const log = require('debug')('moveTasks')
|
|
1400
|
+
if (this.getList(newList).filter)
|
|
1401
|
+
throw new Error(`Tasks can\'t be moved to a filtered list ${newList}.`)
|
|
1402
|
+
|
|
1403
|
+
const listsModified = [newList]
|
|
1404
|
+
this.moving = true
|
|
1405
|
+
|
|
1406
|
+
log('Move tasks to list:%s at position:%d : %j', newList, newPos, tasks)
|
|
1407
|
+
log(
|
|
1408
|
+
'newList before mods:',
|
|
1409
|
+
JSON.stringify(this.getTasksInList(newList), null, 3)
|
|
1410
|
+
)
|
|
1411
|
+
await series(
|
|
1412
|
+
sort(tasks).by({desc: t => t.line}).map((task, i) => {
|
|
1413
|
+
return async () =>{
|
|
1414
|
+
const foundTask = this.getTasks().find(({source, line}) => task.source.path === source.path && task.line === line)
|
|
1415
|
+
if (foundTask) {
|
|
1416
|
+
if (listsModified.indexOf(foundTask.list) < 0) listsModified.push(foundTask.list)
|
|
1417
|
+
await this.moveTask({ task: foundTask, newList, newPos: newPos + i, noEmit: true })
|
|
1418
|
+
}
|
|
1419
|
+
}
|
|
1420
|
+
})
|
|
1421
|
+
)
|
|
1686
1422
|
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1423
|
+
const results = await this.saveModifiedFiles()
|
|
1424
|
+
|
|
1425
|
+
this.lastMovedFiles = results
|
|
1426
|
+
this.moving = false
|
|
1427
|
+
|
|
1428
|
+
if (!noEmit) this.emit('tasks.moved', tasks)
|
|
1429
|
+
return listsModified.map((list) => {
|
|
1430
|
+
return {
|
|
1431
|
+
list: list,
|
|
1432
|
+
tasks: this.getTasksInList(list),
|
|
1433
|
+
}
|
|
1434
|
+
})
|
|
1698
1435
|
}
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1436
|
+
|
|
1437
|
+
getModifiedFiles () {
|
|
1438
|
+
var filesToSave = []
|
|
1439
|
+
this.getFiles().forEach((file) => {
|
|
1440
|
+
if (file.isModified()) filesToSave.push(file)
|
|
1441
|
+
})
|
|
1442
|
+
return filesToSave
|
|
1703
1443
|
}
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1444
|
+
|
|
1445
|
+
// READY Refactor saveModifiedFiles to use async/await
|
|
1446
|
+
// #esm-migration #urgent #important
|
|
1447
|
+
// <!--
|
|
1448
|
+
// order:-110
|
|
1449
|
+
// -->
|
|
1450
|
+
async saveModifiedFiles () {
|
|
1451
|
+
var filesToSave = this.getModifiedFiles()
|
|
1452
|
+
var funcs = filesToSave.map((file) => {
|
|
1453
|
+
return async () => {
|
|
1454
|
+
file.checksum = computeChecksum(file.getContent())
|
|
1455
|
+
await this.writeAndExtract(file, false)
|
|
1456
|
+
}
|
|
1457
|
+
})
|
|
1458
|
+
|
|
1459
|
+
if (funcs.length < 1) return
|
|
1460
|
+
|
|
1461
|
+
this.savingFiles = true
|
|
1462
|
+
await Promise.all(funcs)
|
|
1463
|
+
this.savingFiles = false
|
|
1464
|
+
this.emit('files.saved', filesToSave)
|
|
1711
1465
|
}
|
|
1712
|
-
}
|
|
1713
1466
|
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1467
|
+
/**
|
|
1468
|
+
* Description
|
|
1469
|
+
* @method getTasks
|
|
1470
|
+
* @return tasks
|
|
1471
|
+
*/
|
|
1472
|
+
getTasks () {
|
|
1473
|
+
const tasks = []
|
|
1474
|
+
this.getFiles().forEach((file) => {
|
|
1475
|
+
Array.prototype.push.apply(tasks, file.getTasks())
|
|
1476
|
+
})
|
|
1717
1477
|
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
let date = Date.parse(value)
|
|
1721
|
-
if (date && /(\d{4})-(\d{2})-(\d{2})/.test(value)) {
|
|
1722
|
-
return date
|
|
1723
|
-
}
|
|
1724
|
-
return value
|
|
1725
|
-
})
|
|
1726
|
-
}
|
|
1478
|
+
return tasks
|
|
1479
|
+
}
|
|
1727
1480
|
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
for (const [key, value] of Object.entries(o)) {
|
|
1731
|
-
if (value && typeof value === 'object') {
|
|
1732
|
-
Repository.filterObjectValues(value, cb)
|
|
1733
|
-
} else {
|
|
1734
|
-
o[key] = cb(key, value)
|
|
1735
|
-
}
|
|
1736
|
-
}
|
|
1481
|
+
getTasksByList (noSort) {
|
|
1482
|
+
return Repository.getTasksByList(this, this.getTasks(), noSort, true)
|
|
1737
1483
|
}
|
|
1738
|
-
return o
|
|
1739
|
-
}
|
|
1740
1484
|
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
}
|
|
1485
|
+
/**
|
|
1486
|
+
* Description
|
|
1487
|
+
* @method getTasksInList
|
|
1488
|
+
* @param {} name
|
|
1489
|
+
* @return ConditionalExpression
|
|
1490
|
+
*/
|
|
1491
|
+
getTasksInList (name, offset, limit) {
|
|
1492
|
+
if (!_isString(name)) return []
|
|
1493
|
+
var tasks = _where(this.getTasks(), { list: name })
|
|
1494
|
+
if (tasks.length === 0) return []
|
|
1495
|
+
var allTasks = sort(tasks).by(DEFAULT_SORT)
|
|
1496
|
+
if (isNumber(offset) && isNumber(limit))
|
|
1497
|
+
return allTasks.slice(offset, offset + limit)
|
|
1498
|
+
return allTasks
|
|
1499
|
+
}
|
|
1500
|
+
|
|
1501
|
+
getTaskIndex (task) {
|
|
1502
|
+
const tasks = this.getTasksInList(task.list)
|
|
1503
|
+
let index = 0
|
|
1504
|
+
tasks.forEach((t, i) => {
|
|
1505
|
+
if (t.id === task.id) index = i
|
|
1506
|
+
})
|
|
1507
|
+
return index
|
|
1508
|
+
}
|
|
1745
1509
|
|
|
1746
|
-
|
|
1510
|
+
query (queryString) {
|
|
1511
|
+
const result = Repository.query(this.getTasks(), queryString)
|
|
1512
|
+
return Repository.getTasksByList(this, result, true)
|
|
1513
|
+
}
|
|
1514
|
+
}
|