imdone-core 1.40.2 → 1.41.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/lib/adapters/date-time.js +11 -0
- package/lib/adapters/markdown.js +1 -1
- package/lib/adapters/parsers/task/CardContentParser.js +54 -28
- package/lib/card.js +2 -2
- package/lib/config.js +4 -6
- package/lib/default-settings.js +1 -0
- package/lib/file.js +6 -6
- package/lib/project.js +88 -24
- package/lib/repository.js +33 -2
- package/lib/task.js +18 -18
- package/package.json +1 -1
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
const moment = require('moment');
|
|
2
|
+
module.exports = {
|
|
3
|
+
getIsoDateWithOffset: function ({date, config}) {
|
|
4
|
+
const momentDate = moment(date);
|
|
5
|
+
if (momentDate.isDST() && config && config.noDST) {
|
|
6
|
+
const offset = momentDate.utcOffset();
|
|
7
|
+
momentDate.utcOffset(offset - 60);
|
|
8
|
+
}
|
|
9
|
+
return momentDate.format();
|
|
10
|
+
}
|
|
11
|
+
}
|
package/lib/adapters/markdown.js
CHANGED
|
@@ -14,7 +14,7 @@ md.use(checkbox)
|
|
|
14
14
|
.use(imageSize)
|
|
15
15
|
.use(wikilinks(
|
|
16
16
|
{
|
|
17
|
-
linkPattern: /\[\[([\w\s\d-/]+)(\|([\w\s\d-/]+))?\]\]/,
|
|
17
|
+
linkPattern: /\[\[([\w\u00C0-\u017F\s\d-/]+)(\|([\w\u00C0-\u017F\s\d-/]+))?\]\]/,
|
|
18
18
|
uriSuffix: '.md',
|
|
19
19
|
postProcessPageName (pagename) {
|
|
20
20
|
return pagename.trim()
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
const eol = require('eol')
|
|
2
|
-
const Task = require('../../../task')
|
|
3
2
|
const XRegExp = require('xregexp')
|
|
4
3
|
|
|
5
4
|
const FILE_TYPES = {
|
|
@@ -23,6 +22,18 @@ const LINK_STYLE_REGEX = new XRegExp(
|
|
|
23
22
|
'gm'
|
|
24
23
|
)
|
|
25
24
|
|
|
25
|
+
const CHECK_REGEX = /^(\s*- )\[([x ])\]/
|
|
26
|
+
function getCheckedData(content) {
|
|
27
|
+
const taskRegex = new RegExp(CHECK_REGEX)
|
|
28
|
+
const result = taskRegex.exec(content)
|
|
29
|
+
return result
|
|
30
|
+
? {
|
|
31
|
+
pad: result[1].length,
|
|
32
|
+
checked: result[2].trim() !== '',
|
|
33
|
+
}
|
|
34
|
+
: null
|
|
35
|
+
}
|
|
36
|
+
|
|
26
37
|
function getContentLines(content) {
|
|
27
38
|
let foundContent = false
|
|
28
39
|
return eol.split(content).filter((line) => {
|
|
@@ -35,10 +46,10 @@ function getContentLines(content) {
|
|
|
35
46
|
function isCheckBoxTask (config, line, beforeText) {
|
|
36
47
|
if (!config.isAddCheckBoxTasks()) return
|
|
37
48
|
|
|
38
|
-
const beforeTextCheckData =
|
|
49
|
+
const beforeTextCheckData = getCheckedData(beforeText)
|
|
39
50
|
if (!beforeTextCheckData) return
|
|
40
51
|
|
|
41
|
-
const lineCheckData =
|
|
52
|
+
const lineCheckData = getCheckedData(line)
|
|
42
53
|
if (!lineCheckData) return
|
|
43
54
|
|
|
44
55
|
return lineCheckData.pad <= beforeTextCheckData.pad
|
|
@@ -54,7 +65,28 @@ function hasTaskInText(config, text, isCodeFile) {
|
|
|
54
65
|
)
|
|
55
66
|
}
|
|
56
67
|
|
|
57
|
-
function
|
|
68
|
+
function isBeforeTextMarkdownList(beforeText) {
|
|
69
|
+
return /^\s*(\*|-|- \[[x| ]\]|\d+\.|[a-zA-Z]\.)\s$/.test(beforeText)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function isMarkdownListItem(line) {
|
|
73
|
+
return /^\s*(\*|-|- \[[x| ]\]|\d+\.|[a-zA-Z]\.)\s/.test(line)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function padDescription(description = [], beforeText = '') {
|
|
77
|
+
if (!isBeforeTextMarkdownList(beforeText)) return description
|
|
78
|
+
return description.map((line) => {
|
|
79
|
+
return line.padStart(line.length + beforeText.length)
|
|
80
|
+
})
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function isLineOutsideMarkdownList(line, beforeText) {
|
|
84
|
+
return isBeforeTextMarkdownList(beforeText) &&
|
|
85
|
+
isMarkdownListItem(line) &&
|
|
86
|
+
line.search(/\S/) <= beforeText.search(/\S/)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function hasCodeStyleTask(config, text) {
|
|
58
90
|
let result = new RegExp(CODE_STYLE_PATTERN).exec(text)
|
|
59
91
|
if (!result) return false
|
|
60
92
|
return config.includeList(result[1])
|
|
@@ -165,31 +197,23 @@ function getTextFileTaskContent ({
|
|
|
165
197
|
if (hasCardStartTag) return
|
|
166
198
|
|
|
167
199
|
const isMarkDownFile = fileType === FILE_TYPES.MARKDOWN
|
|
200
|
+
const isTaskInList = isMarkDownFile && isBeforeTextMarkdownList(beforeText)
|
|
168
201
|
let openBlockCommentTokens = 0
|
|
169
202
|
let closeBlockCommentTokens = 0
|
|
170
203
|
let lastLineBlank = false
|
|
171
204
|
let endsWithDoubleBlank = false
|
|
172
205
|
let trailingBlankLines = 0
|
|
173
206
|
const rawTaskContentLines = []
|
|
207
|
+
const taskContentLines = []
|
|
174
208
|
|
|
175
209
|
for (let i = 1; i < lines.length; i++) {
|
|
176
210
|
let line = lines[i]
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
if (hasTaskInText(config, line, isCodeFile)) break
|
|
211
|
+
let taskContentLine = `${line}`
|
|
212
|
+
if (hasTaskInText(config, line)) break
|
|
180
213
|
if (isCheckBoxTask(config, line, beforeText)) break
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
// #urgent
|
|
185
|
-
// <!-- order:-65 -->
|
|
186
|
-
if (
|
|
187
|
-
isMarkDownFile &&
|
|
188
|
-
beforeText &&
|
|
189
|
-
/^\s*(\*|-|\d+\.|[a-zA-Z]\.)\s$/.test(beforeText) &&
|
|
190
|
-
line.search(/\S/) <= beforeText.search(/\S/)
|
|
191
|
-
) break
|
|
192
|
-
|
|
214
|
+
if (isTaskInList && isLineOutsideMarkdownList(line, beforeText)) break
|
|
215
|
+
|
|
216
|
+
taskContentLines.push(taskContentLine)
|
|
193
217
|
rawTaskContentLines.push(line)
|
|
194
218
|
|
|
195
219
|
// Check for matching block comments in markdown files
|
|
@@ -217,17 +241,17 @@ function getTextFileTaskContent ({
|
|
|
217
241
|
rawTaskContentLines.length &&
|
|
218
242
|
rawTaskContentLines[rawTaskContentLines.length - 1].trim() === '-->' &&
|
|
219
243
|
openBlockCommentTokens !== closeBlockCommentTokens
|
|
220
|
-
)
|
|
244
|
+
) {
|
|
221
245
|
rawTaskContentLines.pop()
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
? rawTaskContentLines.slice(0, -trailingBlankLines)
|
|
225
|
-
: rawTaskContentLines;
|
|
246
|
+
taskContentLines.pop()
|
|
247
|
+
}
|
|
226
248
|
|
|
227
249
|
return {
|
|
228
250
|
rawTaskContentLines,
|
|
229
|
-
taskContentLines
|
|
230
|
-
|
|
251
|
+
taskContentLines: trailingBlankLines
|
|
252
|
+
? taskContentLines.slice(0, -trailingBlankLines)
|
|
253
|
+
: taskContentLines,
|
|
254
|
+
trailingBlankLines,
|
|
231
255
|
}
|
|
232
256
|
}
|
|
233
257
|
|
|
@@ -247,8 +271,10 @@ function getTaskContent ({
|
|
|
247
271
|
module.exports = {
|
|
248
272
|
FILE_TYPES,
|
|
249
273
|
getTaskContent,
|
|
250
|
-
|
|
251
|
-
|
|
274
|
+
isBeforeTextMarkdownList,
|
|
275
|
+
padDescription,
|
|
276
|
+
getCheckedData,
|
|
277
|
+
CHECK_REGEX,
|
|
252
278
|
LIST_NAME_PATTERN,
|
|
253
279
|
HASH_STYLE_REGEX,
|
|
254
280
|
HASH_STYLE_META_ORDER_REGEX,
|
package/lib/card.js
CHANGED
|
@@ -7,8 +7,8 @@ const _isObject = require('lodash.isobject')
|
|
|
7
7
|
const _isEmpty = require('lodash.isempty')
|
|
8
8
|
const _get = require('lodash.get')
|
|
9
9
|
const eol = require('eol')
|
|
10
|
-
const moment = require('moment')
|
|
11
10
|
const allEmoji = require('markdown-it-emoji/lib/data/full.json')
|
|
11
|
+
const { getIsoDateWithOffset } = require('./adapters/date-time')
|
|
12
12
|
|
|
13
13
|
const { removeMD, renderMarkdown } = require('./adapters/markdown')
|
|
14
14
|
|
|
@@ -117,7 +117,7 @@ module.exports = function newCard(task, _project, dontParse) {
|
|
|
117
117
|
|
|
118
118
|
get defaultData() {
|
|
119
119
|
return {
|
|
120
|
-
timestamp:
|
|
120
|
+
timestamp: getIsoDateWithOffset({config: project.config}),
|
|
121
121
|
..._pick(
|
|
122
122
|
this,
|
|
123
123
|
...['beforeText',
|
package/lib/config.js
CHANGED
|
@@ -56,12 +56,6 @@ class Config {
|
|
|
56
56
|
return this.lists.findIndex((list) => list.name === name) > -1
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
-
getDateString(date = new Date()) {
|
|
60
|
-
return _get(this, 'settings.cards.useLocalDate')
|
|
61
|
-
? moment(date).utcOffset(0, true).format()
|
|
62
|
-
: date.toISOString()
|
|
63
|
-
}
|
|
64
|
-
|
|
65
59
|
getDefaultList() {
|
|
66
60
|
return _get(this, 'settings.cards.defaultList', this.lists[0].name)
|
|
67
61
|
}
|
|
@@ -100,6 +94,10 @@ class Config {
|
|
|
100
94
|
return _get(this, 'settings.cards.addCompletedMeta', false)
|
|
101
95
|
}
|
|
102
96
|
|
|
97
|
+
get noDST() {
|
|
98
|
+
return _get(this, 'settings.noDST', false)
|
|
99
|
+
}
|
|
100
|
+
|
|
103
101
|
get markdownOnly() {
|
|
104
102
|
return this.settings.markdownOnly
|
|
105
103
|
}
|
package/lib/default-settings.js
CHANGED
package/lib/file.js
CHANGED
|
@@ -20,7 +20,7 @@ var _clone = require('lodash.clone'),
|
|
|
20
20
|
newCard = require('./card'),
|
|
21
21
|
fastSort = require('fast-sort/dist/sort'),
|
|
22
22
|
XRegExp = require('xregexp'),
|
|
23
|
-
|
|
23
|
+
{ getIsoDateWithOffset } = require('./adapters/date-time'),
|
|
24
24
|
{
|
|
25
25
|
FILE_TYPES,
|
|
26
26
|
getTaskContent,
|
|
@@ -149,7 +149,7 @@ File.addCompleted = function ({ task, content, config }) {
|
|
|
149
149
|
if (task.list !== doneList) return content
|
|
150
150
|
if (task.completed || task.meta.completed) return content
|
|
151
151
|
if (content.includes(`completed${config.getMetaSep()}`)) return content
|
|
152
|
-
const now =
|
|
152
|
+
const now = getIsoDateWithOffset({ config })
|
|
153
153
|
content = task.addToLastCommentInContent(
|
|
154
154
|
content,
|
|
155
155
|
`completed${config.getMetaSep()}${now}`,
|
|
@@ -167,7 +167,7 @@ File.parseDueDate = function (config, text) {
|
|
|
167
167
|
try {
|
|
168
168
|
const due = chrono.parseDate(dueMatch, new Date(), {forwardDate: true})
|
|
169
169
|
if (!due) return dueMatch
|
|
170
|
-
dueString =
|
|
170
|
+
dueString = getIsoDateWithOffset({date: due, config})
|
|
171
171
|
return `${p1.toLowerCase()}${config.getMetaSep()}${dueString}`
|
|
172
172
|
} catch (e) {
|
|
173
173
|
console.log(`Unable to parse due date for ${text}`)
|
|
@@ -788,9 +788,9 @@ const trimBlankLines = File.trimBlankLines = function (content, isCodeFile) {
|
|
|
788
788
|
}
|
|
789
789
|
|
|
790
790
|
File.prototype.modifyDescription = function (task, config) {
|
|
791
|
-
//
|
|
791
|
+
// TODO This should be split out by type (code, markdown, etc)
|
|
792
792
|
// #urgent
|
|
793
|
-
// <!-- order:-
|
|
793
|
+
// <!-- order:-70 -->
|
|
794
794
|
const taskStart = this.getLinePos(task.line)
|
|
795
795
|
const descStart = this.getLinePos(task.line + 1)
|
|
796
796
|
const contentWithTask = this.getContent().substring(taskStart)
|
|
@@ -836,7 +836,7 @@ File.prototype.modifyDescription = function (task, config) {
|
|
|
836
836
|
description.length > 0 &&
|
|
837
837
|
(hasBlankLines(description) || isWrappedWithCardTag || trailingBlankLines)
|
|
838
838
|
) {
|
|
839
|
-
task.isWrappedWithCardTag = isWrappedWithCardTag //
|
|
839
|
+
task.isWrappedWithCardTag = isWrappedWithCardTag // FIXME Find out where this is used and stop using it
|
|
840
840
|
// <!-- order:-30 -->
|
|
841
841
|
const blankLinesToAdd = isWrappedWithCardTag ? 2 : trailingBlankLines
|
|
842
842
|
description = `${description}${lineEnd.repeat(blankLinesToAdd)}`
|
package/lib/project.js
CHANGED
|
@@ -102,10 +102,14 @@ module.exports = class WorkerProject extends Project {
|
|
|
102
102
|
files: this.files,
|
|
103
103
|
totals,
|
|
104
104
|
tags: this.getTags(),
|
|
105
|
+
allMeta: this.repo.allMeta,
|
|
106
|
+
allContexts: [...this.repo.allContexts],
|
|
107
|
+
allTags: [...this.repo.allTags],
|
|
105
108
|
filter: this.filter,
|
|
106
109
|
defaultFilter: this.defaultFilter,
|
|
107
110
|
actions: this.boardActions,
|
|
108
111
|
plugins: this.pluginManager.getPlugins(),
|
|
112
|
+
queryProps: this.getQueryProps(cards),
|
|
109
113
|
}
|
|
110
114
|
}
|
|
111
115
|
|
|
@@ -177,8 +181,42 @@ module.exports = class WorkerProject extends Project {
|
|
|
177
181
|
getLists(opts) {
|
|
178
182
|
const {tasks = this.getDefaultFilteredCards(), populateFiltered = false} = opts || {}
|
|
179
183
|
return Repository.getTasksByList(this.repo, tasks, true, populateFiltered)
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
getTaskQueryProps(task) {
|
|
187
|
+
const queryProps = []
|
|
188
|
+
if (task) {
|
|
189
|
+
// add all properties of the task to the queryProps array
|
|
190
|
+
Object.keys(task).forEach((key) => {
|
|
191
|
+
if (key === 'data') return
|
|
192
|
+
if (queryProps.includes(key)) return
|
|
193
|
+
|
|
194
|
+
queryProps.push(key)
|
|
195
|
+
|
|
196
|
+
if (_isObject(task[key])) {
|
|
197
|
+
Object.keys(task[key]).forEach((subKey) => {
|
|
198
|
+
if (!queryProps.includes(`${key}.${subKey}`))
|
|
199
|
+
queryProps.push(`${key}.${subKey}`)
|
|
200
|
+
})
|
|
201
|
+
}
|
|
202
|
+
})
|
|
203
|
+
}
|
|
204
|
+
return queryProps
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
getQueryProps(cards) {
|
|
208
|
+
if (!cards) return []
|
|
209
|
+
const queryProps = this.getTaskQueryProps(cards[0])
|
|
210
|
+
return [
|
|
211
|
+
...new Set(queryProps),
|
|
212
|
+
...[...this.repo.metaKeys].map(key => `allMeta.${key}`),
|
|
213
|
+
...[...this.repo.metaKeys].map(key => `meta.${key}`),
|
|
214
|
+
...this.repo.allTags,
|
|
215
|
+
...this.repo.allContexts,
|
|
216
|
+
]
|
|
180
217
|
}
|
|
181
218
|
|
|
219
|
+
|
|
182
220
|
getTags(cards = this.getDefaultFilteredCards()) {
|
|
183
221
|
const tags = []
|
|
184
222
|
cards.forEach((card) => {
|
|
@@ -208,7 +246,8 @@ module.exports = class WorkerProject extends Project {
|
|
|
208
246
|
}
|
|
209
247
|
|
|
210
248
|
getCards(filter, tasks = this.getDefaultFilteredCards()) {
|
|
211
|
-
|
|
249
|
+
tasks = filter ? Repository.query(tasks, filter) : tasks
|
|
250
|
+
return tasks
|
|
212
251
|
}
|
|
213
252
|
|
|
214
253
|
get files() {
|
|
@@ -404,27 +443,31 @@ module.exports = class WorkerProject extends Project {
|
|
|
404
443
|
const filePath = cardData.path
|
|
405
444
|
if (addTemplate) content += cardData.template
|
|
406
445
|
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
446
|
+
content = this.addTagsToContent(tags, content)
|
|
447
|
+
content = this.addContextsToContent(contexts, content)
|
|
448
|
+
content = this.addMetaToContent(meta, content)
|
|
449
|
+
|
|
450
|
+
return new Promise((resolve, reject) => {
|
|
451
|
+
this.repo.addTaskToFile(filePath, list, content, (err, file, task) => {
|
|
452
|
+
if (err) return reject(err)
|
|
453
|
+
|
|
454
|
+
const newList = task.list
|
|
455
|
+
const list = this.lists.find(l => l.name === newList)
|
|
456
|
+
const newPos = this.config.isAddNewCardsToTop() ? 0 : list.tasks.length - 1
|
|
457
|
+
|
|
458
|
+
this.repo.moveTask({ task, newList, newPos }, (err) => {
|
|
459
|
+
if (err) return reject(err)
|
|
460
|
+
|
|
461
|
+
resolve({ file, task })
|
|
462
|
+
})
|
|
422
463
|
})
|
|
423
|
-
|
|
424
|
-
|
|
464
|
+
})
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
addMetaToContent(meta, content) {
|
|
425
468
|
if (meta && meta.length > 0) {
|
|
426
469
|
let metaContent = ''
|
|
427
|
-
meta.forEach(({key, value}) => {
|
|
470
|
+
meta.forEach(({ key, value }) => {
|
|
428
471
|
if (!/^['"]/.test(value) && /\s/.test(value)) value = `"${value}"`
|
|
429
472
|
const metaData = `${key}${this.repo.config.getMetaSep()}${value}`
|
|
430
473
|
if (content.includes(metaData)) return
|
|
@@ -442,12 +485,33 @@ module.exports = class WorkerProject extends Project {
|
|
|
442
485
|
})
|
|
443
486
|
content = Task.addToLastCommentInContent(content, metaContent.trim(), this.config.isMetaNewLine())
|
|
444
487
|
}
|
|
445
|
-
return
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
488
|
+
return content
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
addContextsToContent(contexts, content) {
|
|
492
|
+
if (contexts && contexts.length > 0) {
|
|
493
|
+
let contextContent = ''
|
|
494
|
+
contexts.forEach(context => {
|
|
495
|
+
const contextWithPrefix = `@${context}`
|
|
496
|
+
if (content.includes(contextWithPrefix)) return
|
|
497
|
+
contextContent = `${contextContent} @${context}`
|
|
449
498
|
})
|
|
450
|
-
|
|
499
|
+
content = Task.addToLastCommentInContent(content, contextContent.trim(), this.config.isMetaNewLine())
|
|
500
|
+
}
|
|
501
|
+
return content
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
addTagsToContent(tags, content) {
|
|
505
|
+
if (tags && tags.length > 0) {
|
|
506
|
+
let tagContent = ''
|
|
507
|
+
tags.forEach(tag => {
|
|
508
|
+
const tagWithPrefix = `${this.config.getTagPrefix()}${tag}`
|
|
509
|
+
if (content.includes(tagWithPrefix)) return
|
|
510
|
+
tagContent = `${tagContent} ${tagWithPrefix}`
|
|
511
|
+
})
|
|
512
|
+
content = Task.addToLastCommentInContent(content, tagContent.trim(), this.config.isMetaNewLine())
|
|
513
|
+
}
|
|
514
|
+
return content
|
|
451
515
|
}
|
|
452
516
|
|
|
453
517
|
async deleteTask(task) {
|
package/lib/repository.js
CHANGED
|
@@ -15,6 +15,7 @@ var _get = require('lodash.get'),
|
|
|
15
15
|
_groupBy = require('lodash.groupby'),
|
|
16
16
|
_where = require('lodash.where'),
|
|
17
17
|
_template = require('lodash.template'),
|
|
18
|
+
_union = require('lodash.union'),
|
|
18
19
|
events = require('events'),
|
|
19
20
|
languages = require('./languages'),
|
|
20
21
|
util = require('util'),
|
|
@@ -65,6 +66,10 @@ function Repository(_path, config) {
|
|
|
65
66
|
this.path = _path
|
|
66
67
|
this.files = []
|
|
67
68
|
this.languages = languages
|
|
69
|
+
this.allMeta = {}
|
|
70
|
+
this.metaKeys = new Set()
|
|
71
|
+
this.allTags = new Set()
|
|
72
|
+
this.allContexts = new Set()
|
|
68
73
|
}
|
|
69
74
|
|
|
70
75
|
util.inherits(Repository, events.EventEmitter)
|
|
@@ -165,6 +170,10 @@ Repository.prototype.createListeners = function () {
|
|
|
165
170
|
self.emit('list.found', list)
|
|
166
171
|
self.saveConfig()
|
|
167
172
|
}
|
|
173
|
+
Object.keys(task.allMeta).forEach(key => self.metaKeys.add(key))
|
|
174
|
+
task.allTags.forEach(tag => self.allTags.add(tag))
|
|
175
|
+
task.allContext.forEach(context => self.allContexts.add(context))
|
|
176
|
+
self.allMeta = self.addAllMeta(task.allMeta)
|
|
168
177
|
self.emit(event, task)
|
|
169
178
|
}
|
|
170
179
|
|
|
@@ -177,6 +186,18 @@ Repository.prototype.createListeners = function () {
|
|
|
177
186
|
}
|
|
178
187
|
}
|
|
179
188
|
|
|
189
|
+
Repository.prototype.addAllMeta = function (meta) {
|
|
190
|
+
const allMeta = Object.assign({}, this.allMeta)
|
|
191
|
+
Object.keys(meta).forEach((key) => {
|
|
192
|
+
if (!allMeta[key]) {
|
|
193
|
+
allMeta[key] = meta[key]
|
|
194
|
+
return
|
|
195
|
+
}
|
|
196
|
+
allMeta[key] = _union(allMeta[key], meta[key])
|
|
197
|
+
})
|
|
198
|
+
return allMeta
|
|
199
|
+
}
|
|
200
|
+
|
|
180
201
|
/**
|
|
181
202
|
* Description
|
|
182
203
|
* @method addList
|
|
@@ -645,6 +666,11 @@ Repository.prototype.readFiles = function (files, cb) {
|
|
|
645
666
|
|
|
646
667
|
var self = this
|
|
647
668
|
|
|
669
|
+
this.allMeta = {}
|
|
670
|
+
this.metaKeys = new Set()
|
|
671
|
+
this.allTags = new Set()
|
|
672
|
+
this.allContexts = new Set()
|
|
673
|
+
|
|
648
674
|
var exec = function (files) {
|
|
649
675
|
var completed = 0
|
|
650
676
|
if (files.length < 1) return cb(null, [])
|
|
@@ -1089,8 +1115,13 @@ Repository.prototype.appendTask = function({file, content, list}, cb) {
|
|
|
1089
1115
|
appendContent = `${taskPrefix}#${list}${inLineOrder} ${text}${eol.lf}${taskContent}`
|
|
1090
1116
|
}
|
|
1091
1117
|
appendContent = File.trimBlankLines(appendContent)
|
|
1092
|
-
|
|
1093
|
-
|
|
1118
|
+
fileContent = `${fileContent}${sep}`
|
|
1119
|
+
file.setContent(`${fileContent}${appendContent}${"\n".repeat(2)}`)
|
|
1120
|
+
this.writeAndExtract(file, true, (err, file) => {
|
|
1121
|
+
if (err) return cb(err)
|
|
1122
|
+
const task = file.getTasks().find(task => task.text === text && task.list === list)
|
|
1123
|
+
cb(null, file, task)
|
|
1124
|
+
})
|
|
1094
1125
|
}
|
|
1095
1126
|
|
|
1096
1127
|
Repository.prototype.addTaskToFile = function (filePath, list, content, cb) {
|
package/lib/task.js
CHANGED
|
@@ -12,7 +12,13 @@ var _clone = require('lodash.clone'),
|
|
|
12
12
|
lineEnd = String(eol.auto),
|
|
13
13
|
fastSort = require('fast-sort/dist/sort.js'),
|
|
14
14
|
{ escapeRegExp } = require('./tools'),
|
|
15
|
-
cheerio = require('cheerio')
|
|
15
|
+
cheerio = require('cheerio');
|
|
16
|
+
|
|
17
|
+
const {
|
|
18
|
+
CHECK_REGEX,
|
|
19
|
+
getCheckedData,
|
|
20
|
+
isBeforeTextMarkdownList
|
|
21
|
+
} = require('./adapters/parsers/task/CardContentParser.js')
|
|
16
22
|
|
|
17
23
|
/**
|
|
18
24
|
* Description
|
|
@@ -180,7 +186,7 @@ class Task {
|
|
|
180
186
|
// replace all occurrences of two empty lines in a row with a single empty line
|
|
181
187
|
content = content.replace(/\n\s*\n\s*\n/g, '\n\n')
|
|
182
188
|
let lines = eol.split(content)
|
|
183
|
-
this.text = lines.shift().
|
|
189
|
+
this.text = lines.shift().trimStart()
|
|
184
190
|
if (lines && lines.length > 1 && lines[lines.length - 1].trim() === '') lines.pop()
|
|
185
191
|
this.description = lines
|
|
186
192
|
this.parse()
|
|
@@ -197,24 +203,12 @@ class Task {
|
|
|
197
203
|
}
|
|
198
204
|
}
|
|
199
205
|
|
|
200
|
-
Task.CHECK_REGEX = /^(\s*- )\[([x ])\]/
|
|
201
|
-
Task.getCheckedData = function (content) {
|
|
202
|
-
const taskRegex = new RegExp(Task.CHECK_REGEX)
|
|
203
|
-
const result = taskRegex.exec(content)
|
|
204
|
-
return result
|
|
205
|
-
? {
|
|
206
|
-
pad: result[1].length,
|
|
207
|
-
checked: result[2].trim() !== '',
|
|
208
|
-
}
|
|
209
|
-
: null
|
|
210
|
-
}
|
|
211
|
-
|
|
212
206
|
Task.hasCheckPrefix = function (content) {
|
|
213
|
-
return new RegExp(
|
|
207
|
+
return new RegExp(CHECK_REGEX).test(content)
|
|
214
208
|
}
|
|
215
209
|
|
|
216
210
|
Task.padDescription = function (description = [], beforeText = '') {
|
|
217
|
-
const checkedData =
|
|
211
|
+
const checkedData = getCheckedData(beforeText)
|
|
218
212
|
if (checkedData) {
|
|
219
213
|
return description.map((line) => {
|
|
220
214
|
const paddedLine = line.padStart(line.length + checkedData.pad)
|
|
@@ -225,7 +219,7 @@ Task.padDescription = function (description = [], beforeText = '') {
|
|
|
225
219
|
}
|
|
226
220
|
|
|
227
221
|
Task.trimDescription = function (rawTaskContentLines, beforeText) {
|
|
228
|
-
const checkedData =
|
|
222
|
+
const checkedData = getCheckedData(beforeText)
|
|
229
223
|
if (checkedData) {
|
|
230
224
|
rawTaskContentLines = rawTaskContentLines.map((line) => {
|
|
231
225
|
const lineLength = line.length
|
|
@@ -237,7 +231,7 @@ Task.trimDescription = function (rawTaskContentLines, beforeText) {
|
|
|
237
231
|
}
|
|
238
232
|
|
|
239
233
|
Task.prototype.getCheckedData = function () {
|
|
240
|
-
return
|
|
234
|
+
return getCheckedData(this.beforeText)
|
|
241
235
|
}
|
|
242
236
|
|
|
243
237
|
Task.Types = {
|
|
@@ -417,6 +411,12 @@ Task.prototype.addToLastCommentInContent = Task.addToLastCommentInContent = func
|
|
|
417
411
|
return `${before}${prefix}${toAdd}${prefix}${after}`
|
|
418
412
|
}
|
|
419
413
|
if (!content.endsWith(lf) && content !== '') content = content + lineEnd
|
|
414
|
+
if (isBeforeTextMarkdownList(this.beforeText)) {
|
|
415
|
+
const spaces = this.beforeText.search(/\S|$/)
|
|
416
|
+
content = content.padEnd(content.length + spaces)
|
|
417
|
+
prefix = prefix.padEnd(prefix.length + spaces)
|
|
418
|
+
}
|
|
419
|
+
|
|
420
420
|
return `${content}<!--${prefix}${toAdd}${prefix}-->`
|
|
421
421
|
}
|
|
422
422
|
|