imdone-core 1.54.10 → 2.0.0

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.
Files changed (71) hide show
  1. package/README.md +2 -2
  2. package/lib/cli.js +114 -0
  3. package/lib/index.js +23 -0
  4. package/package.json +48 -66
  5. package/.github/ISSUE_TEMPLATE/bug_report.md +0 -37
  6. package/.github/workflows/ci.yml +0 -24
  7. package/.imdoneignore +0 -12
  8. package/.mocharc.json +0 -10
  9. package/.prettierrc +0 -6
  10. package/CHANGELOG.md +0 -160
  11. package/_navbar.md +0 -1
  12. package/cli.js +0 -74
  13. package/index-markdown.js +0 -55
  14. package/index.html +0 -184
  15. package/index.js +0 -1
  16. package/lib/ProjectContext.js +0 -42
  17. package/lib/adapters/date-time.js +0 -20
  18. package/lib/adapters/file-gateway.js +0 -127
  19. package/lib/adapters/git-download.js +0 -35
  20. package/lib/adapters/markdown.js +0 -168
  21. package/lib/adapters/parsers/DateLanguageParser.js +0 -10
  22. package/lib/adapters/parsers/content-transformer.js +0 -111
  23. package/lib/adapters/parsers/file/LocalFileParserFactory.js +0 -37
  24. package/lib/adapters/parsers/file/ReadStreamCodeParser.js +0 -126
  25. package/lib/adapters/parsers/file/ReadStreamMarkdownParser.js +0 -17
  26. package/lib/adapters/parsers/file/ReadStreamTaskParser.js +0 -104
  27. package/lib/adapters/parsers/function-parser.js +0 -29
  28. package/lib/adapters/parsers/task/CardContentParser.js +0 -376
  29. package/lib/adapters/parsers/task/CheckStyleTaskParser.js +0 -28
  30. package/lib/adapters/parsers/task/CodeStyleTaskParser.js +0 -24
  31. package/lib/adapters/parsers/task/HashStyleTaskParser.js +0 -27
  32. package/lib/adapters/parsers/task/MarkdownStyleTaskParser.js +0 -24
  33. package/lib/adapters/parsers/task/TaskParser.js +0 -38
  34. package/lib/adapters/readers/FileSystemProjectReader.js +0 -45
  35. package/lib/adapters/storage/config.js +0 -49
  36. package/lib/adapters/storage/tags.js +0 -30
  37. package/lib/adapters/yaml.js +0 -6
  38. package/lib/card.js +0 -300
  39. package/lib/config.js +0 -214
  40. package/lib/constants.js +0 -97
  41. package/lib/context/ApplicationContext.js +0 -32
  42. package/lib/context/StreamingApplicationContext.js +0 -31
  43. package/lib/controlers/SaveViewController.js +0 -10
  44. package/lib/default-settings.js +0 -37
  45. package/lib/domain/entities/FileProjectContext.js +0 -10
  46. package/lib/domain/entities/View.js +0 -30
  47. package/lib/domain/usecases/GetViewsUsecase.js +0 -50
  48. package/lib/domain/usecases/OpenProjectUsecase.js +0 -13
  49. package/lib/domain/usecases/SaveViewUsecase.js +0 -57
  50. package/lib/file.js +0 -1395
  51. package/lib/languages.js +0 -114
  52. package/lib/list.js +0 -105
  53. package/lib/migrate-config.js +0 -165
  54. package/lib/mixins/repo-fs-store.js +0 -424
  55. package/lib/mixins/repo-watched-fs-store.js +0 -195
  56. package/lib/plugins/archive-plugin.js +0 -70
  57. package/lib/plugins/default-board-actions-plugin.js +0 -56
  58. package/lib/plugins/default-board-properties-plugin.js +0 -101
  59. package/lib/plugins/epic-plugin.js +0 -176
  60. package/lib/plugins/extension-plugin.js +0 -87
  61. package/lib/plugins/persist-tags-plugin.js +0 -13
  62. package/lib/plugins/plugin-manager.js +0 -421
  63. package/lib/plugins/plugin-registry.js +0 -61
  64. package/lib/project-factory.js +0 -45
  65. package/lib/project.js +0 -911
  66. package/lib/repository.js +0 -1746
  67. package/lib/task.js +0 -798
  68. package/lib/tools.js +0 -250
  69. package/lib/usecases/get-imdone-url.js +0 -6
  70. package/lib/usecases/get-project-tags.js +0 -16
  71. package/lib/usecases/get-tasks-in-file.js +0 -29
