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/file.js
CHANGED
|
@@ -1,101 +1,50 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
newCard = require('./card'),
|
|
21
|
-
fastSort = require('fast-sort/dist/sort'),
|
|
22
|
-
XRegExp = require('xregexp'),
|
|
23
|
-
{ getIsoDateWithOffset } = require('./adapters/date-time'),
|
|
24
|
-
{
|
|
25
|
-
FILE_TYPES,
|
|
1
|
+
import _isObject from 'lodash.isobject'
|
|
2
|
+
import _assign from 'lodash.assign'
|
|
3
|
+
import _omit from 'lodash.omit'
|
|
4
|
+
import _get from 'lodash.get'
|
|
5
|
+
import crypto from 'crypto'
|
|
6
|
+
import Emitter from 'events'
|
|
7
|
+
import path from 'path'
|
|
8
|
+
import matter from 'gray-matter'
|
|
9
|
+
import eol from 'eol'
|
|
10
|
+
import { tools } from './tools.js'
|
|
11
|
+
import debug from 'debug'
|
|
12
|
+
import * as chrono from 'chrono-node'
|
|
13
|
+
import { Task } from './task.js'
|
|
14
|
+
import { newCard } from './card.js'
|
|
15
|
+
import { sort } from 'fast-sort'
|
|
16
|
+
import XRegExp from 'xregexp'
|
|
17
|
+
import { getIsoDateWithOffset } from './adapters/date-time.js'
|
|
18
|
+
import {
|
|
19
|
+
FILE_TYPES,
|
|
26
20
|
getTaskContent,
|
|
27
21
|
getRawTask,
|
|
28
22
|
getHashStyleRegex,
|
|
29
23
|
hasTaskInText,
|
|
30
24
|
LIST_NAME_PATTERN,
|
|
31
25
|
LINK_STYLE_REGEX,
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
26
|
+
} from './adapters/parsers/task/CardContentParser.js'
|
|
27
|
+
import { appContext } from './context/ApplicationContext.js'
|
|
28
|
+
import { languages } from './languages.js'
|
|
29
|
+
import { logger } from './adapters/logger.js'
|
|
30
|
+
|
|
31
|
+
const log = debug('imdone-core:File')
|
|
32
|
+
const lf = String(eol.lf)
|
|
33
|
+
const lineEnd = String(eol.auto)
|
|
34
|
+
const { hasBlankLines, escapeRegExp } = tools
|
|
37
35
|
const ERRORS = {
|
|
38
36
|
NOT_A_TASK: 'task must be of type Task',
|
|
39
37
|
}
|
|
40
|
-
const escapeRegExp = tools.escapeRegExp
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Description
|
|
44
|
-
* @method File
|
|
45
|
-
* @param {} repoId
|
|
46
|
-
* @param {} filePath
|
|
47
|
-
* @param {} content
|
|
48
|
-
* @param {} modifiedTime
|
|
49
|
-
* @return
|
|
50
|
-
*
|
|
51
|
-
* */
|
|
52
|
-
function File(opts) {
|
|
53
|
-
events.EventEmitter.call(this)
|
|
54
|
-
this.project = opts.project
|
|
55
|
-
this.projectContext = appContext().projectContext
|
|
56
|
-
if (_isObject(opts.file) && _isObject(opts.config)) {
|
|
57
|
-
_assign(this, opts.file)
|
|
58
|
-
this.tasks.forEach((task) => {
|
|
59
|
-
task = newCard(task, this.project)
|
|
60
|
-
})
|
|
61
|
-
} else {
|
|
62
|
-
this.repoId = opts.repoId
|
|
63
|
-
this.path = opts.filePath
|
|
64
|
-
this.content = opts.content
|
|
65
|
-
this.modifiedTime = opts.modifiedTime
|
|
66
|
-
this.createdTime = opts.createdTime
|
|
67
|
-
this.languages = opts.languages || require('./languages')
|
|
68
|
-
this.modified = false
|
|
69
|
-
this.frontMatter = {
|
|
70
|
-
tags: [],
|
|
71
|
-
context: [],
|
|
72
|
-
meta: {},
|
|
73
|
-
}
|
|
74
|
-
this.tasks = []
|
|
75
|
-
this.isDir = false
|
|
76
|
-
this.lineCount = 0
|
|
77
|
-
this.deleted = false
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
util.inherits(File, events.EventEmitter)
|
|
81
|
-
|
|
82
38
|
const CODE_STYLE_END = '((:)(-?[\\d.]+(?:e-?\\d+)?)?)?[ \\t]+(.+)$'
|
|
83
|
-
const CODE_STYLE_PATTERN = (
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
File.isListNameValid = function(listName) {
|
|
87
|
-
return new XRegExp(LIST_NAME_PATTERN).test(listName)
|
|
88
|
-
}
|
|
39
|
+
const CODE_STYLE_PATTERN = '([A-Z]+[A-Z-_]+?)' + CODE_STYLE_END
|
|
40
|
+
const CHECK_STYLE_PATTERN = /^(\s*- \[([x ])\]\s)(.+$)/gm
|
|
89
41
|
|
|
90
|
-
|
|
91
|
-
/^(\s*- \[([x ])\]\s)(.+$)/gm)
|
|
92
|
-
|
|
93
|
-
var getTaskId = (File.getTaskId = function (path, line, text) {
|
|
42
|
+
function getTaskId (path, line, text) {
|
|
94
43
|
var shasum = crypto.createHash('sha1')
|
|
95
44
|
const taskElements = { path, line, text: text.trim() }
|
|
96
45
|
shasum.update(JSON.stringify(taskElements))
|
|
97
46
|
return shasum.digest('hex')
|
|
98
|
-
}
|
|
47
|
+
}
|
|
99
48
|
|
|
100
49
|
function getDoneList(config) {
|
|
101
50
|
return config.getDoneList()
|
|
@@ -119,114 +68,6 @@ function getFrontMeta(meta) {
|
|
|
119
68
|
return metadata
|
|
120
69
|
}
|
|
121
70
|
|
|
122
|
-
File.getUnixContent = function (content) {
|
|
123
|
-
return content.replace(/\r\n|\r/g, '\n')
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
File.isMetaNewLine = function (config) {
|
|
127
|
-
return config.isMetaNewLine()
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
File.isAddCompletedMeta = function (config) {
|
|
131
|
-
return config.isAddCompletedMeta()
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
File.isFile = function (file) {
|
|
135
|
-
return file instanceof File
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
File.isMarkdown = function (relPath) {
|
|
139
|
-
return /\.md$/i.test(relPath) || path.extname(relPath) === ''
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
File.prototype.removeCompleted = function ({ task, content, config }) {
|
|
143
|
-
const doneList = getDoneList(config)
|
|
144
|
-
if (doneList === task.list) return content
|
|
145
|
-
if (
|
|
146
|
-
task.meta.completed &&
|
|
147
|
-
task.meta.completed.length > 0
|
|
148
|
-
) {
|
|
149
|
-
content = this.removeMetaData(
|
|
150
|
-
content,
|
|
151
|
-
'completed',
|
|
152
|
-
task.meta.completed[0]
|
|
153
|
-
)
|
|
154
|
-
}
|
|
155
|
-
return content
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
File.addStarted = function ({ task, content, config }) {
|
|
159
|
-
if (!task || !config || !config.settings) return content
|
|
160
|
-
if (!config.settings.cards.addStartedMeta) return content
|
|
161
|
-
if (task.meta.started) return content
|
|
162
|
-
if (task.list !== getDoingList(config)) return content
|
|
163
|
-
const now = getIsoDateWithOffset()
|
|
164
|
-
content = task.addToLastCommentInContent(
|
|
165
|
-
content,
|
|
166
|
-
`started${config.getMetaSep()}${now}`,
|
|
167
|
-
File.isMetaNewLine(config)
|
|
168
|
-
)
|
|
169
|
-
const lines = eol.split(content)
|
|
170
|
-
return lines.join(lineEnd)
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
File.addCompleted = function ({ task, content, config }) {
|
|
174
|
-
const doneList = getDoneList(config)
|
|
175
|
-
if (
|
|
176
|
-
!task ||
|
|
177
|
-
!config ||
|
|
178
|
-
!config.settings ||
|
|
179
|
-
!doneList ||
|
|
180
|
-
!this.isAddCompletedMeta(config)
|
|
181
|
-
)
|
|
182
|
-
return content
|
|
183
|
-
if (task.list !== doneList) return content
|
|
184
|
-
if (task.completed || task.meta.completed) return content
|
|
185
|
-
if (content.includes(`completed${config.getMetaSep()}`)) return content
|
|
186
|
-
const now = getIsoDateWithOffset()
|
|
187
|
-
content = task.addToLastCommentInContent(
|
|
188
|
-
content,
|
|
189
|
-
`completed${config.getMetaSep()}${now}`,
|
|
190
|
-
File.isMetaNewLine(config)
|
|
191
|
-
)
|
|
192
|
-
const lines = eol.split(content)
|
|
193
|
-
return lines.join(lineEnd)
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
File.parseDueDate = function (config, text) {
|
|
197
|
-
return File.parseDate(config, text, 'due')
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
File.parseRemindDate = function (config, text) {
|
|
201
|
-
return File.parseDate(config, text, 'remind')
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
File.parseDeferDate = function (config, text) {
|
|
205
|
-
return File.parseDate(config, text, 'defer')
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
File.parseDate = function (config, text, dateType) {
|
|
209
|
-
// TODO Add the ability to set multiple reminders
|
|
210
|
-
// #imdone-1.54.0
|
|
211
|
-
// <!--
|
|
212
|
-
// order:-150
|
|
213
|
-
// -->
|
|
214
|
-
if (text.includes(`${dateType}${config.getMetaSep()}`)) return text
|
|
215
|
-
let dateString
|
|
216
|
-
return text.replace(new RegExp(`(\\s${dateType})\\s.*?\\.`,'gi'), (match, p1) => {
|
|
217
|
-
if (dateString) return match
|
|
218
|
-
try {
|
|
219
|
-
const date = chrono.parseDate(match, new Date(), {forwardDate: true})
|
|
220
|
-
if (!date) return match
|
|
221
|
-
dateString = getIsoDateWithOffset(date)
|
|
222
|
-
return `${p1.toLowerCase()}${config.getMetaSep()}${dateString}`
|
|
223
|
-
} catch (e) {
|
|
224
|
-
console.log(`Unable to parse ${dateType} date for ${text}`)
|
|
225
|
-
return match
|
|
226
|
-
}
|
|
227
|
-
})
|
|
228
|
-
}
|
|
229
|
-
|
|
230
71
|
function trackMarkdownChecklistChanges({task, config, modify}) {
|
|
231
72
|
const doneList = config.getDoneList()
|
|
232
73
|
let beforeTextModified = false
|
|
@@ -253,1143 +94,1298 @@ function trackMarkdownChecklistChanges({task, config, modify}) {
|
|
|
253
94
|
return beforeTextModified
|
|
254
95
|
}
|
|
255
96
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
.
|
|
97
|
+
function trimBlankLines (content, isCodeFile) {
|
|
98
|
+
if (isCodeFile) {
|
|
99
|
+
// replace all occurrences of two empty lines in a row with a single empty line
|
|
100
|
+
return content.replace(/\n\s*\n/g, '\n')
|
|
101
|
+
}
|
|
102
|
+
return content.replace(/\n\s*\n\s*\n/g, '\n\n')
|
|
103
|
+
}
|
|
260
104
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
105
|
+
function padDescription (description = [], beforeText = '') {
|
|
106
|
+
return Task.padDescription(description, beforeText)
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function bothAreUndefNull(a, b) {
|
|
110
|
+
return isUndefNull(a) && isUndefNull(b)
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function isUndefNull(val) {
|
|
114
|
+
return val === null || val === undefined
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
export class File extends Emitter {
|
|
120
|
+
constructor(opts) {
|
|
121
|
+
super()
|
|
122
|
+
this.project = opts.project
|
|
123
|
+
this.projectContext = appContext().projectContext
|
|
124
|
+
if (_isObject(opts.file) && _isObject(opts.config)) {
|
|
125
|
+
_assign(this, opts.file)
|
|
126
|
+
this.tasks.forEach((task) => {
|
|
127
|
+
task = newCard(task, this.project)
|
|
128
|
+
})
|
|
129
|
+
} else {
|
|
130
|
+
this.repoId = opts.repoId
|
|
131
|
+
this.path = opts.filePath
|
|
132
|
+
this.content = opts.content
|
|
133
|
+
this.modifiedTime = opts.modifiedTime
|
|
134
|
+
this.createdTime = opts.createdTime
|
|
135
|
+
this.languages = opts.languages || languages
|
|
136
|
+
this.modified = false
|
|
137
|
+
this.frontMatter = {
|
|
138
|
+
tags: [],
|
|
139
|
+
context: [],
|
|
140
|
+
meta: {},
|
|
141
|
+
}
|
|
142
|
+
this.tasks = []
|
|
143
|
+
this.isDir = false
|
|
144
|
+
this.lineCount = 0
|
|
145
|
+
this.deleted = false
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
static CODE_STYLE_PATTERN = CODE_STYLE_PATTERN
|
|
150
|
+
|
|
151
|
+
static CHECK_STYLE_PATTERN = CHECK_STYLE_PATTERN
|
|
152
|
+
|
|
153
|
+
static getTaskId = getTaskId
|
|
154
|
+
|
|
155
|
+
static trimBlankLines = trimBlankLines
|
|
156
|
+
|
|
157
|
+
static padDescription = padDescription
|
|
158
|
+
|
|
159
|
+
static isListNameValid(listName) {
|
|
160
|
+
return new XRegExp(LIST_NAME_PATTERN).test(listName)
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
static getUnixContent (content) {
|
|
164
|
+
return content.replace(/\r\n|\r/g, '\n')
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
static isMetaNewLine (config) {
|
|
168
|
+
return config.isMetaNewLine()
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
static isAddCompletedMeta (config) {
|
|
172
|
+
return config.isAddCompletedMeta()
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
static isFile (file) {
|
|
176
|
+
return file instanceof File
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
static isMarkdown (relPath) {
|
|
180
|
+
return /\.md$/i.test(relPath) || path.extname(relPath) === ''
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
static addStarted ({ task, content, config }) {
|
|
184
|
+
if (!task || !config || !config.settings) return content
|
|
185
|
+
if (!config.settings.cards.addStartedMeta) return content
|
|
186
|
+
if (task.meta.started) return content
|
|
187
|
+
if (task.list !== getDoingList(config)) return content
|
|
188
|
+
const now = getIsoDateWithOffset()
|
|
189
|
+
content = task.addToLastCommentInContent(
|
|
190
|
+
content,
|
|
191
|
+
`started${config.getMetaSep()}${now}`,
|
|
192
|
+
File.isMetaNewLine(config)
|
|
193
|
+
)
|
|
194
|
+
const lines = eol.split(content)
|
|
195
|
+
return lines.join(lineEnd)
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
static addCompleted ({ task, content, config }) {
|
|
199
|
+
const doneList = getDoneList(config)
|
|
265
200
|
if (
|
|
266
|
-
|
|
267
|
-
|
|
201
|
+
!task ||
|
|
202
|
+
!config ||
|
|
203
|
+
!config.settings ||
|
|
204
|
+
!doneList ||
|
|
205
|
+
!this.isAddCompletedMeta(config)
|
|
206
|
+
)
|
|
207
|
+
return content
|
|
208
|
+
if (task.list !== doneList) return content
|
|
209
|
+
if (task.completed || task.meta.completed) return content
|
|
210
|
+
if (content.includes(`completed${config.getMetaSep()}`)) return content
|
|
211
|
+
const now = getIsoDateWithOffset()
|
|
212
|
+
content = task.addToLastCommentInContent(
|
|
213
|
+
content,
|
|
214
|
+
`completed${config.getMetaSep()}${now}`,
|
|
215
|
+
File.isMetaNewLine(config)
|
|
216
|
+
)
|
|
217
|
+
const lines = eol.split(content)
|
|
218
|
+
return lines.join(lineEnd)
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
static parseDueDate (config, text) {
|
|
222
|
+
return File.parseDate(config, text, 'due')
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
static parseRemindDate (config, text) {
|
|
226
|
+
return File.parseDate(config, text, 'remind')
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
static parseDeferDate (config, text) {
|
|
230
|
+
return File.parseDate(config, text, 'defer')
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
static parseDate (config, text, dateType) {
|
|
234
|
+
// TODO Add the ability to set multiple reminders
|
|
235
|
+
// #imdone-1.54.0
|
|
236
|
+
// <!--
|
|
237
|
+
// order:-150
|
|
238
|
+
// -->
|
|
239
|
+
if (text.includes(`${dateType}${config.getMetaSep()}`)) return text
|
|
240
|
+
let dateString
|
|
241
|
+
return text.replace(new RegExp(`(\\s${dateType})\\s.*?\\.`,'gi'), (match, p1) => {
|
|
242
|
+
if (dateString) return match
|
|
243
|
+
try {
|
|
244
|
+
const date = chrono.parseDate(match, new Date(), {forwardDate: true})
|
|
245
|
+
if (!date) return match
|
|
246
|
+
dateString = getIsoDateWithOffset(date)
|
|
247
|
+
return `${p1.toLowerCase()}${config.getMetaSep()}${dateString}`
|
|
248
|
+
} catch (e) {
|
|
249
|
+
logger.log(`Unable to parse ${dateType} date for ${text}`)
|
|
250
|
+
return match
|
|
251
|
+
}
|
|
252
|
+
})
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
removeCompleted ({ task, content, config }) {
|
|
256
|
+
const doneList = getDoneList(config)
|
|
257
|
+
if (doneList === task.list) return content
|
|
258
|
+
if (
|
|
259
|
+
task.meta.completed &&
|
|
260
|
+
task.meta.completed.length > 0
|
|
268
261
|
) {
|
|
269
|
-
|
|
270
|
-
const now = new Date().toISOString()
|
|
271
|
-
content = task.addToLastCommentInContent(
|
|
262
|
+
content = this.removeMetaData(
|
|
272
263
|
content,
|
|
273
|
-
|
|
274
|
-
|
|
264
|
+
'completed',
|
|
265
|
+
task.meta.completed[0]
|
|
275
266
|
)
|
|
276
|
-
if (!task.meta[list]) task.meta[list] = []
|
|
277
|
-
task.meta[list].push(now)
|
|
278
267
|
}
|
|
268
|
+
return content
|
|
279
269
|
}
|
|
280
270
|
|
|
281
|
-
|
|
282
|
-
|
|
271
|
+
trackListChanges ({ task, content, config, modify }) {
|
|
272
|
+
const lists = config.lists
|
|
273
|
+
.filter((list) => !list.filter)
|
|
274
|
+
.map((list) => list.name)
|
|
275
|
+
|
|
276
|
+
let beforeTextModified = false
|
|
277
|
+
if (this.isMarkDownFile()) {
|
|
278
|
+
beforeTextModified = trackMarkdownChecklistChanges({task, config, modify})
|
|
279
|
+
|
|
280
|
+
if (
|
|
281
|
+
_get(config, 'settings.cards.trackChanges') &&
|
|
282
|
+
task.hasListChanged(lists)
|
|
283
|
+
) {
|
|
284
|
+
const list = task.list
|
|
285
|
+
const now = new Date().toISOString()
|
|
286
|
+
content = task.addToLastCommentInContent(
|
|
287
|
+
content,
|
|
288
|
+
`${list}${config.getMetaSep()}${now}`,
|
|
289
|
+
File.isMetaNewLine(config)
|
|
290
|
+
)
|
|
291
|
+
if (!task.meta[list]) task.meta[list] = []
|
|
292
|
+
task.meta[list].push(now)
|
|
293
|
+
}
|
|
294
|
+
}
|
|
283
295
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
config: this.projectContext.config,
|
|
287
|
-
content,
|
|
288
|
-
key,
|
|
289
|
-
value,
|
|
290
|
-
})
|
|
291
|
-
}
|
|
296
|
+
return { content, beforeTextModified }
|
|
297
|
+
}
|
|
292
298
|
|
|
293
|
-
|
|
294
|
-
|
|
299
|
+
removeMetaData (content, key, value) {
|
|
300
|
+
return Task.removeMetaData({
|
|
301
|
+
config: this.projectContext.config,
|
|
302
|
+
content,
|
|
303
|
+
key,
|
|
304
|
+
value,
|
|
305
|
+
})
|
|
306
|
+
}
|
|
295
307
|
|
|
296
|
-
|
|
297
|
-
task
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
content.
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
308
|
+
transformTask ({config, modify, task}) {
|
|
309
|
+
let content = task.content
|
|
310
|
+
|
|
311
|
+
const trackListChanges = this.trackListChanges({
|
|
312
|
+
task,
|
|
313
|
+
content,
|
|
314
|
+
config,
|
|
315
|
+
modify,
|
|
316
|
+
})
|
|
317
|
+
content = trackListChanges.content
|
|
318
|
+
content = File.parseDueDate(config, content)
|
|
319
|
+
content = File.parseRemindDate(config, content)
|
|
320
|
+
content = File.parseDeferDate(config, content)
|
|
321
|
+
content = File.addStarted({ task, content, config })
|
|
322
|
+
content = File.addCompleted({ task, content, config })
|
|
323
|
+
content = this.removeCompleted({ task, content, config })
|
|
324
|
+
content = task.format(content)
|
|
325
|
+
if (
|
|
326
|
+
content.trim() !== task.content.trim()
|
|
327
|
+
|| trackListChanges.beforeTextModified
|
|
328
|
+
|| task.orderModified
|
|
329
|
+
) {
|
|
330
|
+
this.modifyTaskFromContent(task, content, config)
|
|
331
|
+
}
|
|
316
332
|
}
|
|
317
|
-
}
|
|
318
333
|
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
}
|
|
334
|
+
transformTasks (config, modify) {
|
|
335
|
+
sort(this.getTasks())
|
|
336
|
+
.desc(u => u.line)
|
|
337
|
+
.forEach(task => this.transformTask({config, modify, task}))
|
|
338
|
+
}
|
|
324
339
|
|
|
325
|
-
// TODO Blank lines should be allowed in code tasks
|
|
326
|
-
// <!--
|
|
327
|
-
// #imdone-1.54.0
|
|
328
|
-
// #feature
|
|
329
|
-
// order:-105
|
|
330
|
-
// -->
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
340
|
+
// TODO Blank lines should be allowed in code tasks
|
|
341
|
+
// <!--
|
|
342
|
+
// #imdone-1.54.0
|
|
343
|
+
// #feature
|
|
344
|
+
// order:-105
|
|
345
|
+
// -->
|
|
346
|
+
extractCodeStyleTasks (config, pos, content) {
|
|
347
|
+
var self = this
|
|
348
|
+
var codeStyleRegex = new RegExp(CODE_STYLE_PATTERN, 'gm')
|
|
349
|
+
var result
|
|
350
|
+
const inBlockComment = this.isInBlockComment(content)
|
|
351
|
+
const singleLineBlockComment =
|
|
352
|
+
inBlockComment && this.isSingleLineBlockComment(content)
|
|
353
|
+
while ((result = codeStyleRegex.exec(content)) !== null) {
|
|
354
|
+
var posInContent = pos + result.index
|
|
355
|
+
var line = this.getLineNumber(posInContent)
|
|
356
|
+
if (self.getTaskAtLine(line)) continue
|
|
357
|
+
var charBeforeList = this.getContent().substring(
|
|
358
|
+
posInContent - 1,
|
|
359
|
+
posInContent
|
|
360
|
+
)
|
|
361
|
+
if (this.startsWithCommentOrSpace(posInContent) && charBeforeList !== '#') {
|
|
362
|
+
var list = result[1]
|
|
363
|
+
if (!config.includeList(list)) continue
|
|
364
|
+
var rawTask = result[0]
|
|
365
|
+
var text = result[5]
|
|
366
|
+
const linePos = self.getLinePos(line)
|
|
367
|
+
const matchCharsInFront = this.getContent()
|
|
368
|
+
.substring(linePos, posInContent)
|
|
369
|
+
.match(/\S+\s*/)
|
|
370
|
+
const charsInFront = matchCharsInFront ? matchCharsInFront[0].length : 0
|
|
371
|
+
var hasColon =
|
|
372
|
+
result[3] !== undefined
|
|
373
|
+
const taskStartOnLine = inBlockComment
|
|
374
|
+
? posInContent - charsInFront - linePos
|
|
375
|
+
: pos - linePos
|
|
376
|
+
var task = self.extractTaskWithDescription({
|
|
377
|
+
taskStartOnLine,
|
|
378
|
+
rawTask,
|
|
379
|
+
config,
|
|
380
|
+
list,
|
|
381
|
+
text,
|
|
382
|
+
line,
|
|
383
|
+
type: Task.Types.CODE,
|
|
384
|
+
hasColon,
|
|
385
|
+
content: self.getContent().substring(linePos),
|
|
386
|
+
inBlockComment,
|
|
387
|
+
singleLineBlockComment,
|
|
388
|
+
})
|
|
389
|
+
self.addTask(task)
|
|
390
|
+
self.emit('task.found', task)
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
extractHashStyleTasks (config, pos, content) {
|
|
396
|
+
var hashStyleRegex = getHashStyleRegex(config.tokenPrefix)
|
|
397
|
+
var lang = this.getLang()
|
|
398
|
+
const codePositions = this.getMarkdownCodePositions(content);
|
|
399
|
+
var result
|
|
400
|
+
while ((result = hashStyleRegex.exec(content)) !== null) {
|
|
401
|
+
if (this.isResultInMarkdownCode(codePositions, result.index)) continue;
|
|
402
|
+
var [rawTask, list, orderGroup, order, text] = result
|
|
403
|
+
if (!config.listExists(list)) continue
|
|
404
|
+
|
|
405
|
+
const posInContent = result.index + pos
|
|
406
|
+
if (this.isWithinCodeSpanOrBlock(result.index, content)) continue
|
|
407
|
+
|
|
408
|
+
const line = this.getLineNumber(posInContent)
|
|
409
|
+
if (this.getTaskAtLine(line)) continue
|
|
410
|
+
|
|
411
|
+
if (lang.block) {
|
|
412
|
+
const blockEndPos = text.indexOf(lang.block.end)
|
|
413
|
+
if (blockEndPos > -1) text = text.substring(0, blockEndPos)
|
|
414
|
+
}
|
|
415
|
+
var task = this.extractTaskWithDescription({
|
|
364
416
|
config,
|
|
365
417
|
list,
|
|
366
418
|
text,
|
|
419
|
+
order,
|
|
367
420
|
line,
|
|
368
|
-
type: Task.Types.
|
|
369
|
-
hasColon,
|
|
370
|
-
content:
|
|
371
|
-
|
|
372
|
-
singleLineBlockComment,
|
|
421
|
+
type: Task.Types.HASHTAG,
|
|
422
|
+
hasColon: orderGroup && orderGroup.startsWith(':'),
|
|
423
|
+
content: content.substring(result.index),
|
|
424
|
+
pos: posInContent,
|
|
373
425
|
})
|
|
374
|
-
|
|
375
|
-
|
|
426
|
+
task.taskStartOnLine = pos - this.getLinePos(line)
|
|
427
|
+
task.rawTask = rawTask
|
|
428
|
+
this.addTask(task)
|
|
429
|
+
this.emit('task.found', task)
|
|
376
430
|
}
|
|
377
431
|
}
|
|
378
|
-
}
|
|
379
432
|
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
433
|
+
extractLinkStyleTasks (config, pos, content) {
|
|
434
|
+
var self = this
|
|
435
|
+
var linkStyleRegex = new XRegExp(LINK_STYLE_REGEX)
|
|
436
|
+
const log = debug('extractLinkStyleTasks')
|
|
437
|
+
const codePositions = this.getMarkdownCodePositions(content);
|
|
438
|
+
var result
|
|
439
|
+
while ((result = linkStyleRegex.exec(content)) !== null) {
|
|
440
|
+
if (this.isResultInMarkdownCode(codePositions, result.index)) continue;
|
|
441
|
+
let [match, before, rawTask, text, list, colon, order] = result
|
|
442
|
+
const beforeLength = before ? before.length : 0
|
|
443
|
+
const posInContent = result.index + pos + beforeLength
|
|
444
|
+
if (this.isWithinCodeSpanOrBlock(result.index, content)) continue
|
|
445
|
+
var line = this.getLineNumber(posInContent)
|
|
446
|
+
if (self.getTaskAtLine(line)) continue
|
|
447
|
+
if (!config.listExists(list)) continue
|
|
448
|
+
log('*********************************************************')
|
|
449
|
+
log(result)
|
|
450
|
+
log('list:%s text:%s order:%d line:%d', list, text, order, line)
|
|
395
451
|
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
452
|
+
var task = self.extractTaskWithDescription({
|
|
453
|
+
config,
|
|
454
|
+
list,
|
|
455
|
+
text,
|
|
456
|
+
order,
|
|
457
|
+
line,
|
|
458
|
+
type: Task.Types.MARKDOWN,
|
|
459
|
+
hasColon: !!colon,
|
|
460
|
+
content: content.substring(result.index),
|
|
461
|
+
pos: posInContent,
|
|
462
|
+
})
|
|
463
|
+
task.rawTask = rawTask
|
|
464
|
+
self.addTask(task)
|
|
465
|
+
self.emit('task.found', task)
|
|
399
466
|
}
|
|
400
|
-
var task = this.extractTaskWithDescription({
|
|
401
|
-
config,
|
|
402
|
-
list,
|
|
403
|
-
text,
|
|
404
|
-
order,
|
|
405
|
-
line,
|
|
406
|
-
type: Task.Types.HASHTAG,
|
|
407
|
-
hasColon: orderGroup && orderGroup.startsWith(':'),
|
|
408
|
-
content: content.substring(result.index),
|
|
409
|
-
pos: posInContent,
|
|
410
|
-
})
|
|
411
|
-
task.taskStartOnLine = pos - this.getLinePos(line)
|
|
412
|
-
task.rawTask = rawTask
|
|
413
|
-
this.addTask(task)
|
|
414
|
-
this.emit('task.found', task)
|
|
415
|
-
}
|
|
416
|
-
};
|
|
417
|
-
|
|
418
|
-
File.prototype.extractLinkStyleTasks = function (config, pos, content) {
|
|
419
|
-
var self = this
|
|
420
|
-
var linkStyleRegex = new XRegExp(LINK_STYLE_REGEX)
|
|
421
|
-
const codePositions = this.getMarkdownCodePositions(content);
|
|
422
|
-
var result
|
|
423
|
-
while ((result = linkStyleRegex.exec(content)) !== null) {
|
|
424
|
-
if (this.isResultInMarkdownCode(codePositions, result.index)) continue;
|
|
425
|
-
let [match, before, rawTask, text, list, colon, order] = result
|
|
426
|
-
const beforeLength = before ? before.length : 0
|
|
427
|
-
const posInContent = result.index + pos + beforeLength
|
|
428
|
-
if (this.isWithinCodeSpanOrBlock(result.index, content)) continue
|
|
429
|
-
var line = this.getLineNumber(posInContent)
|
|
430
|
-
if (self.getTaskAtLine(line)) continue
|
|
431
|
-
if (!config.listExists(list)) continue
|
|
432
|
-
log = require('debug')('extractLinkStyleTasks')
|
|
433
|
-
log('*********************************************************')
|
|
434
|
-
log(result)
|
|
435
|
-
log('list:%s text:%s order:%d line:%d', list, text, order, line)
|
|
436
|
-
|
|
437
|
-
var task = self.extractTaskWithDescription({
|
|
438
|
-
config,
|
|
439
|
-
list,
|
|
440
|
-
text,
|
|
441
|
-
order,
|
|
442
|
-
line,
|
|
443
|
-
type: Task.Types.MARKDOWN,
|
|
444
|
-
hasColon: !!colon,
|
|
445
|
-
content: content.substring(result.index),
|
|
446
|
-
pos: posInContent,
|
|
447
|
-
})
|
|
448
|
-
task.rawTask = rawTask
|
|
449
|
-
self.addTask(task)
|
|
450
|
-
self.emit('task.found', task)
|
|
451
467
|
}
|
|
452
|
-
}
|
|
453
468
|
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
469
|
+
extractCheckboxTasks (config, pos, content) {
|
|
470
|
+
if (!this.isMarkDownFile()) return
|
|
471
|
+
if (!config.isAddCheckBoxTasks()) return
|
|
457
472
|
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
const hasTaskAtLine = (line) => {
|
|
464
|
-
return (
|
|
465
|
-
this.getTaskAtLine(line) ||
|
|
466
|
-
tasks.find((task) => {
|
|
467
|
-
return line >= task.line && line <= task.lastLine
|
|
468
|
-
})
|
|
469
|
-
)
|
|
470
|
-
}
|
|
471
|
-
while ((result = checkStyleRegex.exec(content)) !== null) {
|
|
472
|
-
if (this.isResultInMarkdownCode(codePositions, result.index)) continue;
|
|
473
|
-
let [match, before, checked, text] = result
|
|
474
|
-
const list =
|
|
475
|
-
checked.trim() === 'x' ? config.getDoneList() : config.getDefaultList()
|
|
476
|
-
const beforeLength = before.length
|
|
477
|
-
const posInContent = result.index + pos + beforeLength
|
|
478
|
-
var line = this.getLineNumber(posInContent)
|
|
479
|
-
if (hasTaskAtLine(line)) continue
|
|
480
|
-
var task = this.extractTaskWithDescription({
|
|
481
|
-
config,
|
|
482
|
-
list,
|
|
483
|
-
text,
|
|
484
|
-
line,
|
|
485
|
-
type,
|
|
486
|
-
hasColon: true,
|
|
487
|
-
content: content.substring(result.index),
|
|
488
|
-
pos: posInContent,
|
|
489
|
-
})
|
|
490
|
-
task.rawTask = getRawTask({tokenPrefix: config.tokenPrefix, orderMeta: config.orderMeta, list, text, type})
|
|
491
|
-
tasks.push(task)
|
|
492
|
-
}
|
|
493
|
-
if (tasks) {
|
|
473
|
+
const codePositions = this.getMarkdownCodePositions(content);
|
|
474
|
+
const type = Task.Types[config.getNewCardSyntax()]
|
|
475
|
+
const checkStyleRegex = new RegExp(CHECK_STYLE_PATTERN)
|
|
476
|
+
let result
|
|
477
|
+
let tasks = []
|
|
494
478
|
const hasTaskAtLine = (line) => {
|
|
495
479
|
return (
|
|
496
480
|
this.getTaskAtLine(line) ||
|
|
497
481
|
tasks.find((task) => {
|
|
498
|
-
return line
|
|
482
|
+
return line >= task.line && line <= task.lastLine
|
|
499
483
|
})
|
|
500
484
|
)
|
|
501
485
|
}
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
486
|
+
while ((result = checkStyleRegex.exec(content)) !== null) {
|
|
487
|
+
if (this.isResultInMarkdownCode(codePositions, result.index)) continue;
|
|
488
|
+
let [match, before, checked, text] = result
|
|
489
|
+
const list =
|
|
490
|
+
checked.trim() === 'x' ? config.getDoneList() : config.getDefaultList()
|
|
491
|
+
const beforeLength = before.length
|
|
492
|
+
const posInContent = result.index + pos + beforeLength
|
|
493
|
+
var line = this.getLineNumber(posInContent)
|
|
494
|
+
if (hasTaskAtLine(line)) continue
|
|
495
|
+
var task = this.extractTaskWithDescription({
|
|
496
|
+
config,
|
|
497
|
+
list,
|
|
498
|
+
text,
|
|
499
|
+
line,
|
|
500
|
+
type,
|
|
501
|
+
hasColon: true,
|
|
502
|
+
content: content.substring(result.index),
|
|
503
|
+
pos: posInContent,
|
|
504
|
+
})
|
|
505
|
+
task.rawTask = getRawTask({tokenPrefix: config.tokenPrefix, orderMeta: config.orderMeta, list, text, type})
|
|
506
|
+
tasks.push(task)
|
|
507
|
+
}
|
|
508
|
+
if (tasks) {
|
|
509
|
+
const hasTaskAtLine = (line) => {
|
|
510
|
+
return (
|
|
511
|
+
this.getTaskAtLine(line) ||
|
|
512
|
+
tasks.find((task) => {
|
|
513
|
+
return line > task.line && line <= task.lastLine
|
|
514
|
+
})
|
|
515
|
+
)
|
|
516
|
+
}
|
|
517
|
+
tasks = tasks.filter((task) => {
|
|
518
|
+
return !hasTaskAtLine(task.line)
|
|
519
|
+
})
|
|
520
|
+
if (!tasks) return
|
|
521
|
+
let newContent = content
|
|
522
|
+
tasks.reverse().forEach((task) => {
|
|
523
|
+
this.addTask(task)
|
|
524
|
+
const beforeTaskContent = content.substring(0, task.pos)
|
|
525
|
+
const afterTaskContent = newContent.substring(task.pos + task.text.length)
|
|
526
|
+
newContent = beforeTaskContent + task.rawTask + afterTaskContent
|
|
527
|
+
this.emit('task.found', task)
|
|
528
|
+
})
|
|
518
529
|
|
|
519
|
-
|
|
520
|
-
console.log('extractCheckboxTasks setModified true for file:', this.path)
|
|
530
|
+
if (this.content === newContent || !newContent) return
|
|
521
531
|
|
|
522
|
-
|
|
523
|
-
}
|
|
532
|
+
this.content = newContent
|
|
524
533
|
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
const data = this.parseFrontMatter(config)
|
|
529
|
-
if (data.imdone_ignore || data['kanban-plugin']) return this
|
|
534
|
+
this.setModified(true)
|
|
535
|
+
logger.log('extractCheckboxTasks setModified true for file:', this.path)
|
|
536
|
+
}
|
|
530
537
|
}
|
|
531
|
-
|
|
532
|
-
this.
|
|
533
|
-
|
|
534
|
-
|
|
538
|
+
extractTasks (config) {
|
|
539
|
+
this.tasks = []
|
|
540
|
+
if (this.isMarkDownFile()) {
|
|
541
|
+
const data = this.parseFrontMatter(config)
|
|
542
|
+
if (data.imdone_ignore || data['kanban-plugin']) return this
|
|
543
|
+
}
|
|
544
|
+
if (this.isCodeFile()) {
|
|
545
|
+
this.extractTasksInCodeFile(config)
|
|
546
|
+
} else {
|
|
547
|
+
this.extractTasksInNonCodeFile(config)
|
|
548
|
+
}
|
|
549
|
+
return this
|
|
535
550
|
}
|
|
536
|
-
return this
|
|
537
|
-
}
|
|
538
|
-
|
|
539
|
-
File.prototype.extractAndTransformTasks = function (config) {
|
|
540
|
-
this.extractTasks(config)
|
|
541
|
-
this.transformTasks(config)
|
|
542
|
-
}
|
|
543
551
|
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
File.prototype.extractTasksInCodeFile = function (config) {
|
|
548
|
-
var self = this
|
|
549
|
-
var commentRegex = this.getCodeCommentRegex()
|
|
550
|
-
var result
|
|
551
|
-
while ((result = commentRegex.exec(self.getContent())) !== null) {
|
|
552
|
-
var comment = result[0]
|
|
553
|
-
var commentStart = result.index
|
|
554
|
-
self.extractCodeStyleTasks(config, commentStart, comment)
|
|
552
|
+
extractAndTransformTasks (config) {
|
|
553
|
+
this.extractTasks(config)
|
|
554
|
+
this.transformTasks(config)
|
|
555
555
|
}
|
|
556
|
-
}
|
|
557
556
|
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
557
|
+
// TODO Extract functions should be moved to another file
|
|
558
|
+
// Only pass the needed config values to the functions
|
|
559
|
+
// #imdone-1.54.0
|
|
560
|
+
// <!--
|
|
561
|
+
// order:40
|
|
562
|
+
// -->
|
|
563
|
+
extractTasksInCodeFile (config) {
|
|
564
|
+
var self = this
|
|
565
|
+
var commentRegex = this.getCodeCommentRegex()
|
|
566
|
+
var result
|
|
567
|
+
while ((result = commentRegex.exec(self.getContent())) !== null) {
|
|
568
|
+
var comment = result[0]
|
|
569
|
+
var commentStart = result.index
|
|
570
|
+
self.extractCodeStyleTasks(config, commentStart, comment)
|
|
571
|
+
}
|
|
572
|
+
}
|
|
563
573
|
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
if (startOfNextLine < 0) return
|
|
569
|
-
var content = this.content
|
|
570
|
-
var lineContent = content.substring(startOfLine, startOfNextLine)
|
|
571
|
-
const trimmedLine = lineContent.trim()
|
|
572
|
-
if (
|
|
573
|
-
trimmedLine === '' ||
|
|
574
|
-
(this.isMarkDownFile() && /^(-|\*+|\#+)$/.test(trimmedLine))
|
|
575
|
-
) {
|
|
576
|
-
var start = content.substring(0, startOfLine)
|
|
577
|
-
var end = content.substring(startOfNextLine)
|
|
578
|
-
this.setContent(start + end)
|
|
574
|
+
extractTasksInNonCodeFile (config) {
|
|
575
|
+
this.extractHashStyleTasks(config, 0, this.getContent())
|
|
576
|
+
this.extractLinkStyleTasks(config, 0, this.getContent())
|
|
577
|
+
this.extractCheckboxTasks(config, 0, this.getContent())
|
|
579
578
|
}
|
|
580
|
-
}
|
|
581
579
|
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
580
|
+
deleteBlankLine (lineNo) {
|
|
581
|
+
var startOfLine = this.getLinePos(lineNo)
|
|
582
|
+
if (this.isMarkDownFile()) startOfLine = startOfLine - 1
|
|
583
|
+
var startOfNextLine = this.getLinePos(lineNo + 1)
|
|
584
|
+
if (startOfNextLine < 0) return
|
|
585
|
+
var content = this.content
|
|
586
|
+
var lineContent = content.substring(startOfLine, startOfNextLine)
|
|
587
|
+
const trimmedLine = lineContent.trim()
|
|
587
588
|
if (
|
|
588
|
-
|
|
589
|
-
|
|
589
|
+
trimmedLine === '' ||
|
|
590
|
+
(this.isMarkDownFile() && /^(-|\*+|\#+)$/.test(trimmedLine))
|
|
590
591
|
) {
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
beforeContent = beforeContent.substring(0, blockStartPos)
|
|
595
|
-
afterContent = afterContent.substring(blockEndPos)
|
|
592
|
+
var start = content.substring(0, startOfLine)
|
|
593
|
+
var end = content.substring(startOfNextLine)
|
|
594
|
+
this.setContent(start + end)
|
|
596
595
|
}
|
|
597
596
|
}
|
|
598
597
|
|
|
599
|
-
|
|
600
|
-
|
|
598
|
+
deleteTaskContent (beforeContent, afterContent) {
|
|
599
|
+
const lang = this.getLang()
|
|
600
|
+
if (this.isCodeFile() && lang.block) {
|
|
601
|
+
const beforeContentTrim = beforeContent.trim()
|
|
602
|
+
const blockStartTrimPos = beforeContentTrim.lastIndexOf(lang.block.start)
|
|
603
|
+
if (
|
|
604
|
+
blockStartTrimPos > -1 &&
|
|
605
|
+
blockStartTrimPos === beforeContentTrim.length - lang.block.start.length
|
|
606
|
+
) {
|
|
607
|
+
const blockStartPos = beforeContent.lastIndexOf(lang.block.start)
|
|
608
|
+
const blockEndPos =
|
|
609
|
+
afterContent.indexOf(lang.block.end) + lang.block.end.length
|
|
610
|
+
beforeContent = beforeContent.substring(0, blockStartPos)
|
|
611
|
+
afterContent = afterContent.substring(blockEndPos)
|
|
612
|
+
}
|
|
613
|
+
}
|
|
601
614
|
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
615
|
+
this.setContent(beforeContent + afterContent)
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
deleteDescription (task, config) {
|
|
619
|
+
if (task.singleLineBlockComment) return
|
|
620
|
+
task.description = []
|
|
621
|
+
this.modifyDescription(task, config)
|
|
622
|
+
}
|
|
607
623
|
|
|
608
|
-
// TODO This isn't deleting all the newlines at the end of each line in code files
|
|
609
|
-
// <!--
|
|
610
|
-
// #bug
|
|
611
|
-
// #imdone-1.54.0
|
|
612
|
-
// order:-165
|
|
613
|
-
// -->
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
624
|
+
// TODO This isn't deleting all the newlines at the end of each line in code files
|
|
625
|
+
// <!--
|
|
626
|
+
// #bug
|
|
627
|
+
// #imdone-1.54.0
|
|
628
|
+
// order:-165
|
|
629
|
+
// -->
|
|
630
|
+
deleteCodeOrHashTask (re, task, config) {
|
|
631
|
+
var log = debug('delete-task:deleteCodeOrHashTask')
|
|
632
|
+
var self = this
|
|
633
|
+
var line = task.getLine()
|
|
634
|
+
re = new XRegExp(re)
|
|
635
|
+
re.lastIndex = this.getLinePos(line)
|
|
636
|
+
var result = re.exec(this.getContent())
|
|
637
|
+
if (result) {
|
|
638
|
+
log('Got result: %j', result)
|
|
639
|
+
var lang = self.getLang()
|
|
640
|
+
var text = result[task.type === Task.Types.HASHTAG ? 4 : 5]
|
|
641
|
+
var taskText = this.trimCommentBlockEnd(text)
|
|
642
|
+
if (this.tasksMatch(config, task, line, taskText)) {
|
|
643
|
+
var index = result.index
|
|
644
|
+
var afterStart = re.lastIndex
|
|
645
|
+
if (index < 0) index = 0
|
|
646
|
+
if (self.isCodeFile()) {
|
|
647
|
+
var commentStart = this.getLinePos(line) + task.taskStartOnLine
|
|
648
|
+
var commentPrefix = this.getContent().substring(commentStart, index)
|
|
649
|
+
var symbolRe = new RegExp(escapeRegExp(lang.symbol) + '\\s*')
|
|
650
|
+
if (symbolRe.test(commentPrefix)) index = commentStart
|
|
651
|
+
else if (lang && lang.block && lang.block.end) {
|
|
652
|
+
var blockEndRe = new RegExp(escapeRegExp(lang.block.end) + '\\s*$')
|
|
653
|
+
var match = blockEndRe.exec(task.rawTask)
|
|
654
|
+
if (match) afterStart -= match[0].length
|
|
655
|
+
}
|
|
639
656
|
}
|
|
657
|
+
var beforeContent = this.getContent().substring(0, index)
|
|
658
|
+
var afterContent = this.getContent().substring(afterStart)
|
|
659
|
+
this.deleteTaskContent(beforeContent, afterContent)
|
|
660
|
+
this.deleteBlankLine(line)
|
|
661
|
+
this.setModified(true)
|
|
662
|
+
// task.type = Task.Types.HASHTAG;
|
|
663
|
+
this.emit('task.deleted', task)
|
|
664
|
+
this.emit('file.modified', self)
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
return this
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
deleteTask (task, config) {
|
|
672
|
+
var self = this
|
|
673
|
+
if (this.isCodeFile()) {
|
|
674
|
+
this.deleteDescription(task, config)
|
|
675
|
+
if (task.type === Task.Types.CODE) {
|
|
676
|
+
this.deleteCodeOrHashTask(
|
|
677
|
+
new RegExp(CODE_STYLE_PATTERN, 'gm'),
|
|
678
|
+
task,
|
|
679
|
+
config
|
|
680
|
+
)
|
|
681
|
+
} else if (task.type === Task.Types.HASHTAG) {
|
|
682
|
+
this.deleteCodeOrHashTask(getHashStyleRegex(config.tokenPrefix), task, config)
|
|
640
683
|
}
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
684
|
+
} else {
|
|
685
|
+
const fileContent = this.getContentLines()
|
|
686
|
+
const newContent = [
|
|
687
|
+
...fileContent.slice(0, task.line - 1),
|
|
688
|
+
...fileContent.slice(task.lastLine),
|
|
689
|
+
]
|
|
690
|
+
this.setContent(newContent.join(lineEnd))
|
|
645
691
|
this.setModified(true)
|
|
646
|
-
// task.type = Task.Types.HASHTAG;
|
|
647
692
|
this.emit('task.deleted', task)
|
|
648
693
|
this.emit('file.modified', self)
|
|
649
694
|
}
|
|
650
695
|
}
|
|
651
696
|
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
File.prototype.deleteTask = function (task, config) {
|
|
656
|
-
var self = this
|
|
657
|
-
if (this.isCodeFile()) {
|
|
658
|
-
this.deleteDescription(task, config)
|
|
697
|
+
modifyTask (task, config, noEmit) {
|
|
698
|
+
task.orderModified = true
|
|
699
|
+
task.updateOrderMeta(config)
|
|
659
700
|
if (task.type === Task.Types.CODE) {
|
|
660
|
-
this.
|
|
701
|
+
this.modifyCodeOrHashTask(
|
|
661
702
|
new RegExp(CODE_STYLE_PATTERN, 'gm'),
|
|
662
703
|
task,
|
|
663
|
-
config
|
|
704
|
+
config,
|
|
705
|
+
noEmit
|
|
664
706
|
)
|
|
665
|
-
} else
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
this.modifyCodeOrHashTask(
|
|
686
|
-
new RegExp(CODE_STYLE_PATTERN, 'gm'),
|
|
687
|
-
task,
|
|
688
|
-
config,
|
|
689
|
-
noEmit
|
|
690
|
-
)
|
|
691
|
-
} else {
|
|
692
|
-
task.updateContent()
|
|
693
|
-
const fileContent = this.getContentLines()
|
|
694
|
-
let text = getRawTask({
|
|
695
|
-
tokenPrefix: config.tokenPrefix,
|
|
696
|
-
orderMeta: config.orderMeta,
|
|
697
|
-
beforeText: task.beforeText,
|
|
698
|
-
hasColon: task.hasColon,
|
|
699
|
-
list: task.list,
|
|
700
|
-
order: task.order,
|
|
701
|
-
text: task.text,
|
|
702
|
-
type: task.type,
|
|
703
|
-
})
|
|
704
|
-
const linesBefore = fileContent.slice(0, task.line - 1)
|
|
705
|
-
if (this.isCodeFile()) {
|
|
706
|
-
const linesBeforeLength = linesBefore.join(lineEnd).length
|
|
707
|
-
const charsBefore = task.pos - (linesBeforeLength + 1)
|
|
708
|
-
if (charsBefore > 0) {
|
|
709
|
-
text = fileContent[task.line -1].substring(0,charsBefore) + text
|
|
707
|
+
} else {
|
|
708
|
+
task.updateContent()
|
|
709
|
+
const fileContent = this.getContentLines()
|
|
710
|
+
let text = getRawTask({
|
|
711
|
+
tokenPrefix: config.tokenPrefix,
|
|
712
|
+
orderMeta: config.orderMeta,
|
|
713
|
+
beforeText: task.beforeText,
|
|
714
|
+
hasColon: task.hasColon,
|
|
715
|
+
list: task.list,
|
|
716
|
+
order: task.order,
|
|
717
|
+
text: task.text,
|
|
718
|
+
type: task.type,
|
|
719
|
+
})
|
|
720
|
+
const linesBefore = fileContent.slice(0, task.line - 1)
|
|
721
|
+
if (this.isCodeFile()) {
|
|
722
|
+
const linesBeforeLength = linesBefore.join(lineEnd).length
|
|
723
|
+
const charsBefore = task.pos - (linesBeforeLength + 1)
|
|
724
|
+
if (charsBefore > 0) {
|
|
725
|
+
text = fileContent[task.line -1].substring(0,charsBefore) + text
|
|
726
|
+
}
|
|
710
727
|
}
|
|
711
|
-
}
|
|
712
|
-
|
|
713
|
-
const linesAfter = fileContent.slice(task.line)
|
|
714
|
-
const newContent = [
|
|
715
|
-
...linesBefore,
|
|
716
|
-
text,
|
|
717
|
-
...linesAfter,
|
|
718
|
-
].join(lineEnd)
|
|
719
728
|
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
729
|
+
const linesAfter = fileContent.slice(task.line)
|
|
730
|
+
const newContent = [
|
|
731
|
+
...linesBefore,
|
|
732
|
+
text,
|
|
733
|
+
...linesAfter,
|
|
734
|
+
].join(lineEnd)
|
|
724
735
|
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
this.
|
|
728
|
-
this.
|
|
729
|
-
}
|
|
730
|
-
}
|
|
731
|
-
}
|
|
736
|
+
const contentBeforeUpdate = this.getContent()
|
|
737
|
+
this.setContent(newContent)
|
|
738
|
+
this.modifyDescription(task, config)
|
|
739
|
+
if (contentBeforeUpdate.trim() == this.getContent().trim()) return
|
|
732
740
|
|
|
733
|
-
File.prototype.modifyCodeOrHashTask = function (re, task, config, noEmit) {
|
|
734
|
-
log('In modifyCodeOrHashTask:%j', task)
|
|
735
|
-
log('--------------------------------')
|
|
736
|
-
log(`modifying task: ${task.rawTask}`)
|
|
737
|
-
log(`line: ${task.line}`)
|
|
738
|
-
var self = this
|
|
739
|
-
var line = task.getLine()
|
|
740
|
-
re = new RegExp(re)
|
|
741
|
-
var lang = this.getLang()
|
|
742
|
-
var linePos = (re.lastIndex = this.getLinePos(line))
|
|
743
|
-
var nextLinePos = this.getLinePos(line + 1)
|
|
744
|
-
var lineContent = this.getContent().substring(linePos, nextLinePos)
|
|
745
|
-
if (lineContent.indexOf(lang.symbol) > -1) {
|
|
746
|
-
re.lastIndex = this.getContent().indexOf(lang.symbol, linePos)
|
|
747
|
-
}
|
|
748
|
-
if (lang.block && lineContent.indexOf(lang.block.start) > -1) {
|
|
749
|
-
re.lastIndex = this.getContent().indexOf(lang.block.start, linePos)
|
|
750
|
-
}
|
|
751
|
-
|
|
752
|
-
var result
|
|
753
|
-
while ((result = re.exec(this.getContent())) !== null) {
|
|
754
|
-
log('Got result: %j', result)
|
|
755
|
-
var text = result[task.type === Task.Types.HASHTAG ? 3 : 5]
|
|
756
|
-
var taskText = this.trimCommentBlockEnd(text)
|
|
757
|
-
if (this.tasksMatch(config, task, line, taskText)) {
|
|
758
|
-
if (task.updatedText) task.text = task.updatedText
|
|
759
|
-
var index = result.index
|
|
760
|
-
const pos = this.isCodeFile() ? index : this.getLinePos(line)
|
|
761
|
-
if (index < 0) index = 0
|
|
762
|
-
var beforeContent = this.getContent().substring(0, pos)
|
|
763
|
-
var afterContent = this.getContent().substring(re.lastIndex)
|
|
764
|
-
if (task.inBlockComment) {
|
|
765
|
-
var blockEnd = text.indexOf(lang.block.end)
|
|
766
|
-
if (blockEnd > -1) {
|
|
767
|
-
const desc =
|
|
768
|
-
task.description.length > 0
|
|
769
|
-
? `${lineEnd}${task.description.join(lineEnd)}`
|
|
770
|
-
: ''
|
|
771
|
-
text = task.text + desc + text.substring(blockEnd)
|
|
772
|
-
} else text = task.text
|
|
773
|
-
} else text = task.text
|
|
774
|
-
if (/[a-z]/.test(task.list)) task.type = Task.Types.HASHTAG
|
|
775
|
-
const tokenPrefix = task.type === Task.Types.HASHTAG ? config.tokenPrefix : ''
|
|
776
|
-
var taskContent = getRawTask({tokenPrefix, orderMeta: config.orderMeta, list: task.list, order: task.order, text, type: task.type})
|
|
777
|
-
task.line = this.getLineNumber(index)
|
|
778
|
-
task.id = getTaskId(self.getPath(), task.line, task.text)
|
|
779
|
-
this.setContent(beforeContent + taskContent + afterContent)
|
|
780
|
-
if (!task.singleLineBlockComment) {
|
|
781
|
-
this.modifyDescription(task, config)
|
|
782
|
-
}
|
|
783
741
|
this.setModified(true)
|
|
784
|
-
// console.log('modifyCodeOrHashTask setModified true for file:', this.path)
|
|
785
742
|
if (!noEmit) {
|
|
786
743
|
this.emit('task.modified', task)
|
|
787
|
-
this.emit('file.modified',
|
|
744
|
+
this.emit('file.modified', this)
|
|
788
745
|
}
|
|
789
|
-
return this
|
|
790
746
|
}
|
|
791
747
|
}
|
|
792
748
|
|
|
793
|
-
|
|
794
|
-
|
|
749
|
+
modifyCodeOrHashTask (re, task, config, noEmit) {
|
|
750
|
+
log('In modifyCodeOrHashTask:%j', task)
|
|
751
|
+
log('--------------------------------')
|
|
752
|
+
log(`modifying task: ${task.rawTask}`)
|
|
753
|
+
log(`line: ${task.line}`)
|
|
754
|
+
var self = this
|
|
755
|
+
var line = task.getLine()
|
|
756
|
+
re = new RegExp(re)
|
|
757
|
+
var lang = this.getLang()
|
|
758
|
+
var linePos = (re.lastIndex = this.getLinePos(line))
|
|
759
|
+
var nextLinePos = this.getLinePos(line + 1)
|
|
760
|
+
var lineContent = this.getContent().substring(linePos, nextLinePos)
|
|
761
|
+
if (lineContent.indexOf(lang.symbol) > -1) {
|
|
762
|
+
re.lastIndex = this.getContent().indexOf(lang.symbol, linePos)
|
|
763
|
+
}
|
|
764
|
+
if (lang.block && lineContent.indexOf(lang.block.start) > -1) {
|
|
765
|
+
re.lastIndex = this.getContent().indexOf(lang.block.start, linePos)
|
|
766
|
+
}
|
|
795
767
|
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
768
|
+
var result
|
|
769
|
+
while ((result = re.exec(this.getContent())) !== null) {
|
|
770
|
+
log('Got result: %j', result)
|
|
771
|
+
var text = result[task.type === Task.Types.HASHTAG ? 3 : 5]
|
|
772
|
+
var taskText = this.trimCommentBlockEnd(text)
|
|
773
|
+
if (this.tasksMatch(config, task, line, taskText)) {
|
|
774
|
+
if (task.updatedText) task.text = task.updatedText
|
|
775
|
+
var index = result.index
|
|
776
|
+
const pos = this.isCodeFile() ? index : this.getLinePos(line)
|
|
777
|
+
if (index < 0) index = 0
|
|
778
|
+
var beforeContent = this.getContent().substring(0, pos)
|
|
779
|
+
var afterContent = this.getContent().substring(re.lastIndex)
|
|
780
|
+
if (task.inBlockComment) {
|
|
781
|
+
var blockEnd = text.indexOf(lang.block.end)
|
|
782
|
+
if (blockEnd > -1) {
|
|
783
|
+
const desc =
|
|
784
|
+
task.description.length > 0
|
|
785
|
+
? `${lineEnd}${task.description.join(lineEnd)}`
|
|
786
|
+
: ''
|
|
787
|
+
text = task.text + desc + text.substring(blockEnd)
|
|
788
|
+
} else text = task.text
|
|
789
|
+
} else text = task.text
|
|
790
|
+
if (/[a-z]/.test(task.list)) task.type = Task.Types.HASHTAG
|
|
791
|
+
const tokenPrefix = task.type === Task.Types.HASHTAG ? config.tokenPrefix : ''
|
|
792
|
+
var taskContent = getRawTask({tokenPrefix, orderMeta: config.orderMeta, list: task.list, order: task.order, text, type: task.type})
|
|
793
|
+
task.line = this.getLineNumber(index)
|
|
794
|
+
task.id = getTaskId(self.getPath(), task.line, task.text)
|
|
795
|
+
this.setContent(beforeContent + taskContent + afterContent)
|
|
796
|
+
if (!task.singleLineBlockComment) {
|
|
797
|
+
this.modifyDescription(task, config)
|
|
798
|
+
}
|
|
799
|
+
this.setModified(true)
|
|
800
|
+
// logger.log('modifyCodeOrHashTask setModified true for file:', this.path)
|
|
801
|
+
if (!noEmit) {
|
|
802
|
+
this.emit('task.modified', task)
|
|
803
|
+
this.emit('file.modified', self)
|
|
804
|
+
}
|
|
805
|
+
return this
|
|
806
|
+
}
|
|
807
|
+
}
|
|
816
808
|
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
console.log('modifyTaskFromHtml setModified true for file:', this.path)
|
|
820
|
-
}
|
|
809
|
+
return this
|
|
810
|
+
}
|
|
821
811
|
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
812
|
+
modifyTaskFromHtml (task, html) {
|
|
813
|
+
const checks = task.getChecksFromHtml(html)
|
|
814
|
+
const re = /- \[[\sx]{1}\]/g
|
|
815
|
+
const descStart = this.getLinePos(task.line + 1)
|
|
816
|
+
const descEnd = this.getLinePos(task.line + 1 + task.description.length)
|
|
817
|
+
let descContent =
|
|
818
|
+
descEnd > 0
|
|
819
|
+
? this.getContent().substring(descStart, descEnd)
|
|
820
|
+
: this.getContent().substring(descStart)
|
|
821
|
+
const beforeDescContent = this.getContent().substring(0, descStart)
|
|
822
|
+
const afterDescContent =
|
|
823
|
+
descEnd > 0 ? this.getContent().substring(descEnd) : ''
|
|
824
|
+
let i = 0
|
|
825
|
+
descContent = descContent.replace(re, (match) => {
|
|
826
|
+
const check = checks[i]
|
|
827
|
+
i++
|
|
828
|
+
if (check === undefined) return match
|
|
829
|
+
let char = check ? 'x' : ' '
|
|
830
|
+
return `- [${char}]`
|
|
831
|
+
})
|
|
827
832
|
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
}
|
|
833
|
-
return content.replace(/\n\s*\n\s*\n/g, '\n\n')
|
|
834
|
-
}
|
|
833
|
+
this.setContent(beforeDescContent + descContent + afterDescContent)
|
|
834
|
+
this.setModified(true)
|
|
835
|
+
logger.log('modifyTaskFromHtml setModified true for file:', this.path)
|
|
836
|
+
}
|
|
835
837
|
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
const descStart = this.getLinePos(task.line + 1)
|
|
842
|
-
const contentWithTask = this.getContent().substring(taskStart)
|
|
843
|
-
let {
|
|
844
|
-
rawTaskContentLines,
|
|
845
|
-
taskContentLines,
|
|
846
|
-
isWrappedWithCardTag,
|
|
847
|
-
trailingBlankLines
|
|
848
|
-
} =
|
|
849
|
-
this.getTaskContent({
|
|
850
|
-
config,
|
|
851
|
-
content: contentWithTask,
|
|
852
|
-
inBlockComment: task.inBlockComment,
|
|
853
|
-
beforeText: task.beforeText,
|
|
854
|
-
})
|
|
838
|
+
modifyTaskFromContent (task, content, config) {
|
|
839
|
+
content = trimBlankLines(content, this.isCodeFile())
|
|
840
|
+
task.updateFromContent(content)
|
|
841
|
+
this.modifyTask(task, config)
|
|
842
|
+
}
|
|
855
843
|
|
|
856
|
-
|
|
844
|
+
modifyDescription (task, config) {
|
|
845
|
+
// TODO This should be split out by type (code, markdown, etc)
|
|
846
|
+
// #urgent
|
|
847
|
+
// <!-- order:-70 -->
|
|
848
|
+
const taskStart = this.getLinePos(task.line)
|
|
849
|
+
const descStart = this.getLinePos(task.line + 1)
|
|
850
|
+
const contentWithTask = this.getContent().substring(taskStart)
|
|
851
|
+
let {
|
|
852
|
+
rawTaskContentLines,
|
|
853
|
+
taskContentLines,
|
|
854
|
+
isWrappedWithCardTag,
|
|
855
|
+
trailingBlankLines
|
|
856
|
+
} =
|
|
857
|
+
this.getTaskContent({
|
|
858
|
+
config,
|
|
859
|
+
content: contentWithTask,
|
|
860
|
+
inBlockComment: task.inBlockComment,
|
|
861
|
+
beforeText: task.beforeText,
|
|
862
|
+
})
|
|
857
863
|
|
|
858
|
-
|
|
859
|
-
beforeDescContent += lineEnd
|
|
860
|
-
|
|
861
|
-
let content = this.getContent().substring(descStart)
|
|
862
|
-
let spaces = ''
|
|
863
|
-
if (this.isCodeFile() && !this.isMarkDownFile()) {
|
|
864
|
-
spaces = contentWithTask.substring(0, task.commentStartOnLine)
|
|
865
|
-
spaces = spaces.replace(/\S/g, ' ')
|
|
866
|
-
}
|
|
867
|
-
const descriptionStartsWith = task.descriptionStartsWith
|
|
868
|
-
? `${task.descriptionStartsWith} `
|
|
869
|
-
: ''
|
|
870
|
-
let description = task.description.map(
|
|
871
|
-
(desc) => `${spaces}${descriptionStartsWith}${desc}`
|
|
872
|
-
)
|
|
873
|
-
// BACKLOG Allow this to pad for code files as well
|
|
874
|
-
// <!--
|
|
875
|
-
// order:-620
|
|
876
|
-
// -->
|
|
877
|
-
description = File.padDescription(description, task.beforeText).join(lineEnd)
|
|
878
|
-
if (taskContentLines.length === 0 && description.length > 0) {
|
|
879
|
-
beforeDescContent += description + lineEnd
|
|
880
|
-
} else {
|
|
881
|
-
let rawTaskContent = rawTaskContentLines.join(lineEnd)
|
|
882
|
-
// Add card terminator to description
|
|
883
|
-
if (
|
|
884
|
-
this.isMarkDownFile() &&
|
|
885
|
-
description.length > 0 &&
|
|
886
|
-
(hasBlankLines(description) || isWrappedWithCardTag || trailingBlankLines)
|
|
887
|
-
) {
|
|
888
|
-
task.isWrappedWithCardTag = isWrappedWithCardTag // FIXME Find out where this is used and stop using it
|
|
889
|
-
// <!-- order:-30 -->
|
|
890
|
-
const blankLinesToAdd = isWrappedWithCardTag ? 2 : trailingBlankLines
|
|
891
|
-
description = `${description}${lineEnd.repeat(blankLinesToAdd)}`
|
|
892
|
-
}
|
|
864
|
+
let beforeDescContent = this.getContent().substring(0, descStart)
|
|
893
865
|
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
) {
|
|
900
|
-
|
|
866
|
+
if (descStart === this.getContent().length && !beforeDescContent.endsWith(lf))
|
|
867
|
+
beforeDescContent += lineEnd
|
|
868
|
+
|
|
869
|
+
let content = this.getContent().substring(descStart)
|
|
870
|
+
let spaces = ''
|
|
871
|
+
if (this.isCodeFile() && !this.isMarkDownFile()) {
|
|
872
|
+
spaces = contentWithTask.substring(0, task.commentStartOnLine)
|
|
873
|
+
spaces = spaces.replace(/\S/g, ' ')
|
|
901
874
|
}
|
|
902
|
-
|
|
903
|
-
|
|
875
|
+
const descriptionStartsWith = task.descriptionStartsWith
|
|
876
|
+
? `${task.descriptionStartsWith} `
|
|
877
|
+
: ''
|
|
878
|
+
let description = task.description.map(
|
|
879
|
+
(desc) => `${spaces}${descriptionStartsWith}${desc}`
|
|
880
|
+
)
|
|
881
|
+
// BACKLOG Allow this to pad for code files as well
|
|
882
|
+
// <!--
|
|
883
|
+
// order:-620
|
|
884
|
+
// -->
|
|
885
|
+
description = File.padDescription(description, task.beforeText).join(lineEnd)
|
|
886
|
+
if (taskContentLines.length === 0 && description.length > 0) {
|
|
887
|
+
beforeDescContent += description + lineEnd
|
|
888
|
+
} else {
|
|
889
|
+
let rawTaskContent = rawTaskContentLines.join(lineEnd)
|
|
890
|
+
// Add card terminator to description
|
|
891
|
+
if (
|
|
892
|
+
this.isMarkDownFile() &&
|
|
893
|
+
description.length > 0 &&
|
|
894
|
+
(hasBlankLines(description) || isWrappedWithCardTag || trailingBlankLines)
|
|
895
|
+
) {
|
|
896
|
+
task.isWrappedWithCardTag = isWrappedWithCardTag // FIXME Find out where this is used and stop using it
|
|
897
|
+
// <!-- order:-30 -->
|
|
898
|
+
const blankLinesToAdd = isWrappedWithCardTag ? 2 : trailingBlankLines
|
|
899
|
+
description = `${description}${lineEnd.repeat(blankLinesToAdd)}`
|
|
900
|
+
}
|
|
904
901
|
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
902
|
+
// Handle code file tasks
|
|
903
|
+
if (
|
|
904
|
+
task.singleLineBlockComment &&
|
|
905
|
+
rawTaskContent.length > 0 &&
|
|
906
|
+
description.length === 0
|
|
907
|
+
) {
|
|
908
|
+
description = lineEnd + description
|
|
909
|
+
}
|
|
910
|
+
content = content.replace(rawTaskContent, description)
|
|
911
|
+
}
|
|
908
912
|
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
}
|
|
913
|
+
task.lastLine = task.line + description.split(lineEnd).length
|
|
914
|
+
this.setContent(beforeDescContent + content)
|
|
915
|
+
}
|
|
912
916
|
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
config,
|
|
917
|
-
list,
|
|
918
|
-
text,
|
|
919
|
-
order,
|
|
920
|
-
line,
|
|
921
|
-
type,
|
|
922
|
-
hasColon,
|
|
923
|
-
content,
|
|
924
|
-
inBlockComment,
|
|
925
|
-
singleLineBlockComment,
|
|
926
|
-
pos,
|
|
927
|
-
}) {
|
|
928
|
-
var self = this
|
|
929
|
-
const lang = this.getLang()
|
|
930
|
-
let description = []
|
|
931
|
-
// BACKLOG ## add beforeText for code files
|
|
932
|
-
// <!--
|
|
933
|
-
// order:-630
|
|
934
|
-
// -->
|
|
935
|
-
const beforeText = this.getBeforeText(line, pos)
|
|
936
|
-
let { rawTaskContentLines, taskContentLines, isWrappedWithCardTag } = this.getTaskContent({
|
|
917
|
+
extractTaskWithDescription ({
|
|
918
|
+
taskStartOnLine,
|
|
919
|
+
rawTask,
|
|
937
920
|
config,
|
|
921
|
+
list,
|
|
922
|
+
text,
|
|
923
|
+
order,
|
|
924
|
+
line,
|
|
925
|
+
type,
|
|
926
|
+
hasColon,
|
|
938
927
|
content,
|
|
939
928
|
inBlockComment,
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
if (descriptionStartsWith === lang.symbol)
|
|
955
|
-
commentStartOnLine = taskStartOnLine
|
|
956
|
-
|
|
957
|
-
var task = newCard(
|
|
958
|
-
{
|
|
959
|
-
pos,
|
|
960
|
-
frontMatter,
|
|
929
|
+
singleLineBlockComment,
|
|
930
|
+
pos,
|
|
931
|
+
}) {
|
|
932
|
+
var self = this
|
|
933
|
+
const lang = this.getLang()
|
|
934
|
+
let description = []
|
|
935
|
+
// BACKLOG ## add beforeText for code files
|
|
936
|
+
// <!--
|
|
937
|
+
// order:-630
|
|
938
|
+
// -->
|
|
939
|
+
const beforeText = this.getBeforeText(line, pos)
|
|
940
|
+
let { rawTaskContentLines, taskContentLines, isWrappedWithCardTag } = this.getTaskContent({
|
|
941
|
+
config,
|
|
942
|
+
content,
|
|
961
943
|
inBlockComment,
|
|
962
|
-
singleLineBlockComment,
|
|
963
|
-
rawTask,
|
|
964
|
-
text,
|
|
965
|
-
list,
|
|
966
|
-
rawTaskContentLines,
|
|
967
|
-
description,
|
|
968
|
-
descriptionStartsWith,
|
|
969
|
-
taskStartOnLine,
|
|
970
|
-
commentStartOnLine,
|
|
971
|
-
hasColon,
|
|
972
|
-
order: self.projectContext.getOrder(list, order),
|
|
973
|
-
line,
|
|
974
|
-
id: getTaskId(self.getPath(), line, text),
|
|
975
|
-
repoId: self.getRepoId(),
|
|
976
|
-
source: self.getSource(),
|
|
977
|
-
type,
|
|
978
944
|
beforeText,
|
|
979
|
-
|
|
980
|
-
},
|
|
981
|
-
this.project
|
|
982
|
-
)
|
|
983
|
-
|
|
984
|
-
task.init()
|
|
985
|
-
if (!config.keepEmptyPriority) task.updateOrderMeta(config, task.format(task.descriptionString))
|
|
986
|
-
task.orderModified = task.order + "" !== order + "" && !bothAreUndefNull(task.order, order)
|
|
945
|
+
})
|
|
987
946
|
|
|
988
|
-
|
|
989
|
-
|
|
947
|
+
if (!singleLineBlockComment) {
|
|
948
|
+
description = this.isCodeFile()
|
|
949
|
+
? taskContentLines.map((line) => this.trimCommentChars(line))
|
|
950
|
+
: structuredClone(taskContentLines)
|
|
951
|
+
}
|
|
952
|
+
description = Task.trimDescription(description, beforeText)
|
|
953
|
+
const descriptionStartsWith = this.getDescriptionChars(inBlockComment)
|
|
954
|
+
const frontMatter = this.frontMatter
|
|
955
|
+
text = this.trimCommentBlockEnd(text)
|
|
956
|
+
let commentStartOnLine =
|
|
957
|
+
content.search(/\w/) - (descriptionStartsWith.length + 1)
|
|
958
|
+
if (descriptionStartsWith === lang.symbol)
|
|
959
|
+
commentStartOnLine = taskStartOnLine
|
|
960
|
+
|
|
961
|
+
var task = newCard(
|
|
962
|
+
{
|
|
963
|
+
pos,
|
|
964
|
+
frontMatter,
|
|
965
|
+
inBlockComment,
|
|
966
|
+
singleLineBlockComment,
|
|
967
|
+
rawTask,
|
|
968
|
+
text,
|
|
969
|
+
list,
|
|
970
|
+
rawTaskContentLines,
|
|
971
|
+
description,
|
|
972
|
+
descriptionStartsWith,
|
|
973
|
+
taskStartOnLine,
|
|
974
|
+
commentStartOnLine,
|
|
975
|
+
hasColon,
|
|
976
|
+
order: self.projectContext.getOrder(list, order),
|
|
977
|
+
line,
|
|
978
|
+
id: getTaskId(self.getPath(), line, text),
|
|
979
|
+
repoId: self.getRepoId(),
|
|
980
|
+
source: self.getSource(),
|
|
981
|
+
type,
|
|
982
|
+
beforeText,
|
|
983
|
+
isWrappedWithCardTag,
|
|
984
|
+
},
|
|
985
|
+
this.project
|
|
986
|
+
)
|
|
990
987
|
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
988
|
+
task.init()
|
|
989
|
+
if (!config.keepEmptyPriority) task.updateOrderMeta(config, task.format(task.descriptionString))
|
|
990
|
+
task.orderModified = task.order + "" !== order + "" && !bothAreUndefNull(task.order, order)
|
|
994
991
|
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
}
|
|
992
|
+
return task
|
|
993
|
+
}
|
|
998
994
|
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
}
|
|
995
|
+
tasksMatch (config, task, line, taskText) {
|
|
996
|
+
return (
|
|
997
|
+
task.id == getTaskId(this.getPath(), line, taskText) ||
|
|
998
|
+
(task.meta.id &&
|
|
999
|
+
Task.getMetaData(config, taskText).id &&
|
|
1000
|
+
task.meta.id[0] === Task.getMetaData(config, taskText).id[0])
|
|
1001
|
+
)
|
|
1002
|
+
}
|
|
1007
1003
|
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
}
|
|
1004
|
+
getTaskAtLine (line) {
|
|
1005
|
+
return this.getTasks().find((task) => {
|
|
1006
|
+
return line >= task.line && line <= task.lastLine
|
|
1007
|
+
})
|
|
1008
|
+
}
|
|
1013
1009
|
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
}
|
|
1010
|
+
getLinePos (lineNo) {
|
|
1011
|
+
return Task.getLinePos(this.content, lineNo)
|
|
1012
|
+
}
|
|
1017
1013
|
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
}
|
|
1014
|
+
getLineNumber (pos, content = this.content) {
|
|
1015
|
+
return Task.getLineNumber(content, pos)
|
|
1016
|
+
}
|
|
1021
1017
|
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
}
|
|
1018
|
+
toJSON () {
|
|
1019
|
+
return _omit(this, ['domain', '_events', '_maxListeners'])
|
|
1020
|
+
}
|
|
1025
1021
|
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
}
|
|
1022
|
+
getRepoId () {
|
|
1023
|
+
return this.repoId
|
|
1024
|
+
}
|
|
1029
1025
|
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
}
|
|
1026
|
+
getPath () {
|
|
1027
|
+
return this.path
|
|
1028
|
+
}
|
|
1033
1029
|
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
}
|
|
1030
|
+
getFullPath () {
|
|
1031
|
+
return path.join(this.repoId, this.path)
|
|
1032
|
+
}
|
|
1037
1033
|
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
}
|
|
1034
|
+
getId () {
|
|
1035
|
+
return this.getPath()
|
|
1036
|
+
}
|
|
1041
1037
|
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1038
|
+
reset () {
|
|
1039
|
+
this.previousContent = this.content
|
|
1040
|
+
this.content = null
|
|
1041
|
+
this.modified = false
|
|
1042
|
+
return this
|
|
1043
|
+
}
|
|
1047
1044
|
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
}
|
|
1045
|
+
rollback () {
|
|
1046
|
+
this.content = this.previousContent
|
|
1047
|
+
return this
|
|
1048
|
+
}
|
|
1052
1049
|
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
}
|
|
1050
|
+
setContent (content) {
|
|
1051
|
+
this.content = content
|
|
1052
|
+
return this
|
|
1053
|
+
}
|
|
1057
1054
|
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
}
|
|
1055
|
+
setContentFromFile (content) {
|
|
1056
|
+
this.content = eol.auto(content || '')
|
|
1057
|
+
return this
|
|
1058
|
+
}
|
|
1062
1059
|
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
}
|
|
1060
|
+
getContent () {
|
|
1061
|
+
return this.content
|
|
1062
|
+
}
|
|
1066
1063
|
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
}
|
|
1064
|
+
getContentForFile () {
|
|
1065
|
+
return eol.auto(this.content || '')
|
|
1066
|
+
}
|
|
1070
1067
|
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
}
|
|
1068
|
+
getContentLines () {
|
|
1069
|
+
return eol.split(this.getContentForFile())
|
|
1070
|
+
}
|
|
1074
1071
|
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
}
|
|
1072
|
+
setModifiedTime (modifiedTime) {
|
|
1073
|
+
this.modifiedTime = modifiedTime
|
|
1074
|
+
return this
|
|
1075
|
+
}
|
|
1079
1076
|
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
}
|
|
1077
|
+
setCreatedTime (createdTime) {
|
|
1078
|
+
this.createdTime = createdTime
|
|
1079
|
+
return this
|
|
1080
|
+
}
|
|
1084
1081
|
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
}
|
|
1082
|
+
getCreatedTime () {
|
|
1083
|
+
return this.createdTime
|
|
1084
|
+
}
|
|
1088
1085
|
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
}
|
|
1086
|
+
getModifiedTime () {
|
|
1087
|
+
return this.modifiedTime
|
|
1088
|
+
}
|
|
1092
1089
|
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
}
|
|
1090
|
+
setModified (modified) {
|
|
1091
|
+
this.modified = modified
|
|
1092
|
+
return this
|
|
1093
|
+
}
|
|
1097
1094
|
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
}
|
|
1095
|
+
isModified () {
|
|
1096
|
+
return this.modified
|
|
1097
|
+
}
|
|
1101
1098
|
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
}
|
|
1099
|
+
getType () {
|
|
1100
|
+
return this.constructor.name
|
|
1101
|
+
}
|
|
1105
1102
|
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
}
|
|
1103
|
+
getTasks () {
|
|
1104
|
+
return this.tasks
|
|
1105
|
+
}
|
|
1109
1106
|
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1107
|
+
getTask (id) {
|
|
1108
|
+
return (
|
|
1109
|
+
this.getTasks().find((task) => id === task.id) ||
|
|
1110
|
+
this.getTasks().find(
|
|
1111
|
+
(task) => task.meta && task.meta.id && task.meta.id[0] === id.toString()
|
|
1112
|
+
)
|
|
1115
1113
|
)
|
|
1116
|
-
|
|
1117
|
-
}
|
|
1114
|
+
}
|
|
1118
1115
|
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
}
|
|
1116
|
+
addTask (task) {
|
|
1117
|
+
if (!(task instanceof Task)) throw new Error(ERRORS.NOT_A_TASK)
|
|
1118
|
+
if (!Array.isArray(this.tasks)) this.tasks = []
|
|
1119
|
+
var index = this.tasks.findIndex(({ id }) => task.id === id)
|
|
1120
|
+
log(
|
|
1121
|
+
'Adding task with text:%s in list:%s with order:%d at index %d',
|
|
1122
|
+
task.text,
|
|
1123
|
+
task.list,
|
|
1124
|
+
task.order,
|
|
1125
|
+
index
|
|
1126
|
+
)
|
|
1127
|
+
if (index > -1) {
|
|
1128
|
+
this.tasks[index] = task
|
|
1129
|
+
} else {
|
|
1130
|
+
this.tasks.push(task)
|
|
1131
|
+
}
|
|
1132
|
+
return this
|
|
1133
|
+
}
|
|
1137
1134
|
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1135
|
+
removeTask (task) {
|
|
1136
|
+
if (!(task instanceof Task)) throw new Error(ERRORS.NOT_A_TASK)
|
|
1137
|
+
if (!Array.isArray(this.tasks)) this.tasks = []
|
|
1138
|
+
var index = this.tasks.findIndex(({ id }) => task.id === id)
|
|
1139
|
+
if (index > -1) {
|
|
1140
|
+
this.tasks.splice(index, 1)
|
|
1141
|
+
}
|
|
1144
1142
|
}
|
|
1145
|
-
}
|
|
1146
1143
|
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
}
|
|
1144
|
+
isMarkDownFile () {
|
|
1145
|
+
return /^md|markdown$/i.test(this.getExt())
|
|
1146
|
+
}
|
|
1150
1147
|
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
}
|
|
1148
|
+
getLang () {
|
|
1149
|
+
var lang = this.languages[path.extname(this.path)]
|
|
1150
|
+
return lang || { name: 'text', symbol: '' }
|
|
1151
|
+
}
|
|
1155
1152
|
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
}
|
|
1153
|
+
getExt () {
|
|
1154
|
+
return path.extname(this.path).substring(1).toLowerCase()
|
|
1155
|
+
}
|
|
1159
1156
|
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
}
|
|
1157
|
+
isCodeFile () {
|
|
1158
|
+
var symbol = this.getLang().symbol
|
|
1159
|
+
return symbol && symbol !== ''
|
|
1160
|
+
}
|
|
1164
1161
|
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
}
|
|
1162
|
+
getBeforeText (line, pos) {
|
|
1163
|
+
return this.isCodeFile()
|
|
1164
|
+
? null
|
|
1165
|
+
: this.content.substring(this.getLinePos(line), pos)
|
|
1166
|
+
}
|
|
1170
1167
|
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
}
|
|
1168
|
+
getDescriptionChars (inBlockComment) {
|
|
1169
|
+
if (!this.isCodeFile()) return ''
|
|
1170
|
+
const lang = this.getLang()
|
|
1171
|
+
if (inBlockComment && lang.block && lang.block.ignore) return lang.block.ignore
|
|
1172
|
+
return lang.symbol
|
|
1173
|
+
}
|
|
1177
1174
|
|
|
1178
|
-
|
|
1179
|
-
config,
|
|
1180
|
-
content,
|
|
1181
|
-
inBlockComment,
|
|
1182
|
-
beforeText,
|
|
1183
|
-
}) {
|
|
1184
|
-
const isMarkDownFile = this.isMarkDownFile()
|
|
1185
|
-
const isCodeFile = this.isCodeFile()
|
|
1186
|
-
const lang = this.getLang()
|
|
1187
|
-
const fileType = isMarkDownFile ? FILE_TYPES.MARKDOWN : isCodeFile ? FILE_TYPES.CODE : undefined
|
|
1188
|
-
return getTaskContent({
|
|
1175
|
+
getTaskContent ({
|
|
1189
1176
|
config,
|
|
1190
1177
|
content,
|
|
1191
1178
|
inBlockComment,
|
|
1192
1179
|
beforeText,
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1180
|
+
}) {
|
|
1181
|
+
const isMarkDownFile = this.isMarkDownFile()
|
|
1182
|
+
const isCodeFile = this.isCodeFile()
|
|
1183
|
+
const lang = this.getLang()
|
|
1184
|
+
const fileType = isMarkDownFile ? FILE_TYPES.MARKDOWN : isCodeFile ? FILE_TYPES.CODE : undefined
|
|
1185
|
+
return getTaskContent({
|
|
1186
|
+
config,
|
|
1187
|
+
content,
|
|
1188
|
+
inBlockComment,
|
|
1189
|
+
beforeText,
|
|
1190
|
+
lang,
|
|
1191
|
+
fileType,
|
|
1192
|
+
})
|
|
1193
|
+
}
|
|
1197
1194
|
|
|
1198
|
-
|
|
1199
|
-
|
|
1195
|
+
isCheckBoxTask (config, line, beforeText) {
|
|
1196
|
+
if (!config.isAddCheckBoxTasks()) return
|
|
1200
1197
|
|
|
1201
|
-
|
|
1202
|
-
|
|
1198
|
+
const beforeTextCheckData = Task.getCheckedData(beforeText)
|
|
1199
|
+
if (!beforeTextCheckData) return
|
|
1203
1200
|
|
|
1204
|
-
|
|
1205
|
-
|
|
1201
|
+
const lineCheckData = Task.getCheckedData(line)
|
|
1202
|
+
if (!lineCheckData) return
|
|
1206
1203
|
|
|
1207
|
-
|
|
1208
|
-
}
|
|
1204
|
+
return lineCheckData.pad <= beforeTextCheckData.pad
|
|
1205
|
+
}
|
|
1209
1206
|
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1207
|
+
getCodeCommentRegex () {
|
|
1208
|
+
// #BACKLOG:-460 Allow languages to have multiple block comment styles, like html gh:13 id:5
|
|
1209
|
+
var lang = this.getLang()
|
|
1210
|
+
var symbol = lang.symbol
|
|
1211
|
+
var reString = '(?<!["\'`])' + escapeRegExp(symbol) + '[^{].*$'
|
|
1215
1212
|
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1213
|
+
if (lang.block) {
|
|
1214
|
+
var start = escapeRegExp(lang.block.start)
|
|
1215
|
+
var end = escapeRegExp(lang.block.end)
|
|
1216
|
+
//
|
|
1217
|
+
reString = reString + '|(?<!["\'`])' + start + '(.|[\\r\\n])*?' + end
|
|
1218
|
+
}
|
|
1219
|
+
|
|
1220
|
+
return new RegExp(reString, 'gmi')
|
|
1221
1221
|
}
|
|
1222
1222
|
|
|
1223
|
-
|
|
1224
|
-
|
|
1223
|
+
trimCommentStart (text) {
|
|
1224
|
+
if (this.isCodeFile() && this.getLang().symbol) {
|
|
1225
|
+
var start = escapeRegExp(this.getLang().symbol)
|
|
1226
|
+
var startPattern = `^\\s*${start}\\s?`
|
|
1227
|
+
return text.replace(new RegExp(startPattern), '')
|
|
1228
|
+
}
|
|
1229
|
+
return text
|
|
1230
|
+
}
|
|
1225
1231
|
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1232
|
+
trimCommentBlockEnd (text) {
|
|
1233
|
+
if (this.isCodeFile() && this.getLang().block) {
|
|
1234
|
+
var blockEnd = escapeRegExp(this.getLang().block.end)
|
|
1235
|
+
var endPattern = `\\s?${blockEnd}.*$`
|
|
1236
|
+
return text.replace(new RegExp(endPattern), '')
|
|
1237
|
+
}
|
|
1238
|
+
return text
|
|
1231
1239
|
}
|
|
1232
|
-
return text
|
|
1233
|
-
}
|
|
1234
1240
|
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1241
|
+
trimCommentBlockStart (text) {
|
|
1242
|
+
if (this.isCodeFile() && this.getLang().block) {
|
|
1243
|
+
var blockStart = escapeRegExp(this.getLang().block.start)
|
|
1244
|
+
var startPattern = `^\\s*${blockStart}\\s?`
|
|
1245
|
+
return text.replace(new RegExp(startPattern), '')
|
|
1246
|
+
}
|
|
1247
|
+
return text
|
|
1240
1248
|
}
|
|
1241
|
-
return text
|
|
1242
|
-
}
|
|
1243
1249
|
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1250
|
+
trimCommentBlockIgnore (text) {
|
|
1251
|
+
if (
|
|
1252
|
+
this.isCodeFile() &&
|
|
1253
|
+
this.getLang().block &&
|
|
1254
|
+
this.getLang().block.ignore
|
|
1255
|
+
) {
|
|
1256
|
+
var blockIgnore = escapeRegExp(this.getLang().block.ignore)
|
|
1257
|
+
var ignorePattern = `^\\s*${blockIgnore}\\s?`
|
|
1258
|
+
return text.replace(new RegExp(ignorePattern), '')
|
|
1259
|
+
}
|
|
1260
|
+
return text
|
|
1249
1261
|
}
|
|
1250
|
-
return text
|
|
1251
|
-
}
|
|
1252
1262
|
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
this.
|
|
1256
|
-
this.
|
|
1257
|
-
this.
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
var ignorePattern = `^\\s*${blockIgnore}\\s?`
|
|
1261
|
-
return text.replace(new RegExp(ignorePattern), '')
|
|
1262
|
-
}
|
|
1263
|
-
return text
|
|
1264
|
-
}
|
|
1263
|
+
trimCommentChars (text) {
|
|
1264
|
+
let newText = this.trimCommentStart(text)
|
|
1265
|
+
if (text === newText) newText = this.trimCommentBlockEnd(text)
|
|
1266
|
+
if (text === newText) newText = this.trimCommentBlockStart(text)
|
|
1267
|
+
if (text === newText) newText = this.trimCommentBlockIgnore(text)
|
|
1268
|
+
return newText
|
|
1269
|
+
}
|
|
1265
1270
|
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
}
|
|
1271
|
+
hasCodeStyleTask (config, text) {
|
|
1272
|
+
if (!this.isCodeFile()) return false
|
|
1273
|
+
let result = new RegExp(CODE_STYLE_PATTERN).exec(text)
|
|
1274
|
+
if (!result) return false
|
|
1275
|
+
return config.includeList(result[1])
|
|
1276
|
+
}
|
|
1273
1277
|
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
if (!result) return false
|
|
1278
|
-
return config.includeList(result[1])
|
|
1279
|
-
}
|
|
1278
|
+
hasTaskInText (config, text) {
|
|
1279
|
+
return hasTaskInText(config, text, this.isCodeFile())
|
|
1280
|
+
}
|
|
1280
1281
|
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1282
|
+
isInBlockComment (content) {
|
|
1283
|
+
if (!this.isCodeFile()) return false
|
|
1284
|
+
const lang = this.getLang()
|
|
1285
|
+
return (
|
|
1286
|
+
lang.block &&
|
|
1287
|
+
lang.block.start &&
|
|
1288
|
+
content.trim().startsWith(lang.block.start)
|
|
1289
|
+
)
|
|
1290
|
+
}
|
|
1284
1291
|
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1292
|
+
startsWithCommentOrSpace (pos) {
|
|
1293
|
+
var lang = this.getLang()
|
|
1294
|
+
var symbol = lang.symbol
|
|
1295
|
+
var blockStart = lang.block && lang.block.start
|
|
1296
|
+
if (symbol === this.getContent().substring(pos - symbol.length, pos))
|
|
1297
|
+
return true
|
|
1298
|
+
if (
|
|
1299
|
+
blockStart &&
|
|
1300
|
+
blockStart === this.getContent().substring(pos - blockStart.length, pos)
|
|
1301
|
+
)
|
|
1302
|
+
return true
|
|
1303
|
+
if (this.getContent().substring(pos - 1, pos) === ' ') return true
|
|
1304
|
+
return false
|
|
1305
|
+
}
|
|
1294
1306
|
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
var blockStart = lang.block && lang.block.start
|
|
1299
|
-
if (symbol === this.getContent().substring(pos - symbol.length, pos))
|
|
1300
|
-
return true
|
|
1301
|
-
if (
|
|
1302
|
-
blockStart &&
|
|
1303
|
-
blockStart === this.getContent().substring(pos - blockStart.length, pos)
|
|
1304
|
-
)
|
|
1305
|
-
return true
|
|
1306
|
-
if (this.getContent().substring(pos - 1, pos) === ' ') return true
|
|
1307
|
-
return false
|
|
1308
|
-
}
|
|
1307
|
+
isSingleLineBlockComment (content) {
|
|
1308
|
+
return eol.split(content).length === 1
|
|
1309
|
+
}
|
|
1309
1310
|
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1311
|
+
parseFrontMatter (config) {
|
|
1312
|
+
this.frontMatter = {
|
|
1313
|
+
tags: [],
|
|
1314
|
+
context: [],
|
|
1315
|
+
meta: {},
|
|
1316
|
+
}
|
|
1313
1317
|
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
? data.tags.map((tag) => tag.trim())
|
|
1338
|
-
: data.tags
|
|
1339
|
-
.toString()
|
|
1340
|
-
.split(',')
|
|
1341
|
-
.map((tag) => tag.trim())
|
|
1318
|
+
if (config.ignoreFrontMatter) return {}
|
|
1319
|
+
try {
|
|
1320
|
+
const { data, isEmpty } = matter(this.getContent())
|
|
1321
|
+
if (!isEmpty) {
|
|
1322
|
+
this.frontMatter = { props: {}, ...data, ...this.frontMatter }
|
|
1323
|
+
if (data.meta) this.frontMatter.meta = getFrontMeta(data.meta)
|
|
1324
|
+
if (data.context) {
|
|
1325
|
+
this.frontMatter.context = Array.isArray(data.context)
|
|
1326
|
+
? data.context.map((context) => context.trim())
|
|
1327
|
+
: data.context
|
|
1328
|
+
.toString()
|
|
1329
|
+
.split(',')
|
|
1330
|
+
.map((context) => context.trim())
|
|
1331
|
+
}
|
|
1332
|
+
if (data.tags && !config.ignoreFrontMatterTags) {
|
|
1333
|
+
this.frontMatter.tags = Array.isArray(data.tags)
|
|
1334
|
+
? data.tags.map((tag) => tag.trim())
|
|
1335
|
+
: data.tags
|
|
1336
|
+
.toString()
|
|
1337
|
+
.split(',')
|
|
1338
|
+
.map((tag) => tag.trim())
|
|
1339
|
+
}
|
|
1340
|
+
return data
|
|
1342
1341
|
}
|
|
1343
|
-
|
|
1342
|
+
} catch (err) {
|
|
1343
|
+
logger.error(`Error processing front-matter in:${this.path}`, err)
|
|
1344
1344
|
}
|
|
1345
|
-
|
|
1346
|
-
console.error(`Error processing front-matter in:${this.path}`, err)
|
|
1345
|
+
return {}
|
|
1347
1346
|
}
|
|
1348
|
-
return {}
|
|
1349
|
-
}
|
|
1350
1347
|
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1348
|
+
getSource () {
|
|
1349
|
+
var self = this
|
|
1350
|
+
return {
|
|
1351
|
+
path: self.getPath(),
|
|
1352
|
+
id: self.getId(),
|
|
1353
|
+
repoId: self.getRepoId(),
|
|
1354
|
+
type: self.getType(),
|
|
1355
|
+
ext: self.getExt(),
|
|
1356
|
+
lang: self.getLang().name,
|
|
1357
|
+
modified: self.isModified(),
|
|
1358
|
+
modifiedTime: self.getModifiedTime(),
|
|
1359
|
+
createdTime: self.getCreatedTime(),
|
|
1360
|
+
}
|
|
1363
1361
|
}
|
|
1364
|
-
}
|
|
1365
1362
|
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
}
|
|
1370
|
-
|
|
1371
|
-
File.prototype.getMarkdownCodePositions = function (text) {
|
|
1372
|
-
const positions = [];
|
|
1373
|
-
const codeBlockRe = /```[\s\S]*?```/g;
|
|
1374
|
-
const inlineCodeRe = /`[^`]*`/g;
|
|
1363
|
+
isWithinCodeSpanOrBlock(pos, content) {
|
|
1364
|
+
const positions = Task.getMarkdownCodePositions(content)
|
|
1365
|
+
return Task.isResultInMarkdownCode(positions, pos)
|
|
1366
|
+
}
|
|
1375
1367
|
|
|
1376
|
-
|
|
1368
|
+
getMarkdownCodePositions (text) {
|
|
1369
|
+
const positions = [];
|
|
1370
|
+
const codeBlockRe = /```[\s\S]*?```/g;
|
|
1371
|
+
const inlineCodeRe = /`[^`]*`/g;
|
|
1377
1372
|
|
|
1378
|
-
|
|
1379
|
-
while ((match = codeBlockRe.exec(text)) !== null) {
|
|
1380
|
-
positions.push({ start: match.index, end: match.index + match[0].length });
|
|
1381
|
-
}
|
|
1373
|
+
let match;
|
|
1382
1374
|
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1375
|
+
// Find code blocks
|
|
1376
|
+
while ((match = codeBlockRe.exec(text)) !== null) {
|
|
1377
|
+
positions.push({ start: match.index, end: match.index + match[0].length });
|
|
1378
|
+
}
|
|
1387
1379
|
|
|
1388
|
-
|
|
1389
|
-
|
|
1380
|
+
// Find inline code spans
|
|
1381
|
+
while ((match = inlineCodeRe.exec(text)) !== null) {
|
|
1382
|
+
positions.push({ start: match.index, end: match.index + match[0].length });
|
|
1383
|
+
}
|
|
1390
1384
|
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
};
|
|
1385
|
+
return positions;
|
|
1386
|
+
};
|
|
1394
1387
|
|
|
1395
|
-
|
|
1388
|
+
isResultInMarkdownCode (positions, index) {
|
|
1389
|
+
return positions.some(pos => index >= pos.start && index < pos.end);
|
|
1390
|
+
};
|
|
1391
|
+
}
|