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/task.js
CHANGED
|
@@ -1,26 +1,20 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
_assign = require('lodash.assign'),
|
|
7
|
-
_union = require('lodash.union'),
|
|
8
|
-
_get = require('lodash.get'),
|
|
9
|
-
util = require('util'),
|
|
10
|
-
eol = require('eol'),
|
|
11
|
-
lf = String(eol.lf),
|
|
12
|
-
lineEnd = String(eol.auto),
|
|
13
|
-
fastSort = require('fast-sort/dist/sort.js'),
|
|
14
|
-
{ escapeRegExp } = require('./tools'),
|
|
15
|
-
{ extractWikilinkTopics } = require('./adapters/markdown');
|
|
16
|
-
|
|
17
|
-
const {
|
|
1
|
+
import util from 'util';
|
|
2
|
+
import eol from 'eol';
|
|
3
|
+
import { sort } from 'fast-sort';
|
|
4
|
+
import { extractWikilinkTopics } from './adapters/markdown.js';
|
|
5
|
+
import {
|
|
18
6
|
CHECK_REGEX,
|
|
19
7
|
TASK_TYPES,
|
|
20
8
|
getCheckedData,
|
|
21
9
|
isBeforeTextMarkdownList,
|
|
22
|
-
isNumber
|
|
23
|
-
|
|
10
|
+
isNumber,
|
|
11
|
+
toNumber,
|
|
12
|
+
} from './adapters/parsers/task/CardContentParser.js';
|
|
13
|
+
import { tools } from './tools.js';
|
|
14
|
+
|
|
15
|
+
const { deepEqual, union, escapeRegExp } = tools
|
|
16
|
+
const lf = String(eol.lf);
|
|
17
|
+
const lineEnd = String(eol.auto);
|
|
24
18
|
|
|
25
19
|
/**
|
|
26
20
|
* Description
|
|
@@ -28,9 +22,9 @@ const {
|
|
|
28
22
|
* @param {} obj
|
|
29
23
|
* @return
|
|
30
24
|
*/
|
|
31
|
-
class Task {
|
|
25
|
+
export class Task {
|
|
32
26
|
constructor(config, obj, dontParse) {
|
|
33
|
-
if (
|
|
27
|
+
if (obj == null || typeof obj !== 'object') throw new Error('obj must be an Object')
|
|
34
28
|
this.frontMatter = obj.frontMatter || {
|
|
35
29
|
tags: [],
|
|
36
30
|
context: [],
|
|
@@ -75,12 +69,11 @@ class Task {
|
|
|
75
69
|
}
|
|
76
70
|
|
|
77
71
|
set order(val) {
|
|
78
|
-
|
|
79
|
-
this.innerOrder = isNaN(order) ? null : order
|
|
72
|
+
this.innerOrder = toNumber(val)
|
|
80
73
|
}
|
|
81
74
|
|
|
82
75
|
get order() {
|
|
83
|
-
return this.innerOrder
|
|
76
|
+
return toNumber(this.innerOrder)
|
|
84
77
|
}
|
|
85
78
|
|
|
86
79
|
get descriptionString() {
|
|
@@ -133,10 +126,6 @@ class Task {
|
|
|
133
126
|
return beforeText.length > 0 ? `${beforeText} ` : ''
|
|
134
127
|
}
|
|
135
128
|
|
|
136
|
-
getOrder() {
|
|
137
|
-
return this.order
|
|
138
|
-
}
|
|
139
|
-
|
|
140
129
|
getTextAndDescription() {
|
|
141
130
|
const taskContent = `${this.markdownBeforeText}${this.text}${lineEnd}${this.descriptionString}`
|
|
142
131
|
.replace(/<!--\s*\[\s*([\s\S]*?)\s*\]\s*-->/gm, '$1')
|
|
@@ -187,612 +176,605 @@ class Task {
|
|
|
187
176
|
}
|
|
188
177
|
|
|
189
178
|
toJSON() {
|
|
190
|
-
return
|
|
179
|
+
return Object.assign({}, this, {
|
|
191
180
|
allTags: this.allTags,
|
|
192
181
|
allContext: this.allContext,
|
|
193
182
|
allMeta: this.allMeta,
|
|
194
183
|
config: undefined,
|
|
195
|
-
expand: !!
|
|
184
|
+
expand: !!(this?.allMeta?.expand && this.allMeta.expand[0]),
|
|
196
185
|
})
|
|
197
186
|
}
|
|
198
|
-
}
|
|
199
|
-
const DATE_META_KEYS = Task.DATE_META_KEYS = ['due', 'defer', 'created', 'started', 'remind', 'completed', 'archivedAt']
|
|
200
187
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
}
|
|
188
|
+
getTagPrefix () {
|
|
189
|
+
return this.config?.getTagPrefix()
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
static addToLastCommentInContent (content, toAdd, newLine) {
|
|
193
|
+
// BACKLOG respect padding of task prefix for list items
|
|
194
|
+
// <!--
|
|
195
|
+
// order:-680
|
|
196
|
+
// -->
|
|
197
|
+
let prefix = newLine ? lineEnd : ' '
|
|
198
|
+
const commentRegex = /<!--([\s\S]*?)-->/gm
|
|
199
|
+
let result, lastIndex, index
|
|
200
|
+
while ((result = commentRegex.exec(content))) {
|
|
201
|
+
lastIndex = commentRegex.lastIndex
|
|
202
|
+
index = result.index
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
if (lastIndex > 0) {
|
|
206
|
+
let before = content.slice(0, lastIndex - 3).trimEnd()
|
|
207
|
+
const after = content.slice(lastIndex - 3)
|
|
208
|
+
return `${before}${prefix}${toAdd}${prefix}${after}`
|
|
209
|
+
}
|
|
210
|
+
if (!content.endsWith(lf) && content !== '') content = content + lineEnd
|
|
211
|
+
if (isBeforeTextMarkdownList(this.beforeText)) {
|
|
212
|
+
const spaces = this.beforeText.search(/\S|$/)
|
|
213
|
+
content = content.padEnd(content.length + spaces)
|
|
214
|
+
prefix = prefix.padEnd(prefix.length + spaces)
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
return `${content}<!--${prefix}${toAdd}${prefix}-->`
|
|
218
|
+
}
|
|
204
219
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
if (checkedData) {
|
|
208
|
-
return description.map((line) => {
|
|
209
|
-
const paddedLine = line.padStart(line.length + checkedData.pad)
|
|
210
|
-
return paddedLine.trim() ? paddedLine : ''
|
|
211
|
-
})
|
|
220
|
+
addToLastCommentInContent (content, toAdd, newLine) {
|
|
221
|
+
return Task.addToLastCommentInContent(content, toAdd, newLine)
|
|
212
222
|
}
|
|
213
|
-
return description
|
|
214
|
-
}
|
|
215
223
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
return
|
|
224
|
+
getCheckedData () {
|
|
225
|
+
return getCheckedData(this.beforeText)
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
updateOrderMeta (config, descContent = this.descriptionString) {
|
|
229
|
+
if (config.orderMeta) {
|
|
230
|
+
if (!isNumber(this.order)) return this.order = undefined
|
|
231
|
+
const metaSep = config.getMetaSep()
|
|
232
|
+
if (this.meta.order) {
|
|
233
|
+
const regex = Task.getMetaOrderRegex(config)
|
|
234
|
+
descContent = descContent.replace(regex, `order${metaSep}${this.order}`)
|
|
235
|
+
} else {
|
|
236
|
+
const addNewLine = config.isMetaNewLine()
|
|
237
|
+
descContent = this.addToLastCommentInContent(
|
|
238
|
+
descContent,
|
|
239
|
+
`order${metaSep}${this.order}`,
|
|
240
|
+
addNewLine
|
|
241
|
+
)
|
|
242
|
+
}
|
|
243
|
+
this.meta.order = isNumber(this.order) ? [this.order] : undefined
|
|
244
|
+
} else {
|
|
245
|
+
descContent = Task.removeMetaData({
|
|
246
|
+
config,
|
|
247
|
+
content: descContent,
|
|
248
|
+
key: 'order',
|
|
249
|
+
value: Task.parseMetaData(config, descContent).order,
|
|
250
|
+
})
|
|
251
|
+
}
|
|
252
|
+
this.description = descContent.split(lineEnd)
|
|
253
|
+
this.updateContent()
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
replaceContent (regex, replacement) {
|
|
257
|
+
this.text = this.text.replace(regex, replacement)
|
|
258
|
+
this.description = this.description.map((line) =>
|
|
259
|
+
line.replace(regex, replacement)
|
|
260
|
+
)
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
replaceMetaSep (oldMetaSep, newMetaSep) {
|
|
264
|
+
Object.keys(this.meta).forEach((key) => {
|
|
265
|
+
const metaValues = this.meta[key]
|
|
266
|
+
metaValues.forEach((metaValue) => {
|
|
267
|
+
let regex = new RegExp(escapeRegExp(`${key}${oldMetaSep}"${metaValue}"`))
|
|
268
|
+
this.replaceContent(regex, `${key}${newMetaSep}"${metaValue}"`)
|
|
269
|
+
if (metaValue && !metaValue.toString().includes(' ')) {
|
|
270
|
+
regex = new RegExp(escapeRegExp(`${key}${oldMetaSep}${metaValue}`))
|
|
271
|
+
this.replaceContent(regex, `${key}${newMetaSep}${metaValue}`)
|
|
272
|
+
}
|
|
273
|
+
})
|
|
223
274
|
})
|
|
224
275
|
}
|
|
225
|
-
return rawTaskContentLines
|
|
226
|
-
}
|
|
227
276
|
|
|
228
|
-
|
|
229
|
-
return getCheckedData(this.beforeText)
|
|
230
|
-
}
|
|
277
|
+
static DATE_META_KEYS = ['due', 'defer', 'created', 'started', 'remind', 'completed', 'archivedAt']
|
|
231
278
|
|
|
232
|
-
|
|
279
|
+
static hasCheckPrefix (content) {
|
|
280
|
+
return new RegExp(CHECK_REGEX).test(content)
|
|
281
|
+
}
|
|
233
282
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
283
|
+
static padDescription (description = [], beforeText = '') {
|
|
284
|
+
const checkedData = getCheckedData(beforeText)
|
|
285
|
+
if (checkedData) {
|
|
286
|
+
return description.map((line) => {
|
|
287
|
+
const paddedLine = line.padStart(line.length + checkedData.pad)
|
|
288
|
+
return paddedLine.trim() ? paddedLine : ''
|
|
289
|
+
})
|
|
290
|
+
}
|
|
291
|
+
return description
|
|
292
|
+
}
|
|
237
293
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
const codePositions = Task.getMarkdownCodePositions(text);
|
|
247
|
-
const linkLabelPositions = Task.getMarkdownLinkLabelPositions(text);
|
|
248
|
-
let result;
|
|
249
|
-
const re = Task.getTagRegexp(prefix);
|
|
250
|
-
|
|
251
|
-
while ((result = re.exec(text)) !== null) {
|
|
252
|
-
if (Task.isResultInMarkdownCode(codePositions, result.index)) continue;
|
|
253
|
-
if (Task.isResultInMarkdownLinkLabel(linkLabelPositions, result.index)) continue;
|
|
254
|
-
const tag = result[2];
|
|
255
|
-
if (tags.includes(tag) || /^[#]+$/.test(tag)) continue;
|
|
256
|
-
tags.push(tag);
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
return tags;
|
|
260
|
-
};
|
|
261
|
-
|
|
262
|
-
Task.getMarkdownLinkLabelPositions = function (text) {
|
|
263
|
-
const positions = [];
|
|
264
|
-
const re = /\[([^\]]+)\]\([^\)]+\)/g;
|
|
265
|
-
let match;
|
|
266
|
-
|
|
267
|
-
while ((match = re.exec(text)) !== null) {
|
|
268
|
-
positions.push({ start: match.index, end: re.lastIndex });
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
return positions;
|
|
272
|
-
};
|
|
273
|
-
|
|
274
|
-
Task.isResultInMarkdownLinkLabel = function (linkLabelPositions, index) {
|
|
275
|
-
return linkLabelPositions.some(pos => index >= pos.start && index < pos.end);
|
|
276
|
-
};
|
|
277
|
-
|
|
278
|
-
Task.ContextRegExp = new RegExp(
|
|
279
|
-
`(^|\\s)@([${Task.AnyLanguageGroup}${Task.EmojiGroup}]+)`,
|
|
280
|
-
'gmiu'
|
|
281
|
-
)
|
|
282
|
-
|
|
283
|
-
Task.getContext = function (text) {
|
|
284
|
-
const context = []
|
|
285
|
-
var codePositions = Task.getMarkdownCodePositions(text)
|
|
286
|
-
var result,
|
|
287
|
-
re = new RegExp(Task.ContextRegExp)
|
|
288
|
-
|
|
289
|
-
while ((result = re.exec(text)) !== null) {
|
|
290
|
-
if (Task.isResultInMarkdownCode(codePositions, result.index)) continue
|
|
291
|
-
const con = result[2]
|
|
292
|
-
if (!context.includes(con)) context.push(con)
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
return context
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
Task.MetaRegExp = new RegExp(
|
|
299
|
-
`(^|\\s)([a-zA-Z-_]+?):(?!\\/\\/)([${Task.AnyLanguageGroup}${Task.EmojiGroup}]+)`,
|
|
300
|
-
'gu'
|
|
301
|
-
)
|
|
302
|
-
Task.getMetaRegExp = function (config) {
|
|
303
|
-
return new RegExp(
|
|
304
|
-
`(^|\\s)([a-zA-Z-_]+?)${config.getMetaSep()}(?![*_]+)(?!\\/\\/)([${
|
|
305
|
-
Task.AnyLanguageGroup
|
|
306
|
-
}${Task.EmojiGroup}]+)`,
|
|
307
|
-
'gu'
|
|
308
|
-
)
|
|
309
|
-
}
|
|
310
|
-
Task.getMetaRegExpQuotes = function (config) {
|
|
311
|
-
return new RegExp(
|
|
312
|
-
`(^|\\s)([a-zA-Z-_]+?)${config.getMetaSep()}(?![*_]+)"((?${config.getMetaSep()}""|[^"]|[${
|
|
313
|
-
Task.AnyLanguageGroup
|
|
314
|
-
}${Task.EmojiGroup}])*)"`,
|
|
315
|
-
'gu'
|
|
316
|
-
)
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
Task.parseMetaData = function (config, content) {
|
|
320
|
-
var meta = {}
|
|
321
|
-
Task.eachMetaInContent(config, content, (result) => {
|
|
322
|
-
var key = result[2]
|
|
323
|
-
var val = result[3]
|
|
324
|
-
if (!meta[key]) meta[key] = []
|
|
325
|
-
if (!meta[key].push) return
|
|
326
|
-
meta[key].push(val)
|
|
327
|
-
})
|
|
328
|
-
return meta
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
Task.getMetaData = function (config, task) {
|
|
332
|
-
var text = Task.isTask(task) ? task.getRawTextAndDescription() : task
|
|
333
|
-
var meta = Task.parseMetaData(config, text)
|
|
334
|
-
Object.entries(meta).forEach(([key, val]) => {
|
|
335
|
-
if (DATE_META_KEYS.includes(key)) {
|
|
336
|
-
try {
|
|
337
|
-
const date = new Date(val)
|
|
338
|
-
task[key] = date.toISOString()
|
|
339
|
-
task[`${key}Date`] = date.toISOString()
|
|
340
|
-
} catch (e) {}
|
|
294
|
+
static trimDescription (rawTaskContentLines, beforeText) {
|
|
295
|
+
const checkedData = getCheckedData(beforeText)
|
|
296
|
+
if (checkedData) {
|
|
297
|
+
rawTaskContentLines = rawTaskContentLines.map((line) => {
|
|
298
|
+
const lineLength = line.length
|
|
299
|
+
line = line.trimStart()
|
|
300
|
+
return line.padStart(lineLength - checkedData.pad)
|
|
301
|
+
})
|
|
341
302
|
}
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
Task.
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
return /\r\n|\r/.test(content)
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
Task.getLinePos = function (content, lineNo) {
|
|
374
|
-
var re = /^/gm
|
|
375
|
-
var line = 1
|
|
376
|
-
var result
|
|
377
|
-
const normalizedContent = eol.lf(content)
|
|
378
|
-
while ((result = re.exec(normalizedContent)) !== null) {
|
|
379
|
-
if (line == lineNo) {
|
|
380
|
-
return Task.hasWindowsEOL(content)
|
|
381
|
-
? result.index + line - 1
|
|
382
|
-
: result.index
|
|
303
|
+
return rawTaskContentLines
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
static Types = TASK_TYPES
|
|
307
|
+
|
|
308
|
+
static AnyLanguageGroup =
|
|
309
|
+
'#\\w:%/.$-\\u1FD3\\u1FD6-\\u1FDB\\u1FE0-\\u1FEC\\u1FF2-\\u1FF4\\u1FF6-\\u1FFC\\u2071\\u207F\\u2090-\\u209C\\u2102\\u2107\\u210A-\\u2113\\u2115\\u2119-\\u211D\\u2124\\u2126\\u2128\\u212A-\\u212D\\u212F-\\u2139\\u213C-\\u213F\\u2145-\\u2149\\u214E\\u2183\\u2184\\u2C00-\\u2C2E\\u2C30-\\u2C5E\\u2C60-\\u2CE4\\u2CEB-\\u2CEE\\u2CF2\\u2CF3\\u2D00-\\u2D25\\u2D27\\u2D2D\\u2D30-\\u2D67\\u2D6F\\u2D80-\\u2D96\\u2DA0-\\u2DA6\\u2DA8-\\u2DAE\\u2DB0-\\u2DB6\\u2DB8-\\u2DBE\\u2DC0-\\u2DC6\\u2DC8-\\u2DCE\\u2DD0-\\u2DD6\\u2DD8-\\u2DDE\\u2E2F\\u3005\\u3006\\u3031-\\u3035\\u303B\\u303C\\u3041-\\u3096\\u309D-\\u309F\\u30A1-\\u30FA\\u30FC-\\u30FF\\u3105-\\u312D\\u3131-\\u318E\\u31A0-\\u31BA\\u31F0-\\u31FF\\u3400-\\u4DB5\\u4E00-\\u9FCC\\uA000-\\uA48C\\uA4D0-\\uA4FD\\uA500-\\uA60C\\uA610-\\uA61F\\uA62A\\uA62B\\uA640-\\uA66E\\uA67F-\\uA697\\uA6A0-\\uA6E5\\uA717-\\uA71F\\uA722-\\uA788\\uA78B-\\uA78E\\uA790-\\uA793\\uA7A0-\\uA7AA\\uA7F8-\\uA801\\uA803-\\uA805\\uA807-\\uA80A\\uA80C-\\uA822\\uA840-\\uA873\\uA882-\\uA8B3\\uA8F2-\\uA8F7\\uA8FB\\uA90A-\\uA925\\uA930-\\uA946\\uA960-\\uA97C\\uA984-\\uA9B2\\uA9CF\\uAA00-\\uAA28\\uAA40-\\uAA42\\uAA44-\\uAA4B\\uAA60-\\uAA76\\uAA7A\\uAA80-\\uAAAF\\uAAB1\\uAAB5\\uAAB6\\uAAB9-\\uAABD\\uAAC0\\uAAC2\\uAADB-\\uAADD\\uAAE0-\\uAAEA\\uAAF2-\\uAAF4\\uAB01-\\uAB06\\uAB09-\\uAB0E\\uAB11-\\uAB16\\uAB20-\\uAB26\\uAB28-\\uAB2E\\uABC0-\\uABE2\\uAC00-\\uD7A3\\uD7B0-\\uD7C6\\uD7CB-\\uD7FB\\uF900-\\uFA6D\\uFA70-\\uFAD9\\uFB00-\\uFB06\\uFB13-\\uFB17\\uFB1D\\uFB1F-\\uFB28\\uFB2A-\\uFB36\\uFB38-\\uFB3C\\uFB3E\\uFB40\\uFB41\\uFB43\\uFB44\\uFB46-\\uFBB1\\uFBD3-\\uFD3D\\uFD50-\\uFD8F\\uFD92-\\uFDC7\\uFDF0-\\uFDFB\\uFE70-\\uFE74\\uFE76-\\uFEFC\\uFF21-\\uFF3A\\uFF41-\\uFF5A\\uFF66-\\uFFBE\\uFFC2-\\uFFC7\\uFFCA-\\uFFCF\\uFFD2-\\uFFD7\\uFFDA-\\uFFDC'
|
|
310
|
+
static EmojiGroup = '\\p{Emoji_Presentation}'
|
|
311
|
+
|
|
312
|
+
static getTagRegexp (prefix = '+') {
|
|
313
|
+
return new RegExp(
|
|
314
|
+
`(^|\\s)[${prefix}](?![${Task.AnyLanguageGroup}${Task.EmojiGroup}]*##)([${Task.AnyLanguageGroup}${Task.EmojiGroup}]+)`,
|
|
315
|
+
'gmiu'
|
|
316
|
+
)
|
|
317
|
+
}
|
|
318
|
+
static getTags (text, prefix = '+') {
|
|
319
|
+
const tags = [];
|
|
320
|
+
const codePositions = Task.getMarkdownCodePositions(text);
|
|
321
|
+
const linkLabelPositions = Task.getMarkdownLinkLabelPositions(text);
|
|
322
|
+
let result;
|
|
323
|
+
const re = Task.getTagRegexp(prefix);
|
|
324
|
+
|
|
325
|
+
while ((result = re.exec(text)) !== null) {
|
|
326
|
+
if (Task.isResultInMarkdownCode(codePositions, result.index)) continue;
|
|
327
|
+
if (Task.isResultInMarkdownLinkLabel(linkLabelPositions, result.index)) continue;
|
|
328
|
+
const tag = result[2];
|
|
329
|
+
if (tags.includes(tag) || /^[#]+$/.test(tag)) continue;
|
|
330
|
+
tags.push(tag);
|
|
383
331
|
}
|
|
384
|
-
if (result.index === re.lastIndex) re.lastIndex++
|
|
385
|
-
line++
|
|
386
|
-
}
|
|
387
|
-
return content.length
|
|
388
|
-
}
|
|
389
332
|
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
const lines = eol.split(contentBeforePos)
|
|
393
|
-
return lines.length
|
|
394
|
-
}
|
|
333
|
+
return tags;
|
|
334
|
+
};
|
|
395
335
|
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
336
|
+
static getMarkdownLinkLabelPositions (text) {
|
|
337
|
+
const positions = [];
|
|
338
|
+
const re = /\[([^\]]+)\]\([^\)]+\)/g;
|
|
339
|
+
let match;
|
|
399
340
|
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
let before = content.slice(0, lastIndex - 3).trimEnd()
|
|
415
|
-
const after = content.slice(lastIndex - 3)
|
|
416
|
-
return `${before}${prefix}${toAdd}${prefix}${after}`
|
|
417
|
-
}
|
|
418
|
-
if (!content.endsWith(lf) && content !== '') content = content + lineEnd
|
|
419
|
-
if (isBeforeTextMarkdownList(this.beforeText)) {
|
|
420
|
-
const spaces = this.beforeText.search(/\S|$/)
|
|
421
|
-
content = content.padEnd(content.length + spaces)
|
|
422
|
-
prefix = prefix.padEnd(prefix.length + spaces)
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
return `${content}<!--${prefix}${toAdd}${prefix}-->`
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
Task.getMetaOrderRegex = function (config) {
|
|
429
|
-
const metaSep = config.getMetaSep()
|
|
430
|
-
return new RegExp(
|
|
431
|
-
`order${metaSep}("(-?[\\d.]+(?:e-?\\d+)?)"|(-?[\\d.]+(?:e-?\\d+)?))`,
|
|
432
|
-
'gm'
|
|
341
|
+
while ((match = re.exec(text)) !== null) {
|
|
342
|
+
positions.push({ start: match.index, end: re.lastIndex });
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
return positions;
|
|
346
|
+
};
|
|
347
|
+
|
|
348
|
+
static isResultInMarkdownLinkLabel (linkLabelPositions, index) {
|
|
349
|
+
return linkLabelPositions.some(pos => index >= pos.start && index < pos.end);
|
|
350
|
+
};
|
|
351
|
+
|
|
352
|
+
static ContextRegExp = new RegExp(
|
|
353
|
+
`(^|\\s)@([${Task.AnyLanguageGroup}${Task.EmojiGroup}]+)`,
|
|
354
|
+
'gmiu'
|
|
433
355
|
)
|
|
434
|
-
}
|
|
435
356
|
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
descContent,
|
|
447
|
-
`order${metaSep}${this.order}`,
|
|
448
|
-
addNewLine
|
|
449
|
-
)
|
|
357
|
+
static getContext (text) {
|
|
358
|
+
const context = []
|
|
359
|
+
var codePositions = Task.getMarkdownCodePositions(text)
|
|
360
|
+
var result,
|
|
361
|
+
re = new RegExp(Task.ContextRegExp)
|
|
362
|
+
|
|
363
|
+
while ((result = re.exec(text)) !== null) {
|
|
364
|
+
if (Task.isResultInMarkdownCode(codePositions, result.index)) continue
|
|
365
|
+
const con = result[2]
|
|
366
|
+
if (!context.includes(con)) context.push(con)
|
|
450
367
|
}
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
descContent = Task.removeMetaData({
|
|
454
|
-
config,
|
|
455
|
-
content: descContent,
|
|
456
|
-
key: 'order',
|
|
457
|
-
value: Task.parseMetaData(config, descContent).order,
|
|
458
|
-
})
|
|
368
|
+
|
|
369
|
+
return context
|
|
459
370
|
}
|
|
460
|
-
this.description = descContent.split(lineEnd)
|
|
461
|
-
this.updateContent()
|
|
462
|
-
}
|
|
463
371
|
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
line.replace(regex, replacement)
|
|
372
|
+
static MetaRegExp = new RegExp(
|
|
373
|
+
`(^|\\s)([a-zA-Z-_]+?):(?!\\/\\/)([${Task.AnyLanguageGroup}${Task.EmojiGroup}]+)`,
|
|
374
|
+
'gu'
|
|
468
375
|
)
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
376
|
+
static getMetaRegExp (config) {
|
|
377
|
+
return new RegExp(
|
|
378
|
+
`(^|\\s)([a-zA-Z-_]+?)${config.getMetaSep()}(?![*_]+)(?!\\/\\/)([${
|
|
379
|
+
Task.AnyLanguageGroup
|
|
380
|
+
}${Task.EmojiGroup}]+)`,
|
|
381
|
+
'gu'
|
|
382
|
+
)
|
|
383
|
+
}
|
|
384
|
+
static getMetaRegExpQuotes (config) {
|
|
385
|
+
return new RegExp(
|
|
386
|
+
`(^|\\s)([a-zA-Z-_]+?)${config.getMetaSep()}(?![*_]+)"((?${config.getMetaSep()}""|[^"]|[${
|
|
387
|
+
Task.AnyLanguageGroup
|
|
388
|
+
}${Task.EmojiGroup}])*)"`,
|
|
389
|
+
'gu'
|
|
390
|
+
)
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
static parseMetaData (config, content) {
|
|
394
|
+
var meta = {}
|
|
395
|
+
Task.eachMetaInContent(config, content, (result) => {
|
|
396
|
+
var key = result[2]
|
|
397
|
+
var val = result[3]
|
|
398
|
+
if (!meta[key]) meta[key] = []
|
|
399
|
+
if (!meta[key].push) return
|
|
400
|
+
meta[key].push(val)
|
|
401
|
+
})
|
|
402
|
+
return meta
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
static getMetaData (config, task) {
|
|
406
|
+
var text = Task.isTask(task) ? task.getRawTextAndDescription() : task
|
|
407
|
+
var meta = Task.parseMetaData(config, text)
|
|
408
|
+
Object.entries(meta).forEach(([key, val]) => {
|
|
409
|
+
if (Task.DATE_META_KEYS.includes(key)) {
|
|
410
|
+
try {
|
|
411
|
+
const date = new Date(val)
|
|
412
|
+
task[key] = date.toISOString()
|
|
413
|
+
task[`${key}Date`] = date.toISOString()
|
|
414
|
+
} catch (e) {}
|
|
480
415
|
}
|
|
481
416
|
})
|
|
482
|
-
|
|
483
|
-
}
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
Task.getMarkdownCodePositions = function (text) {
|
|
496
|
-
const re = /(```[\s\S]*?```|`[^`]+`)/g;
|
|
497
|
-
let result;
|
|
498
|
-
let positions = [];
|
|
499
|
-
while ((result = re.exec(text)) !== null) {
|
|
500
|
-
const start = result.index;
|
|
501
|
-
const end = start + result[0].length;
|
|
502
|
-
positions.push({ start, end });
|
|
503
|
-
}
|
|
504
|
-
return positions;
|
|
505
|
-
};
|
|
506
|
-
|
|
507
|
-
Task.isResultInMarkdownCode = function (positions, index) {
|
|
508
|
-
for (let i = 0; i < positions.length; i++) {
|
|
509
|
-
const { start, end } = positions[i]
|
|
510
|
-
if (index > start && index < end) return true
|
|
511
|
-
}
|
|
512
|
-
return false
|
|
513
|
-
}
|
|
514
|
-
|
|
515
|
-
Task.prototype.parseTodoTxt = function () {
|
|
516
|
-
this.tags = Task.getTags(this.getRawTextAndDescription(), this.getTagPrefix())
|
|
517
|
-
this.context = Task.getContext(this.getRawTextAndDescription())
|
|
518
|
-
this.meta = Task.getMetaData(this.config, this)
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
Task.removeTags = function (text, prefix = '+') {
|
|
522
|
-
const codePositions = Task.getMarkdownCodePositions(text);
|
|
523
|
-
const linkLabelPositions = Task.getMarkdownLinkLabelPositions(text);
|
|
524
|
-
return text.replace(Task.getTagRegexp(prefix), (match, p1, p2, offset) => {
|
|
525
|
-
if (Task.isResultInMarkdownCode(codePositions, offset) || Task.isResultInMarkdownLinkLabel(linkLabelPositions, offset) || match.includes('##')) {
|
|
526
|
-
return match;
|
|
417
|
+
return meta
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
static execMetaRegex (re, content, codePositions, cb) {
|
|
421
|
+
let result
|
|
422
|
+
while ((result = re.exec(content)) !== null) {
|
|
423
|
+
const index = result.index
|
|
424
|
+
if (Task.isResultInMarkdownCode(codePositions, index)) continue
|
|
425
|
+
var key = result[2]
|
|
426
|
+
if (/[\(<]{1}(http|ssh|ftp|git)/.test(key)) continue
|
|
427
|
+
if (!/^[^$][^\s\.]+$/.test(key)) continue
|
|
428
|
+
cb(result)
|
|
527
429
|
}
|
|
528
|
-
|
|
529
|
-
});
|
|
530
|
-
};
|
|
531
|
-
|
|
532
|
-
Task.removeContext = function (text) {
|
|
533
|
-
const positions = Task.getMarkdownCodePositions(text)
|
|
534
|
-
return text.replace(
|
|
535
|
-
new RegExp(Task.ContextRegExp),
|
|
536
|
-
(match, p1, p2, offset) => {
|
|
537
|
-
if (Task.isResultInMarkdownCode(positions, offset)) return match
|
|
538
|
-
return ''
|
|
539
|
-
}
|
|
540
|
-
)
|
|
541
|
-
}
|
|
430
|
+
}
|
|
542
431
|
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
text += ` @${context}`
|
|
553
|
-
})
|
|
554
|
-
this.text = text
|
|
432
|
+
static eachMetaInContent (config, content, cb) {
|
|
433
|
+
var codePositions = Task.getMarkdownCodePositions(content)
|
|
434
|
+
Task.execMetaRegex(Task.getMetaRegExp(config), content, codePositions, cb)
|
|
435
|
+
Task.execMetaRegex(
|
|
436
|
+
Task.getMetaRegExpQuotes(config),
|
|
437
|
+
content,
|
|
438
|
+
codePositions,
|
|
439
|
+
cb
|
|
440
|
+
)
|
|
555
441
|
}
|
|
556
|
-
}
|
|
557
442
|
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
443
|
+
static hasWindowsEOL (content) {
|
|
444
|
+
return /\r\n|\r/.test(content)
|
|
445
|
+
}
|
|
561
446
|
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
447
|
+
static getLinePos (content, lineNo) {
|
|
448
|
+
var re = /^/gm
|
|
449
|
+
var line = 1
|
|
450
|
+
var result
|
|
451
|
+
const normalizedContent = eol.lf(content)
|
|
452
|
+
while ((result = re.exec(normalizedContent)) !== null) {
|
|
453
|
+
if (line == lineNo) {
|
|
454
|
+
return Task.hasWindowsEOL(content)
|
|
455
|
+
? result.index + line - 1
|
|
456
|
+
: result.index
|
|
457
|
+
}
|
|
458
|
+
if (result.index === re.lastIndex) re.lastIndex++
|
|
459
|
+
line++
|
|
460
|
+
}
|
|
461
|
+
return content.length
|
|
462
|
+
}
|
|
575
463
|
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
}
|
|
608
|
-
|
|
609
|
-
Task.prototype.getListTrackingMeta = function (lists) {
|
|
610
|
-
const taskMeta = this.meta
|
|
611
|
-
let listTrackingMeta = []
|
|
612
|
-
lists.forEach((list) => {
|
|
613
|
-
if (taskMeta[list]) {
|
|
614
|
-
const listMeta = taskMeta[list].map((timestamp) => ({ list, timestamp }))
|
|
615
|
-
listTrackingMeta = listTrackingMeta.concat(listMeta)
|
|
464
|
+
static getLineNumber (content, pos) {
|
|
465
|
+
const contentBeforePos = content.substring(0, pos)
|
|
466
|
+
const lines = eol.split(contentBeforePos)
|
|
467
|
+
return lines.length
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
static getMetaOrderRegex (config) {
|
|
471
|
+
const metaSep = config.getMetaSep()
|
|
472
|
+
return new RegExp(
|
|
473
|
+
`order${metaSep}("(-?[\\d.]+(?:e-?\\d+)?)"|(-?[\\d.]+(?:e-?\\d+)?))`,
|
|
474
|
+
'gm'
|
|
475
|
+
)
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
/**
|
|
479
|
+
* Description
|
|
480
|
+
* @method isTask
|
|
481
|
+
* @param {} task
|
|
482
|
+
* @return BinaryExpression
|
|
483
|
+
*/
|
|
484
|
+
static isTask (task) {
|
|
485
|
+
return task instanceof Task
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
static getMarkdownCodePositions (text) {
|
|
489
|
+
const re = /(```[\s\S]*?```|`[^`]+`)/g;
|
|
490
|
+
let result;
|
|
491
|
+
let positions = [];
|
|
492
|
+
while ((result = re.exec(text)) !== null) {
|
|
493
|
+
const start = result.index;
|
|
494
|
+
const end = start + result[0].length;
|
|
495
|
+
positions.push({ start, end });
|
|
616
496
|
}
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
}
|
|
620
|
-
|
|
621
|
-
Task.prototype.hasListChanged = function (lists) {
|
|
622
|
-
const listTrackingMeta = this.getListTrackingMeta(lists)
|
|
623
|
-
return (
|
|
624
|
-
listTrackingMeta.length === 0 || listTrackingMeta.pop().list !== this.list
|
|
625
|
-
)
|
|
626
|
-
}
|
|
497
|
+
return positions;
|
|
498
|
+
};
|
|
627
499
|
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
500
|
+
static isResultInMarkdownCode (positions, index) {
|
|
501
|
+
for (let i = 0; i < positions.length; i++) {
|
|
502
|
+
const { start, end } = positions[i]
|
|
503
|
+
if (index > start && index < end) return true
|
|
504
|
+
}
|
|
505
|
+
return false
|
|
506
|
+
}
|
|
634
507
|
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
})
|
|
656
|
-
})
|
|
657
|
-
})
|
|
508
|
+
static removeTags (text, prefix = '+') {
|
|
509
|
+
const codePositions = Task.getMarkdownCodePositions(text);
|
|
510
|
+
const linkLabelPositions = Task.getMarkdownLinkLabelPositions(text);
|
|
511
|
+
return text.replace(Task.getTagRegexp(prefix), (match, p1, p2, offset) => {
|
|
512
|
+
if (Task.isResultInMarkdownCode(codePositions, offset) || Task.isResultInMarkdownLinkLabel(linkLabelPositions, offset) || match.includes('##')) {
|
|
513
|
+
return match;
|
|
514
|
+
}
|
|
515
|
+
return '';
|
|
516
|
+
});
|
|
517
|
+
};
|
|
518
|
+
|
|
519
|
+
static removeContext (text) {
|
|
520
|
+
const positions = Task.getMarkdownCodePositions(text)
|
|
521
|
+
return text.replace(
|
|
522
|
+
new RegExp(Task.ContextRegExp),
|
|
523
|
+
(match, p1, p2, offset) => {
|
|
524
|
+
if (Task.isResultInMarkdownCode(positions, offset)) return match
|
|
525
|
+
return ''
|
|
526
|
+
}
|
|
527
|
+
)
|
|
658
528
|
}
|
|
659
529
|
|
|
660
|
-
|
|
661
|
-
|
|
530
|
+
static removeMetaDataFromText (config, text) {
|
|
531
|
+
const re = Task.getMetaRegExp(config)
|
|
532
|
+
const re2 = Task.getMetaRegExpQuotes(config)
|
|
662
533
|
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
534
|
+
const positions = Task.getMarkdownCodePositions(text)
|
|
535
|
+
return text
|
|
536
|
+
.replace(re, (match, p1, p2, p3, offset) => {
|
|
537
|
+
if (/[\(<]{1}(http|ssh|ftp|git)/.test(p1)) return match
|
|
538
|
+
if (Task.isResultInMarkdownCode(positions, offset)) return match
|
|
539
|
+
return ''
|
|
540
|
+
})
|
|
541
|
+
.replace(re2, (match, p1, p2, p3, offset) => {
|
|
542
|
+
if (/[\(<]{1}(http|ssh|ftp|git)/.test(p1)) return match
|
|
543
|
+
if (Task.isResultInMarkdownCode(positions, offset)) return match
|
|
544
|
+
return ''
|
|
545
|
+
})
|
|
670
546
|
}
|
|
671
|
-
}
|
|
672
547
|
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
548
|
+
static removeMetaData ({ config, content, key, value }) {
|
|
549
|
+
return content.replace(
|
|
550
|
+
new RegExp(`${key}${config.getMetaSep()}"?${value}"?\\s`, 'g'),
|
|
551
|
+
''
|
|
552
|
+
)
|
|
553
|
+
}
|
|
554
|
+
updateContext () {
|
|
555
|
+
// BACKLOG implement updateContext id:1 gh:124
|
|
556
|
+
// <!--
|
|
557
|
+
// order:-690
|
|
558
|
+
// -->
|
|
559
|
+
var self = this
|
|
560
|
+
if (this.context) {
|
|
561
|
+
let text = Task.removeContext(this.text)
|
|
562
|
+
this.context.forEach((context) => {
|
|
563
|
+
text += ` @${context}`
|
|
564
|
+
})
|
|
565
|
+
this.text = text
|
|
566
|
+
}
|
|
567
|
+
}
|
|
682
568
|
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
Task.prototype.getRepoId = function () {
|
|
689
|
-
return this.repoId
|
|
690
|
-
}
|
|
569
|
+
parseTodoTxt () {
|
|
570
|
+
this.tags = Task.getTags(this.getRawTextAndDescription(), this.getTagPrefix())
|
|
571
|
+
this.context = Task.getContext(this.getRawTextAndDescription())
|
|
572
|
+
this.meta = Task.getMetaData(this.config, this)
|
|
573
|
+
}
|
|
691
574
|
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
*/
|
|
697
|
-
Task.prototype.getSource = function () {
|
|
698
|
-
return this.source
|
|
699
|
-
}
|
|
575
|
+
getTags () {
|
|
576
|
+
if (!this.tags) this.tags = []
|
|
577
|
+
return union(this.tags, this.frontMatter.tags)
|
|
578
|
+
}
|
|
700
579
|
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
*/
|
|
706
|
-
Task.prototype.getId = function () {
|
|
707
|
-
return this.id
|
|
708
|
-
}
|
|
580
|
+
getContext () {
|
|
581
|
+
if (!this.context) this.context = []
|
|
582
|
+
return union(this.context, this.frontMatter.context)
|
|
583
|
+
}
|
|
709
584
|
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
*/
|
|
715
|
-
Task.prototype.getList = function () {
|
|
716
|
-
return this.list
|
|
717
|
-
}
|
|
585
|
+
getDueMeta () {
|
|
586
|
+
const dueMeta = this.allMeta.due
|
|
587
|
+
if (dueMeta) return dueMeta[0]
|
|
588
|
+
}
|
|
718
589
|
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
Task.prototype.getText = function (opts, text) {
|
|
729
|
-
if (text === undefined) return
|
|
730
|
-
if (opts) {
|
|
731
|
-
if (opts.stripMeta) {
|
|
732
|
-
text = Task.removeMetaDataFromText(this.config || {}, text)
|
|
733
|
-
}
|
|
734
|
-
if (opts.stripTags) {
|
|
735
|
-
text = Task.removeTags(text, this.getTagPrefix())
|
|
736
|
-
} else if (this.fontMatter && this.frontMatter.tags) {
|
|
737
|
-
this.frontMatter.tags.forEach((tag) => (text += ` +${tag}`))
|
|
738
|
-
}
|
|
739
|
-
if (opts.stripContext) {
|
|
740
|
-
text = Task.removeContext(text)
|
|
741
|
-
} else if (this.fontMatter && this.frontMatter.context) {
|
|
742
|
-
this.frontMatter.context.forEach((context) => (text += ` @${context}`))
|
|
743
|
-
}
|
|
590
|
+
getMetaData () {
|
|
591
|
+
const meta = structuredClone(this.frontMatter.meta) || []
|
|
592
|
+
Object.entries(meta).forEach(([key, val]) => {
|
|
593
|
+
if (this.meta[key]) meta[key] = union(meta[key], this.meta[key])
|
|
594
|
+
})
|
|
595
|
+
Object.entries(this.meta).forEach(([key, val]) => {
|
|
596
|
+
if (!meta[key]) meta[key] = this.meta[key]
|
|
597
|
+
})
|
|
598
|
+
return meta
|
|
744
599
|
}
|
|
745
|
-
return text
|
|
746
|
-
}
|
|
747
600
|
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
601
|
+
getListTrackingMeta (lists) {
|
|
602
|
+
const taskMeta = this.meta
|
|
603
|
+
let listTrackingMeta = []
|
|
604
|
+
lists.forEach((list) => {
|
|
605
|
+
if (taskMeta[list]) {
|
|
606
|
+
const listMeta = taskMeta[list].map((timestamp) => ({ list, timestamp }))
|
|
607
|
+
listTrackingMeta = listTrackingMeta.concat(listMeta)
|
|
608
|
+
}
|
|
609
|
+
})
|
|
610
|
+
return sort(listTrackingMeta).asc(u => u.timestamp)
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
hasListChanged (lists) {
|
|
614
|
+
const listTrackingMeta = this.getListTrackingMeta(lists)
|
|
615
|
+
return (
|
|
616
|
+
listTrackingMeta.length === 0 || listTrackingMeta.pop().list !== this.list
|
|
617
|
+
)
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
hasMetaData (key, value) {
|
|
621
|
+
var meta = this.meta[key]
|
|
622
|
+
if (!meta) return false
|
|
623
|
+
if (Array.isArray(value)) return deepEqual(value.sort(), meta.sort())
|
|
624
|
+
return meta.includes(value)
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
/**
|
|
628
|
+
* Returns metadata as list with links
|
|
629
|
+
* @method getMetaDataWithLinks
|
|
630
|
+
* @param {} repository config
|
|
631
|
+
* @return Array
|
|
632
|
+
*/
|
|
633
|
+
getMetaDataWithLinks (config) {
|
|
634
|
+
var self = this
|
|
635
|
+
var meta = []
|
|
636
|
+
var metaData = this.allMeta
|
|
637
|
+
if (metaData) {
|
|
638
|
+
Object.getOwnPropertyNames(metaData)
|
|
639
|
+
.sort()
|
|
640
|
+
.forEach(function (metaKey) {
|
|
641
|
+
var valList = metaData[metaKey]
|
|
642
|
+
valList.forEach(function (value) {
|
|
643
|
+
meta.push({
|
|
644
|
+
key: metaKey,
|
|
645
|
+
value: value,
|
|
646
|
+
link: self.getMetaLink(config, metaKey, value),
|
|
647
|
+
})
|
|
648
|
+
})
|
|
649
|
+
})
|
|
650
|
+
}
|
|
752
651
|
|
|
753
|
-
|
|
754
|
-
while ((match = checkboxRegex.exec(html)) !== null) {
|
|
755
|
-
result.push(checkedRegex.test(match[0]));
|
|
652
|
+
return meta
|
|
756
653
|
}
|
|
757
654
|
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
return this.order
|
|
768
|
-
}
|
|
655
|
+
getMetaLink (config, metaKey, metaValue) {
|
|
656
|
+
var metaConfig = config.meta && config.meta[metaKey]
|
|
657
|
+
if (!metaConfig || !metaValue) return
|
|
658
|
+
return {
|
|
659
|
+
title: util.format(metaConfig.titleTemplate, metaValue),
|
|
660
|
+
url: util.format(metaConfig.urlTemplate, metaValue),
|
|
661
|
+
icon: metaConfig.icon,
|
|
662
|
+
}
|
|
663
|
+
}
|
|
769
664
|
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
665
|
+
toString () {
|
|
666
|
+
return util.format(
|
|
667
|
+
'file:%s, line:%d, text:%s, id:%s',
|
|
668
|
+
this.source.path,
|
|
669
|
+
this.line,
|
|
670
|
+
this.text,
|
|
671
|
+
this.id
|
|
672
|
+
)
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
/**
|
|
676
|
+
* Description
|
|
677
|
+
* @method getRepoId
|
|
678
|
+
* @return MemberExpression
|
|
679
|
+
*/
|
|
680
|
+
getRepoId () {
|
|
681
|
+
return this.repoId
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
/**
|
|
685
|
+
* Description
|
|
686
|
+
* @method getSource
|
|
687
|
+
* @return MemberExpression
|
|
688
|
+
*/
|
|
689
|
+
getSource () {
|
|
690
|
+
return this.source
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
/**
|
|
694
|
+
* Description
|
|
695
|
+
* @method getId
|
|
696
|
+
* @return MemberExpression
|
|
697
|
+
*/
|
|
698
|
+
getId () {
|
|
699
|
+
return this.id
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
/**
|
|
703
|
+
* Description
|
|
704
|
+
* @method getList
|
|
705
|
+
* @return MemberExpression
|
|
706
|
+
*/
|
|
707
|
+
getList () {
|
|
708
|
+
return this.list
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
/**
|
|
712
|
+
* Description
|
|
713
|
+
* @method getText
|
|
714
|
+
* @return text
|
|
715
|
+
*/
|
|
716
|
+
// BACKLOG make this use config.getMetaSep
|
|
717
|
+
// <!--
|
|
718
|
+
// order:-700
|
|
719
|
+
// -->
|
|
720
|
+
getText (opts, text) {
|
|
721
|
+
if (text === undefined) return
|
|
722
|
+
if (opts) {
|
|
723
|
+
if (opts.stripMeta) {
|
|
724
|
+
text = Task.removeMetaDataFromText(this.config || {}, text)
|
|
725
|
+
}
|
|
726
|
+
if (opts.stripTags) {
|
|
727
|
+
text = Task.removeTags(text, this.getTagPrefix())
|
|
728
|
+
} else if (this.fontMatter && this.frontMatter.tags) {
|
|
729
|
+
this.frontMatter.tags.forEach((tag) => (text += ` +${tag}`))
|
|
730
|
+
}
|
|
731
|
+
if (opts.stripContext) {
|
|
732
|
+
text = Task.removeContext(text)
|
|
733
|
+
} else if (this.fontMatter && this.frontMatter.context) {
|
|
734
|
+
this.frontMatter.context.forEach((context) => (text += ` @${context}`))
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
return text
|
|
738
|
+
}
|
|
778
739
|
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
740
|
+
getChecksFromHtml (html) {
|
|
741
|
+
const result = [];
|
|
742
|
+
const checkboxRegex = /<input[^>]*type=['"]checkbox['"][^>]*>/gi;
|
|
743
|
+
const checkedRegex = /checked(?:=['"]?checked['"]?)?/i;
|
|
782
744
|
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
* @return LogicalExpression
|
|
788
|
-
*/
|
|
789
|
-
Task.prototype.equals = function (task) {
|
|
790
|
-
if (!task) return
|
|
791
|
-
return (
|
|
792
|
-
task.getRepoId() == this.getRepoId() &&
|
|
793
|
-
task.getSource().path == this.getSource().path &&
|
|
794
|
-
task.getId() == this.getId()
|
|
795
|
-
)
|
|
796
|
-
}
|
|
745
|
+
let match;
|
|
746
|
+
while ((match = checkboxRegex.exec(html)) !== null) {
|
|
747
|
+
result.push(checkedRegex.test(match[0]));
|
|
748
|
+
}
|
|
797
749
|
|
|
798
|
-
|
|
750
|
+
return result;
|
|
751
|
+
};
|
|
752
|
+
|
|
753
|
+
/**
|
|
754
|
+
* Description
|
|
755
|
+
* @method getLine
|
|
756
|
+
* @return MemberExpression
|
|
757
|
+
*/
|
|
758
|
+
getLine () {
|
|
759
|
+
return this.line
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
getType () {
|
|
763
|
+
return this.type
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
/**
|
|
767
|
+
* Description
|
|
768
|
+
* @method equals
|
|
769
|
+
* @param {} task
|
|
770
|
+
* @return LogicalExpression
|
|
771
|
+
*/
|
|
772
|
+
equals (task) {
|
|
773
|
+
if (!task) return
|
|
774
|
+
return (
|
|
775
|
+
task.getRepoId() == this.getRepoId() &&
|
|
776
|
+
task.getSource().path == this.getSource().path &&
|
|
777
|
+
task.getId() == this.getId()
|
|
778
|
+
)
|
|
779
|
+
}
|
|
780
|
+
}
|