package/lib/task.js DELETED
@@ -1,798 +0,0 @@
1
- 'use strict'
2
-
3
- var _clone = require('lodash.clone'),
4
- _isObject = require('lodash.isobject'),
5
- _isEqual = require('lodash.isequal'),
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 {
18
- CHECK_REGEX,
19
- TASK_TYPES,
20
- getCheckedData,
21
- isBeforeTextMarkdownList,
22
- isNumber
23
- } = require('./adapters/parsers/task/CardContentParser.js')
24
-
25
- /**
26
- * Description
27
- * @method Task
28
- * @param {} obj
29
- * @return
30
- */
31
- class Task {
32
- constructor(config, obj, dontParse) {
33
- if (!_isObject(obj)) throw new Error('obj must be an Object')
34
- this.frontMatter = obj.frontMatter || {
35
- tags: [],
36
- context: [],
37
- meta: {},
38
- }
39
- this.pos = obj.pos
40
- this.rawTask = obj.rawTask
41
- this.beforeText = obj.beforeText
42
- this.text = obj.text
43
- this.list = obj.list
44
- this.order = obj.order
45
- this.hasColon = obj.hasColon
46
- this.line = obj.line
47
- this.id = obj.id
48
- this.repoId = obj.repoId
49
- this.source = obj.source
50
- this.type = obj.type
51
- this.tags = obj.tags || []
52
- this.context = obj.context || []
53
- this.meta = obj.meta || {}
54
- this.metaIndex = obj.metaIndex || {}
55
- this.inBlockComment = obj.inBlockComment
56
- this.singleLineBlockComment = obj.singleLineBlockComment
57
- this.description = obj.description || []
58
- this.rawTaskContentLines = obj.rawTaskContentLines || []
59
- this.taskStartOnLine = obj.taskStartOnLine || 0
60
- this.commentStartOnLine = obj.commentStartOnLine || 0
61
- this.descriptionStartsWith = obj.descriptionStartsWith
62
- this.filteredListName = obj.filteredListName
63
- this.isWrappedWithCardTag = obj.isWrappedWithCardTag
64
- this.config = config
65
- this.allMeta = obj.allMeta || {}
66
- this.allContext = obj.allContext || []
67
- this.allTags = obj.allTags || []
68
- this.progress = obj.progress
69
- this.content = obj.content
70
- this.lastLine = this.getLastLine()
71
- this.orderModified = obj.orderModified
72
- this.index = obj.index
73
- if (dontParse || !this.text) return
74
- this.parse()
75
- }
76
-
77
- set order(val) {
78
- const order = parseFloat(val)
79
- this.innerOrder = isNaN(order) ? null : order
80
- }
81
-
82
- get order() {
83
- return this.innerOrder
84
- }
85
-
86
- get descriptionString() {
87
- return this.description.join(lineEnd)
88
- }
89
-
90
- updateLastLine() {
91
- this.lastLine = this.getLastLine()
92
- }
93
-
94
- getLastLine() {
95
- let lastLine = this.line + this.rawTaskContentLines.length
96
- return lastLine
97
- }
98
-
99
- parse() {
100
- const checkedData = this.getCheckedData()
101
- this.paddingLength = checkedData ? checkedData.pad : 0
102
- this.parseTodoTxt()
103
- if (this.meta.order) {
104
- this.order = this.meta.order[0]
105
- }
106
- this.allMeta = this.getMetaData()
107
- this.allContext = this.getContext()
108
- this.allTags = this.getTags()
109
- this.metaKeys = Object.keys(this.allMeta)
110
- this.progress = this.getProgress()
111
- this.content = this.getContent()
112
- this.topics = extractWikilinkTopics(this.content)
113
- }
114
-
115
- issueNumberRegExp() {
116
- return new RegExp(/:\/\/github\.com.*?\/issues\/\d+/)
117
- }
118
-
119
- get listId() {
120
- return this.filteredListName || this.list
121
- }
122
-
123
- get path() {
124
- return this.source.path
125
- }
126
-
127
- get markdownBeforeText() {
128
- if (!this.beforeText) return ''
129
- const beforeText = this.beforeText
130
- .replace('<!--', '')
131
- .trim()
132
- .replace(/[^#]+/g, '')
133
- return beforeText.length > 0 ? `${beforeText} ` : ''
134
- }
135
-
136
- getOrder() {
137
- return this.order
138
- }
139
-
140
- getTextAndDescription() {
141
- const taskContent = `${this.markdownBeforeText}${this.text}${lineEnd}${this.descriptionString}`
142
- .replace(/<!--\s*\[\s*([\s\S]*?)\s*\]\s*-->/gm, '$1')
143
- return this.getText(
144
- {
145
- stripMeta: true,
146
- sanitize: true,
147
- stripTags: true,
148
- stripContext: true,
149
- },
150
- taskContent);
151
- }
152
-
153
- getRawTextAndDescription() {
154
- const text = this.text
155
- if (this.description.length < 1) return text
156
- return `${text}${lineEnd}${this.descriptionString}${lineEnd}`
157
- }
158
-
159
- getProgress() {
160
- const progress = { completed: 0, total: 0 }
161
- const text = this.interpretedContent
162
- if (!text) return progress
163
- const checks = text.match(/- \[[x| ]\]/g)
164
- if (!checks) return progress
165
- return {
166
- completed: checks.filter((match) => match.includes('x')).length,
167
- total: checks.length,
168
- }
169
- }
170
-
171
- getContent() {
172
- return this.getRawTextAndDescription()
173
- }
174
-
175
- updateContent() {
176
- this.content = this.text + lineEnd + this.descriptionString
177
- }
178
-
179
- updateFromContent(content) {
180
- // replace all occurrences of two empty lines in a row with a single empty line
181
- content = content.replace(/\n\s*\n\s*\n/g, '\n\n')
182
- let lines = eol.split(content)
183
- this.text = lines.shift().trimStart()
184
- if (lines && lines.length > 1 && lines[lines.length - 1].trim() === '') lines.pop()
185
- this.description = lines
186
- this.parse()
187
- }
188
-
189
- toJSON() {
190
- return _assign({}, this, {
191
- allTags: this.allTags,
192
- allContext: this.allContext,
193
- allMeta: this.allMeta,
194
- config: undefined,
195
- expand: !!_get(this, 'allMeta.expand[0]'),
196
- })
197
- }
198
- }
199
- const DATE_META_KEYS = Task.DATE_META_KEYS = ['due', 'defer', 'created', 'started', 'remind', 'completed', 'archivedAt']
200
-
201
- Task.hasCheckPrefix = function (content) {
202
- return new RegExp(CHECK_REGEX).test(content)
203
- }
204
-
205
- Task.padDescription = function (description = [], beforeText = '') {
206
- const checkedData = getCheckedData(beforeText)
207
- if (checkedData) {
208
- return description.map((line) => {
209
- const paddedLine = line.padStart(line.length + checkedData.pad)
210
- return paddedLine.trim() ? paddedLine : ''
211
- })
212
- }
213
- return description
214
- }
215
-
216
- Task.trimDescription = function (rawTaskContentLines, beforeText) {
217
- const checkedData = getCheckedData(beforeText)
218
- if (checkedData) {
219
- rawTaskContentLines = rawTaskContentLines.map((line) => {
220
- const lineLength = line.length
221
- line = line.trimStart()
222
- return line.padStart(lineLength - checkedData.pad)
223
- })
224
- }
225
- return rawTaskContentLines
226
- }
227
-
228
- Task.prototype.getCheckedData = function () {
229
- return getCheckedData(this.beforeText)
230
- }
231
-
232
- Task.Types = TASK_TYPES
233
-
234
- Task.AnyLanguageGroup =
235
- '#\\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'
236
- Task.EmojiGroup = '\\p{Emoji_Presentation}'
237
-
238
- Task.getTagRegexp = function (prefix = '+') {
239
- return new RegExp(
240
- `(^|\\s)[${prefix}](?![${Task.AnyLanguageGroup}${Task.EmojiGroup}]*##)([${Task.AnyLanguageGroup}${Task.EmojiGroup}]+)`,
241
- 'gmiu'
242
- )
243
- }
244
- Task.getTags = function (text, prefix = '+') {
245
- const tags = [];
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) {}
341
- }
342
- })
343
- return meta
344
- }
345
-
346
- Task.execMetaRegex = function (re, content, codePositions, cb) {
347
- let result
348
- while ((result = re.exec(content)) !== null) {
349
- const index = result.index
350
- if (Task.isResultInMarkdownCode(codePositions, index)) continue
351
- var key = result[2]
352
- if (/[\(<]{1}(http|ssh|ftp|git)/.test(key)) continue
353
- if (!/^[^$][^\s\.]+$/.test(key)) continue
354
- cb(result)
355
- }
356
- }
357
-
358
- Task.eachMetaInContent = function (config, content, cb) {
359
- var codePositions = Task.getMarkdownCodePositions(content)
360
- Task.execMetaRegex(Task.getMetaRegExp(config), content, codePositions, cb)
361
- Task.execMetaRegex(
362
- Task.getMetaRegExpQuotes(config),
363
- content,
364
- codePositions,
365
- cb
366
- )
367
- }
368
-
369
- Task.hasWindowsEOL = function (content) {
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
383
- }
384
- if (result.index === re.lastIndex) re.lastIndex++
385
- line++
386
- }
387
- return content.length
388
- }
389
-
390
- Task.getLineNumber = function (content, pos) {
391
- const contentBeforePos = content.substring(0, pos)
392
- const lines = eol.split(contentBeforePos)
393
- return lines.length
394
- }
395
-
396
- Task.prototype.getTagPrefix = function () {
397
- return this.config.getTagPrefix()
398
- }
399
-
400
- Task.prototype.addToLastCommentInContent = Task.addToLastCommentInContent = function (content, toAdd, newLine) {
401
- // BACKLOG respect padding of task prefix for list items
402
- // <!--
403
- // order:-680
404
- // -->
405
- let prefix = newLine ? lineEnd : ' '
406
- const commentRegex = /<!--([\s\S]*?)-->/gm
407
- let result, lastIndex, index
408
- while ((result = commentRegex.exec(content))) {
409
- lastIndex = commentRegex.lastIndex
410
- index = result.index
411
- }
412
-
413
- if (lastIndex > 0) {
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'
433
- )
434
- }
435
-
436
- Task.prototype.updateOrderMeta = function (config, descContent = this.descriptionString) {
437
- if (config.orderMeta) {
438
- if (!isNumber(this.order)) return this.order = ''
439
- const addNewLine = config.isMetaNewLine()
440
- const metaSep = config.getMetaSep()
441
- if (this.meta.order) {
442
- const regex = Task.getMetaOrderRegex(config)
443
- descContent = descContent.replace(regex, `order${metaSep}${this.order}`)
444
- } else {
445
- descContent = this.addToLastCommentInContent(
446
- descContent,
447
- `order${metaSep}${this.order}`,
448
- addNewLine
449
- )
450
- }
451
- this.meta.order = [this.order]
452
- } else {
453
- descContent = Task.removeMetaData({
454
- config,
455
- content: descContent,
456
- key: 'order',
457
- value: Task.parseMetaData(config, descContent).order,
458
- })
459
- }
460
- this.description = descContent.split(lineEnd)
461
- this.updateContent()
462
- }
463
-
464
- Task.prototype.replaceContent = function (regex, replacement) {
465
- this.text = this.text.replace(regex, replacement)
466
- this.description = this.description.map((line) =>
467
- line.replace(regex, replacement)
468
- )
469
- }
470
-
471
- Task.prototype.replaceMetaSep = function (oldMetaSep, newMetaSep) {
472
- Object.keys(this.meta).forEach((key) => {
473
- const metaValues = this.meta[key]
474
- metaValues.forEach((metaValue) => {
475
- let regex = new RegExp(escapeRegExp(`${key}${oldMetaSep}"${metaValue}"`))
476
- this.replaceContent(regex, `${key}${newMetaSep}"${metaValue}"`)
477
- if (metaValue && !metaValue.toString().includes(' ')) {
478
- regex = new RegExp(escapeRegExp(`${key}${oldMetaSep}${metaValue}`))
479
- this.replaceContent(regex, `${key}${newMetaSep}${metaValue}`)
480
- }
481
- })
482
- })
483
- }
484
-
485
- /**
486
- * Description
487
- * @method isTask
488
- * @param {} task
489
- * @return BinaryExpression
490
- */
491
- Task.isTask = function (task) {
492
- return task instanceof Task
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;
527
- }
528
- return '';
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
- }
542
-
543
- Task.prototype.updateContext = function () {
544
- // BACKLOG implement updateContext id:1 gh:124
545
- // <!--
546
- // order:-690
547
- // -->
548
- var self = this
549
- if (this.context) {
550
- let text = Task.removeContext(this.text)
551
- this.context.forEach((context) => {
552
- text += ` @${context}`
553
- })
554
- this.text = text
555
- }
556
- }
557
-
558
- Task.removeMetaDataFromText = function (config, text) {
559
- const re = Task.getMetaRegExp(config)
560
- const re2 = Task.getMetaRegExpQuotes(config)
561
-
562
- const positions = Task.getMarkdownCodePositions(text)
563
- return text
564
- .replace(re, (match, p1, p2, p3, offset) => {
565
- if (/[\(<]{1}(http|ssh|ftp|git)/.test(p1)) return match
566
- if (Task.isResultInMarkdownCode(positions, offset)) return match
567
- return ''
568
- })
569
- .replace(re2, (match, p1, p2, p3, offset) => {
570
- if (/[\(<]{1}(http|ssh|ftp|git)/.test(p1)) return match
571
- if (Task.isResultInMarkdownCode(positions, offset)) return match
572
- return ''
573
- })
574
- }
575
-
576
- Task.removeMetaData = function ({ config, content, key, value }) {
577
- return content.replace(
578
- new RegExp(`${key}${config.getMetaSep()}"?${value}"?\\s`, 'g'),
579
- ''
580
- )
581
- }
582
-
583
- Task.prototype.getTags = function () {
584
- if (!this.tags) this.tags = []
585
- return _union(this.tags, this.frontMatter.tags)
586
- }
587
-
588
- Task.prototype.getContext = function () {
589
- if (!this.context) this.context = []
590
- return _union(this.context, this.frontMatter.context)
591
- }
592
-
593
- Task.prototype.getDueMeta = function () {
594
- const dueMeta = this.allMeta.due
595
- if (dueMeta) return dueMeta[0]
596
- }
597
-
598
- Task.prototype.getMetaData = function () {
599
- const meta = _clone(this.frontMatter.meta) || []
600
- Object.entries(meta).forEach(([key, val]) => {
601
- if (this.meta[key]) meta[key] = _union(meta[key], this.meta[key])
602
- })
603
- Object.entries(this.meta).forEach(([key, val]) => {
604
- if (!meta[key]) meta[key] = this.meta[key]
605
- })
606
- return meta
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)
616
- }
617
- })
618
- return fastSort(listTrackingMeta).asc(u => u.timestamp)
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
- }
627
-
628
- Task.prototype.hasMetaData = function (key, value) {
629
- var meta = this.meta[key]
630
- if (!meta) return false
631
- if (Array.isArray(value)) return _isEqual(value.sort(), meta.sort())
632
- return meta.includes(value)
633
- }
634
-
635
- /**
636
- * Returns metadata as list with links
637
- * @method getMetaDataWithLinks
638
- * @param {} repository config
639
- * @return Array
640
- */
641
- Task.prototype.getMetaDataWithLinks = function (config) {
642
- var self = this
643
- var meta = []
644
- var metaData = this.allMeta
645
- if (metaData) {
646
- Object.getOwnPropertyNames(metaData)
647
- .sort()
648
- .forEach(function (metaKey) {
649
- var valList = metaData[metaKey]
650
- valList.forEach(function (value) {
651
- meta.push({
652
- key: metaKey,
653
- value: value,
654
- link: self.getMetaLink(config, metaKey, value),
655
- })
656
- })
657
- })
658
- }
659
-
660
- return meta
661
- }
662
-
663
- Task.prototype.getMetaLink = function (config, metaKey, metaValue) {
664
- var metaConfig = config.meta && config.meta[metaKey]
665
- if (!metaConfig || !metaValue) return
666
- return {
667
- title: util.format(metaConfig.titleTemplate, metaValue),
668
- url: util.format(metaConfig.urlTemplate, metaValue),
669
- icon: metaConfig.icon,
670
- }
671
- }
672
-
673
- Task.prototype.toString = function () {
674
- return util.format(
675
- 'file:%s, line:%d, text:%s, id:%s',
676
- this.source.path,
677
- this.line,
678
- this.text,
679
- this.id
680
- )
681
- }
682
-
683
- /**
684
- * Description
685
- * @method getRepoId
686
- * @return MemberExpression
687
- */
688
- Task.prototype.getRepoId = function () {
689
- return this.repoId
690
- }
691
-
692
- /**
693
- * Description
694
- * @method getSource
695
- * @return MemberExpression
696
- */
697
- Task.prototype.getSource = function () {
698
- return this.source
699
- }
700
-
701
- /**
702
- * Description
703
- * @method getId
704
- * @return MemberExpression
705
- */
706
- Task.prototype.getId = function () {
707
- return this.id
708
- }
709
-
710
- /**
711
- * Description
712
- * @method getList
713
- * @return MemberExpression
714
- */
715
- Task.prototype.getList = function () {
716
- return this.list
717
- }
718
-
719
- /**
720
- * Description
721
- * @method getText
722
- * @return text
723
- */
724
- // BACKLOG make this use config.getMetaSep
725
- // <!--
726
- // order:-700
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
- }
744
- }
745
- return text
746
- }
747
-
748
- Task.prototype.getChecksFromHtml = function (html) {
749
- const result = [];
750
- const checkboxRegex = /<input[^>]*type=['"]checkbox['"][^>]*>/gi;
751
- const checkedRegex = /checked(?:=['"]?checked['"]?)?/i;
752
-
753
- let match;
754
- while ((match = checkboxRegex.exec(html)) !== null) {
755
- result.push(checkedRegex.test(match[0]));
756
- }
757
-
758
- return result;
759
- };
760
-
761
- /**
762
- * Description
763
- * @method order
764
- * @return MemberExpression
765
- */
766
- Task.prototype.order = function () {
767
- return this.order
768
- }
769
-
770
- /**
771
- * Description
772
- * @method getLine
773
- * @return MemberExpression
774
- */
775
- Task.prototype.getLine = function () {
776
- return this.line
777
- }
778
-
779
- Task.prototype.getType = function () {
780
- return this.type
781
- }
782
-
783
- /**
784
- * Description
785
- * @method equals
786
- * @param {} task
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
- }
797
-
798
- module.exports = Task