imdone-core 2.2.0 → 2.3.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.
- package/.claude/settings.local.json +12 -0
- package/README.md +2 -2
- package/lib/adapters/parsers/file/LocalFileParserFactory.js +1 -1
- package/lib/adapters/parsers/file/ReadStreamCodeParser.js +185 -80
- package/lib/adapters/parsers/file/ReadStreamMarkdownParser.js +79 -4
- package/lib/adapters/parsers/file/ReadStreamTaskParser.js +20 -2
- package/lib/adapters/parsers/task/CheckStyleTaskParser.js +3 -2
- package/lib/adapters/parsers/task/CodeStyleTaskParser.js +1 -1
- package/lib/adapters/parsers/task/HashStyleTaskParser.js +1 -1
- package/lib/adapters/parsers/task/TaskParser.js +7 -2
- package/lib/file.js +2 -2
- package/lib/migrate-config.js +4 -3
- package/lib/repository.js +153 -24
- package/lib/utils/module-import.js +26 -0
- package/package.json +3 -3
- package/scripts/prepublish-only.js +30 -0
- package/types/adapters/parsers/file/ReadStreamCodeParser.d.ts +2 -4
- package/types/adapters/parsers/file/ReadStreamMarkdownParser.d.ts +11 -0
- package/types/adapters/parsers/file/ReadStreamTaskParser.d.ts +5 -1
- package/types/adapters/parsers/task/CheckStyleTaskParser.d.ts +2 -1
- package/types/adapters/parsers/task/TaskParser.d.ts +1 -1
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"permissions": {
|
|
3
|
+
"allow": [
|
|
4
|
+
"Bash(npm test:*)",
|
|
5
|
+
"Bash(node test-debug.js:*)",
|
|
6
|
+
"Bash(cat:*)",
|
|
7
|
+
"Bash(node test-ignore-patterns.js:*)",
|
|
8
|
+
"Bash(node test-ignore-patterns-detailed.js:*)",
|
|
9
|
+
"Bash(node test-ignore-patterns-fixed.js:*)"
|
|
10
|
+
]
|
|
11
|
+
}
|
|
12
|
+
}
|
package/README.md
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
[](https://npmjs.org/package/imdone-core)
|
|
3
3
|

|
|
4
4
|
|
|
5
|
-
Imdone is text based kanban processor with a simple syntax that uses [comment tags like TODO and FIXME](https://en.wikipedia.org/wiki/Comment_%28computer_programming%29#Tags) and [todo.txt format](https://github.com/todotxt/todo.txt#todotxt-format). This model allows the user to create and modify tasks using the keyboard and automatically establishes a link between their tasks and work. Get [imdone](https://imdone.io) or use the cli to see your projects board and this library in action.
|
|
5
|
+
Imdone is text based kanban processor with a simple syntax that uses [comment tags like TODO and FIXME](https://en.wikipedia.org/wiki/Comment_%28computer_programming%29#Tags) and [todo.txt format](https://github.com/todotxt/todo.txt#todotxt-format). This model allows the user to create and modify tasks using the keyboard and automatically establishes a link between their tasks and work. Get [imdone kanban](https://imdone.io/docs/imdone-kanban/) or use the [cli](https://imdone.io/docs/imdone-cli/) to see your projects board and this library in action.
|
|
6
6
|
|
|
7
|
-

|
|
7
|
+

|
|
8
8
|
|
|
9
9
|
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
|
|
10
10
|
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
|
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
import path from 'node:path'
|
|
2
2
|
import { ReadStreamTaskParser } from './ReadStreamTaskParser.js'
|
|
3
|
-
import { CodeStyleTaskParser } from '../task/CodeStyleTaskParser.js'
|
|
4
3
|
import { languages } from '../../../languages.js'
|
|
5
|
-
import
|
|
6
|
-
import eol from 'eol'
|
|
7
|
-
import { Readable } from 'node:stream'
|
|
4
|
+
import { CodeStyleTaskParser } from '../task/CodeStyleTaskParser.js'
|
|
8
5
|
|
|
9
6
|
// TODO Move to readstream parsing for code to improve performance
|
|
10
7
|
// <!--
|
|
@@ -18,109 +15,217 @@ export class ReadStreamCodeParser extends ReadStreamTaskParser {
|
|
|
18
15
|
this.lists = lists
|
|
19
16
|
this.filePath = filePath
|
|
20
17
|
this.lang = lang
|
|
21
|
-
this.taskParsers = [new CodeStyleTaskParser()]
|
|
22
18
|
}
|
|
23
19
|
|
|
24
20
|
async init() {
|
|
25
|
-
const code = await streamToString(this.readStream)
|
|
26
21
|
// TODO Getting tokens from lists should be done higher up in the controller
|
|
27
22
|
// <!--
|
|
28
23
|
// order:-10
|
|
29
24
|
// -->
|
|
30
|
-
const tokens = this.lists
|
|
31
|
-
|
|
25
|
+
const tokens = this.lists
|
|
26
|
+
.map((list) => {
|
|
27
|
+
if (typeof list === 'string') return list
|
|
28
|
+
if (!list || typeof list !== 'object') return undefined
|
|
29
|
+
return list.name
|
|
30
|
+
})
|
|
31
|
+
.filter(Boolean)
|
|
32
|
+
this.cards = await this.parseCards(tokens)
|
|
32
33
|
}
|
|
33
34
|
|
|
34
35
|
async readTask() {
|
|
35
36
|
return this.cards.shift()
|
|
36
37
|
}
|
|
37
38
|
|
|
38
|
-
parseCards(
|
|
39
|
-
const comments = this.parseComments(
|
|
40
|
-
const cards = []
|
|
41
|
-
|
|
39
|
+
async parseCards(tokens = ['TODO']) {
|
|
40
|
+
const comments = await this.parseComments()
|
|
41
|
+
const cards = []
|
|
42
|
+
const listNames = tokens.map((token) =>
|
|
43
|
+
typeof token === 'string' ? token : token?.name
|
|
44
|
+
).filter(Boolean)
|
|
45
|
+
const parser = new CodeStyleTaskParser({
|
|
46
|
+
includeList: (list) => listNames.includes(list),
|
|
47
|
+
listExists: (list) => listNames.includes(list),
|
|
48
|
+
lists: listNames.map((name) => ({ name })),
|
|
49
|
+
})
|
|
50
|
+
|
|
42
51
|
Object.keys(comments).forEach((comment) => {
|
|
43
|
-
const {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
52
|
+
const {
|
|
53
|
+
begin,
|
|
54
|
+
end,
|
|
55
|
+
content,
|
|
56
|
+
inBlockComment,
|
|
57
|
+
singleLineBlockComment,
|
|
58
|
+
} = comments[comment]
|
|
59
|
+
|
|
60
|
+
const lines = content.split('\n')
|
|
61
|
+
let activeTask = null
|
|
62
|
+
let taskLines = []
|
|
63
|
+
|
|
64
|
+
const flushActiveTask = (lineNo) => {
|
|
65
|
+
if (!activeTask) return
|
|
66
|
+
cards.push({
|
|
67
|
+
...activeTask,
|
|
68
|
+
content: `${taskLines.join('\n')}\n`,
|
|
69
|
+
line: activeTask.line,
|
|
70
|
+
lastLine: lineNo,
|
|
71
|
+
inBlockComment,
|
|
72
|
+
singleLineBlockComment,
|
|
73
|
+
})
|
|
74
|
+
activeTask = null
|
|
75
|
+
taskLines = []
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
lines.forEach((line, index) => {
|
|
79
|
+
const lineNo = begin + index
|
|
80
|
+
const parsedTask = parser.parseLine(line, lineNo)
|
|
81
|
+
|
|
82
|
+
if (parsedTask) {
|
|
83
|
+
flushActiveTask(lineNo - 1)
|
|
84
|
+
activeTask = parsedTask
|
|
85
|
+
taskLines = [line]
|
|
86
|
+
return
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (activeTask) {
|
|
90
|
+
taskLines.push(line)
|
|
61
91
|
}
|
|
62
|
-
})
|
|
63
|
-
|
|
64
|
-
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
flushActiveTask(end)
|
|
95
|
+
})
|
|
96
|
+
return cards
|
|
65
97
|
}
|
|
66
98
|
|
|
67
|
-
parseComments(
|
|
68
|
-
const options = getLanguageOptions(this.filePath);
|
|
69
|
-
const comments =
|
|
70
|
-
|
|
99
|
+
async parseComments() {
|
|
100
|
+
const options = getLanguageOptions(this.filePath, this.lang);
|
|
101
|
+
const comments = [];
|
|
102
|
+
let lineNo = 0;
|
|
103
|
+
let singleLineComment;
|
|
104
|
+
let blockComment;
|
|
105
|
+
|
|
106
|
+
const finishSingleLineComment = () => {
|
|
107
|
+
if (!singleLineComment) return
|
|
108
|
+
comments.push(singleLineComment)
|
|
109
|
+
singleLineComment = undefined
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
for await (const line of this.readInterface) {
|
|
113
|
+
lineNo++
|
|
114
|
+
|
|
115
|
+
if (blockComment) {
|
|
116
|
+
appendBlockCommentLine(blockComment, line, options)
|
|
117
|
+
if (line.includes(options.block.end)) {
|
|
118
|
+
blockComment.end = lineNo
|
|
119
|
+
comments.push(blockComment)
|
|
120
|
+
blockComment = undefined
|
|
121
|
+
}
|
|
122
|
+
continue
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const blockStartIndex = getBlockStartIndex(line, options)
|
|
126
|
+
const singleLineIndex = getSingleLineCommentIndex(line, options)
|
|
127
|
+
const blockStartsFirst = blockStartIndex > -1 && (singleLineIndex === -1 || blockStartIndex < singleLineIndex)
|
|
128
|
+
|
|
129
|
+
if (blockStartsFirst) {
|
|
130
|
+
finishSingleLineComment()
|
|
131
|
+
blockComment = {
|
|
132
|
+
begin: lineNo,
|
|
133
|
+
end: lineNo,
|
|
134
|
+
contentLines: [],
|
|
135
|
+
inBlockComment: true,
|
|
136
|
+
}
|
|
137
|
+
appendBlockCommentLine(blockComment, line, options)
|
|
138
|
+
if (line.includes(options.block.end)) {
|
|
139
|
+
comments.push(blockComment)
|
|
140
|
+
blockComment = undefined
|
|
141
|
+
}
|
|
142
|
+
} else if (singleLineIndex > -1) {
|
|
143
|
+
const content = line.slice(singleLineIndex + options.singleLineComment.length)
|
|
144
|
+
if (!singleLineComment || singleLineComment.end !== lineNo - 1) {
|
|
145
|
+
finishSingleLineComment()
|
|
146
|
+
singleLineComment = {
|
|
147
|
+
begin: lineNo,
|
|
148
|
+
end: lineNo,
|
|
149
|
+
contentLines: [],
|
|
150
|
+
inBlockComment: false,
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
singleLineComment.end = lineNo
|
|
154
|
+
singleLineComment.contentLines.push(trimCommentLine(content))
|
|
155
|
+
} else {
|
|
156
|
+
finishSingleLineComment()
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
finishSingleLineComment()
|
|
161
|
+
if (blockComment) comments.push(blockComment)
|
|
162
|
+
|
|
163
|
+
return comments.reduce((acc, comment, index) => {
|
|
164
|
+
acc[index] = {
|
|
165
|
+
begin: comment.begin,
|
|
166
|
+
end: comment.end,
|
|
167
|
+
content: formatCommentContent(comment.contentLines),
|
|
168
|
+
inBlockComment: comment.inBlockComment,
|
|
169
|
+
singleLineBlockComment: comment.inBlockComment && comment.begin === comment.end,
|
|
170
|
+
}
|
|
171
|
+
return acc
|
|
172
|
+
}, {})
|
|
71
173
|
}
|
|
72
174
|
|
|
73
175
|
}
|
|
74
176
|
|
|
177
|
+
function getBlockStartIndex(line, options) {
|
|
178
|
+
if (!options.block.start || !options.block.end) return -1
|
|
179
|
+
return line.indexOf(options.block.start)
|
|
180
|
+
}
|
|
75
181
|
|
|
76
|
-
function
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
const {
|
|
82
|
-
name,
|
|
83
|
-
symbol,
|
|
84
|
-
block,
|
|
85
|
-
} = language ||
|
|
86
|
-
{
|
|
87
|
-
name: 'text',
|
|
88
|
-
symbol: '',
|
|
89
|
-
block: {
|
|
90
|
-
start: undefined,
|
|
91
|
-
end: undefined,
|
|
92
|
-
ignore: undefined,
|
|
93
|
-
}
|
|
94
|
-
};
|
|
95
|
-
// Use lang to get comment patterns
|
|
96
|
-
|
|
97
|
-
const {
|
|
98
|
-
start,
|
|
99
|
-
ignore: middle,
|
|
100
|
-
end
|
|
101
|
-
} = block || {};
|
|
102
|
-
|
|
103
|
-
return language && {
|
|
104
|
-
pattern: {
|
|
105
|
-
name,
|
|
106
|
-
nameMatchers: extension && [extension] || [],
|
|
107
|
-
singleLineComment: symbol && [{ start: symbol }] || [],
|
|
108
|
-
multiLineComment: start && end && [{ start, middle, end }] || [],
|
|
109
|
-
},
|
|
110
|
-
};
|
|
182
|
+
function getSingleLineCommentIndex(line, options) {
|
|
183
|
+
if (!options.singleLineComment) return -1
|
|
184
|
+
return line.indexOf(options.singleLineComment)
|
|
111
185
|
}
|
|
112
186
|
|
|
113
|
-
|
|
114
|
-
const
|
|
187
|
+
function appendBlockCommentLine(comment, line, options) {
|
|
188
|
+
const startIndex = line.indexOf(options.block.start)
|
|
189
|
+
const contentStart = startIndex > -1 ? startIndex + options.block.start.length : 0
|
|
190
|
+
const endIndex = line.indexOf(options.block.end, contentStart)
|
|
191
|
+
const contentEnd = endIndex > -1 ? endIndex : line.length
|
|
192
|
+
const content = line.slice(contentStart, contentEnd)
|
|
193
|
+
|
|
194
|
+
comment.contentLines.push(trimCommentLine(content, options.block.ignore))
|
|
195
|
+
}
|
|
115
196
|
|
|
116
|
-
|
|
117
|
-
|
|
197
|
+
function trimCommentLine(line, ignoreToken) {
|
|
198
|
+
let trimmed = line.trimStart()
|
|
199
|
+
if (ignoreToken && trimmed.startsWith(ignoreToken)) {
|
|
200
|
+
trimmed = trimmed.slice(ignoreToken.length).trimStart()
|
|
118
201
|
}
|
|
202
|
+
return trimmed.trimEnd()
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function formatCommentContent(lines) {
|
|
206
|
+
const trimmedLines = trimBlankCommentLines(lines)
|
|
207
|
+
if (!trimmedLines.length) return ''
|
|
208
|
+
return `${trimmedLines.join('\n')}\n`
|
|
209
|
+
}
|
|
119
210
|
|
|
120
|
-
|
|
211
|
+
function trimBlankCommentLines(lines) {
|
|
212
|
+
const trimmedLines = [...lines]
|
|
213
|
+
while (trimmedLines[0] === '') trimmedLines.shift()
|
|
214
|
+
while (trimmedLines[trimmedLines.length - 1] === '') trimmedLines.pop()
|
|
215
|
+
return trimmedLines
|
|
121
216
|
}
|
|
122
217
|
|
|
123
|
-
function
|
|
124
|
-
const
|
|
125
|
-
|
|
218
|
+
function getLanguageOptions(filePath, lang) {
|
|
219
|
+
const extension = path.extname(filePath)
|
|
220
|
+
const language = lang || languages[extension]
|
|
221
|
+
const block = language?.block || {}
|
|
222
|
+
|
|
223
|
+
return {
|
|
224
|
+
singleLineComment: language?.symbol || '',
|
|
225
|
+
block: {
|
|
226
|
+
start: block.start,
|
|
227
|
+
ignore: block.ignore,
|
|
228
|
+
end: block.end,
|
|
229
|
+
},
|
|
230
|
+
}
|
|
126
231
|
}
|
|
@@ -1,17 +1,92 @@
|
|
|
1
1
|
import { ReadStreamTaskParser } from './ReadStreamTaskParser.js'
|
|
2
2
|
import { HashStyleTaskParser } from '../task/HashStyleTaskParser.js'
|
|
3
3
|
import { MarkdownStyleTaskParser } from '../task/MarkdownStyleTaskParser.js'
|
|
4
|
-
|
|
4
|
+
import { CheckStyleTaskParser } from '../task/CheckStyleTaskParser.js'
|
|
5
|
+
import { loadYAML } from '../../yaml.js'
|
|
6
|
+
|
|
7
|
+
const FRONTMATTER_DELIMITER = '---'
|
|
8
|
+
const CODE_FENCE_PATTERN = /^\s*(```|~~~)/
|
|
9
|
+
const INLINE_CODE_SPAN_PATTERN = /`[^`]*`/g
|
|
5
10
|
|
|
6
11
|
export class ReadStreamMarkdownParser extends ReadStreamTaskParser {
|
|
7
12
|
constructor(readStream, config) {
|
|
8
13
|
super(readStream, config)
|
|
14
|
+
this.frontmatterLines = []
|
|
15
|
+
this.collectingFrontmatter = false
|
|
16
|
+
this.frontmatterClosed = false
|
|
17
|
+
this.ignoredByFrontmatter = false
|
|
18
|
+
this.currentLineIsFrontmatter = false
|
|
19
|
+
this.currentLineIsCodeFence = false
|
|
20
|
+
this.inCodeFence = false
|
|
9
21
|
this.taskParsers = [
|
|
10
22
|
new HashStyleTaskParser(config),
|
|
11
23
|
new MarkdownStyleTaskParser(config),
|
|
12
24
|
]
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
25
|
+
if (config.isAddCheckBoxTasks()) {
|
|
26
|
+
this.taskParsers.push(new CheckStyleTaskParser(config))
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
onLineRead(line) {
|
|
31
|
+
this.updateFrontmatterState(line)
|
|
32
|
+
this.updateCodeFenceState(line)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
shouldParseTaskLine() {
|
|
36
|
+
return !this.ignoredByFrontmatter &&
|
|
37
|
+
!this.currentLineIsFrontmatter &&
|
|
38
|
+
!this.currentLineIsCodeFence
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
getLineForTaskParsing(line) {
|
|
42
|
+
return line.replace(INLINE_CODE_SPAN_PATTERN, (match) => ' '.repeat(match.length))
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
updateFrontmatterState(line) {
|
|
46
|
+
const trimmed = line.trim()
|
|
47
|
+
this.currentLineIsFrontmatter = false
|
|
48
|
+
|
|
49
|
+
if (this.lineNo === 1 && isFrontmatterDelimiter(trimmed)) {
|
|
50
|
+
this.collectingFrontmatter = true
|
|
51
|
+
this.currentLineIsFrontmatter = true
|
|
52
|
+
return
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (!this.collectingFrontmatter) return
|
|
56
|
+
|
|
57
|
+
this.currentLineIsFrontmatter = true
|
|
58
|
+
|
|
59
|
+
if (isFrontmatterDelimiter(trimmed)) {
|
|
60
|
+
this.collectingFrontmatter = false
|
|
61
|
+
this.frontmatterClosed = true
|
|
62
|
+
this.updateIgnoredByFrontmatter()
|
|
63
|
+
return
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
this.frontmatterLines.push(line)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
updateIgnoredByFrontmatter() {
|
|
70
|
+
if (!this.frontmatterClosed) return
|
|
71
|
+
const data = parseFrontmatter(this.frontmatterLines)
|
|
72
|
+
this.ignoredByFrontmatter = !!(data.imdone_ignore || data['kanban-plugin'])
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
updateCodeFenceState(line) {
|
|
76
|
+
const isFence = CODE_FENCE_PATTERN.test(line)
|
|
77
|
+
this.currentLineIsCodeFence = this.inCodeFence || isFence
|
|
78
|
+
if (isFence) this.inCodeFence = !this.inCodeFence
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function isFrontmatterDelimiter(trimmedLine) {
|
|
83
|
+
return trimmedLine === FRONTMATTER_DELIMITER
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function parseFrontmatter(lines) {
|
|
87
|
+
try {
|
|
88
|
+
return loadYAML(lines.join('\n')) || {}
|
|
89
|
+
} catch (error) {
|
|
90
|
+
return {}
|
|
16
91
|
}
|
|
17
92
|
}
|
|
@@ -16,11 +16,13 @@ export class ReadStreamTaskParser {
|
|
|
16
16
|
crlfDelay: Infinity,
|
|
17
17
|
console: false,
|
|
18
18
|
})
|
|
19
|
+
this.lineIterator = this.readInterface[Symbol.asyncIterator]()
|
|
19
20
|
}
|
|
20
21
|
|
|
21
22
|
async readTask() {
|
|
22
23
|
let taskOrStreamDone = false
|
|
23
24
|
this.task = this.nextTask || null
|
|
25
|
+
this.nextTask = null
|
|
24
26
|
this.blankLines = 0
|
|
25
27
|
|
|
26
28
|
try {
|
|
@@ -29,6 +31,7 @@ export class ReadStreamTaskParser {
|
|
|
29
31
|
let { value, done } = this.line
|
|
30
32
|
if (this.line && !done) {
|
|
31
33
|
this.lineNo++
|
|
34
|
+
this.onLineRead(value)
|
|
32
35
|
const endOfTask = this.isEndOfTask(value)
|
|
33
36
|
if (this.task && endOfTask) {
|
|
34
37
|
taskOrStreamDone = true
|
|
@@ -51,7 +54,19 @@ export class ReadStreamTaskParser {
|
|
|
51
54
|
}
|
|
52
55
|
|
|
53
56
|
async readLine() {
|
|
54
|
-
return this.
|
|
57
|
+
return this.lineIterator.next()
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
onLineRead() {
|
|
61
|
+
// Hook for parsers that need line-aware state.
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
shouldParseTaskLine() {
|
|
65
|
+
return true
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
getLineForTaskParsing(line) {
|
|
69
|
+
return line
|
|
55
70
|
}
|
|
56
71
|
|
|
57
72
|
isEndOfTask(line) {
|
|
@@ -76,9 +91,12 @@ export class ReadStreamTaskParser {
|
|
|
76
91
|
}
|
|
77
92
|
|
|
78
93
|
getTaskFromLine(line) {
|
|
94
|
+
if (!this.shouldParseTaskLine(line)) return
|
|
95
|
+
const originalLine = line
|
|
96
|
+
line = this.getLineForTaskParsing(line)
|
|
79
97
|
let task
|
|
80
98
|
this.taskParsers.find((taskParser) => {
|
|
81
|
-
task = taskParser.parseLine(line, this.lineNo, this.task)
|
|
99
|
+
task = taskParser.parseLine(line, this.lineNo, this.task, originalLine)
|
|
82
100
|
return task
|
|
83
101
|
})
|
|
84
102
|
return task
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { TaskParser } from "./TaskParser.js"
|
|
2
2
|
|
|
3
3
|
export class CheckStyleTaskParser extends TaskParser {
|
|
4
|
-
constructor() {
|
|
5
|
-
super()
|
|
4
|
+
constructor(config) {
|
|
5
|
+
super('CHECKBOX', config)
|
|
6
6
|
}
|
|
7
7
|
|
|
8
8
|
get pattern() {
|
|
@@ -20,6 +20,7 @@ export class CheckStyleTaskParser extends TaskParser {
|
|
|
20
20
|
return {
|
|
21
21
|
beforeText,
|
|
22
22
|
text,
|
|
23
|
+
list: checked ? this.config.getDoneList() : this.config.getDefaultList(),
|
|
23
24
|
line,
|
|
24
25
|
checked,
|
|
25
26
|
type: this.config.getNewCardSyntax(),
|
|
@@ -6,7 +6,7 @@ export class CodeStyleTaskParser extends TaskParser {
|
|
|
6
6
|
}
|
|
7
7
|
|
|
8
8
|
get pattern() {
|
|
9
|
-
return /^(.*?[ #]?)([
|
|
9
|
+
return /^(.*?[ #]?)([A-Z]+[A-Z-_]+?)(:)?(-?[\d.]+(?:e-?\d+)?)?[ \t]+(.+)$/gm
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
parse(lineContent, line, matchResult) {
|
|
@@ -8,7 +8,7 @@ export class HashStyleTaskParser extends TaskParser {
|
|
|
8
8
|
|
|
9
9
|
get pattern() {
|
|
10
10
|
const config = this.config
|
|
11
|
-
return getHashStyleRegex(config.tokenPrefix
|
|
11
|
+
return getHashStyleRegex(config.tokenPrefix)
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
parse(lineContent, line, matchResult) {
|
|
@@ -24,10 +24,15 @@ export class TaskParser {
|
|
|
24
24
|
throw new Error('Unimplemented')
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
parseLine(lineContent, line, task) {
|
|
27
|
+
parseLine(lineContent, line, task, originalLineContent = lineContent) {
|
|
28
28
|
const re = new RegExp(this.pattern)
|
|
29
29
|
const result = re.exec(lineContent)
|
|
30
|
-
|
|
30
|
+
if (!result) return
|
|
31
|
+
|
|
32
|
+
const originalResult = originalLineContent === lineContent
|
|
33
|
+
? result
|
|
34
|
+
: new RegExp(this.pattern).exec(originalLineContent.slice(result.index)) || result
|
|
35
|
+
const parseResult = this.parse(originalLineContent, line, originalResult, task)
|
|
31
36
|
|
|
32
37
|
if (parseResult && this.config.lists && !this.config.listExists(parseResult.list)) {
|
|
33
38
|
return
|
package/lib/file.js
CHANGED
|
@@ -852,7 +852,7 @@ export class File extends Emitter {
|
|
|
852
852
|
} else text = task.text
|
|
853
853
|
if (/[a-z]/.test(task.list)) task.type = Task.Types.HASHTAG
|
|
854
854
|
const tokenPrefix = task.type === Task.Types.HASHTAG ? config.tokenPrefix : ''
|
|
855
|
-
var taskContent = getRawTask({tokenPrefix, orderMeta: config.orderMeta, list: task.list, order: task.order, text, type: task.type})
|
|
855
|
+
var taskContent = getRawTask({tokenPrefix, orderMeta: config.orderMeta, hasColon: task.hasColon, list: task.list, order: task.order, text, type: task.type})
|
|
856
856
|
task.line = this.getLineNumber(index)
|
|
857
857
|
task.id = getTaskId(self.getPath(), task.line, task.text)
|
|
858
858
|
this.setContent(beforeContent + taskContent + afterContent)
|
|
@@ -1508,4 +1508,4 @@ export class File extends Emitter {
|
|
|
1508
1508
|
isResultInMarkdownCode (positions, index) {
|
|
1509
1509
|
return positions.some(pos => index >= pos.start && index < pos.end);
|
|
1510
1510
|
};
|
|
1511
|
-
}
|
|
1511
|
+
}
|
package/lib/migrate-config.js
CHANGED
|
@@ -149,13 +149,14 @@ export function buildMigrateConfig (repo, defaultSettings = _defaultSettings) {
|
|
|
149
149
|
config.settings.kudosProbability = 0.33
|
|
150
150
|
}
|
|
151
151
|
|
|
152
|
-
const
|
|
152
|
+
const defaultSettingsCopy = cloneDeep(defaultSettings)
|
|
153
|
+
const defaultCardsSettings = cloneDeep(defaultSettingsCopy.cards)
|
|
153
154
|
const cardsSettings = cloneDeep(config.settings.cards)
|
|
154
155
|
|
|
155
|
-
delete
|
|
156
|
+
delete defaultSettingsCopy.cards
|
|
156
157
|
delete config.settings.cards
|
|
157
158
|
|
|
158
|
-
config.settings = { ...
|
|
159
|
+
config.settings = { ...defaultSettingsCopy, ...config.settings }
|
|
159
160
|
config.settings.cards = {
|
|
160
161
|
...defaultCardsSettings,
|
|
161
162
|
...cardsSettings,
|
package/lib/repository.js
CHANGED
|
@@ -37,8 +37,140 @@ import { appContext } from './context/ApplicationContext.js'
|
|
|
37
37
|
import { computeChecksum } from './checksum.js'
|
|
38
38
|
import { getTasksToModify } from './get-tasks-to-modify.js'
|
|
39
39
|
import { logger } from './adapters/logger.js'
|
|
40
|
+
import { getFileParser } from './adapters/parsers/file/LocalFileParserFactory.js'
|
|
41
|
+
import { CodeStyleTaskParser } from './adapters/parsers/task/CodeStyleTaskParser.js'
|
|
40
42
|
const { ERRORS, ASYNC_LIMIT, DEFAULT_FILE_PATTERN} = constants
|
|
41
43
|
const DEFAULT_SORT = [{ asc: u => isNumber(u.order) ? u.order : Infinity }, { asc: u => u.text }]
|
|
44
|
+
const STREAM_FALLBACK_REASONS = {
|
|
45
|
+
BLOCK_COMMENT_WRITE_BACK_CONTEXT_UNSUPPORTED: 'block-comment-write-back-context-unsupported',
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
async function readStreamTasks(filePath, config) {
|
|
49
|
+
const parser = await getFileParser(filePath, config)
|
|
50
|
+
const tasks = []
|
|
51
|
+
let task
|
|
52
|
+
try {
|
|
53
|
+
while ((task = await parser.readTask())) {
|
|
54
|
+
tasks.push(task)
|
|
55
|
+
}
|
|
56
|
+
} finally {
|
|
57
|
+
parser.close()
|
|
58
|
+
}
|
|
59
|
+
return tasks
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function parseCodeStreamTask(streamTask, config) {
|
|
63
|
+
if (!streamTask.content) return
|
|
64
|
+
const firstTaskLine = streamTask.content
|
|
65
|
+
.split(/\r?\n/)
|
|
66
|
+
.find((line) => line.trim())
|
|
67
|
+
if (!firstTaskLine) return
|
|
68
|
+
|
|
69
|
+
const parser = new CodeStyleTaskParser({
|
|
70
|
+
...config,
|
|
71
|
+
includeList: (list) => config.includeList(list),
|
|
72
|
+
listExists: (list) => config.includeList(list),
|
|
73
|
+
})
|
|
74
|
+
const parsed = parser.parseLine(firstTaskLine, streamTask.line)
|
|
75
|
+
if (!parsed) return
|
|
76
|
+
|
|
77
|
+
parsed.lastLine = streamTask.lastLine
|
|
78
|
+
return parsed
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function toFileTask({ file, streamTask, config }) {
|
|
82
|
+
const parsedTask = streamTask.text
|
|
83
|
+
? streamTask
|
|
84
|
+
: parseCodeStreamTask(streamTask, config)
|
|
85
|
+
if (!parsedTask) return
|
|
86
|
+
|
|
87
|
+
const lineContent = file.getContentLines()[parsedTask.line - 1] || ''
|
|
88
|
+
const type = parsedTask.type || Task.Types.CODE
|
|
89
|
+
const taskStartOnLine = getTaskStartOnLine({ lineContent, parsedTask, type, config })
|
|
90
|
+
const linePos = file.getLinePos(parsedTask.line)
|
|
91
|
+
const tokenPrefix = type === Task.Types.HASHTAG ? config.tokenPrefix : ''
|
|
92
|
+
const rawTask = parsedTask.rawTask || getOriginalRawTask({
|
|
93
|
+
lineContent,
|
|
94
|
+
parsedTask,
|
|
95
|
+
taskStartOnLine,
|
|
96
|
+
type,
|
|
97
|
+
tokenPrefix,
|
|
98
|
+
config,
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
return file.extractTaskWithDescription({
|
|
102
|
+
taskStartOnLine,
|
|
103
|
+
rawTask,
|
|
104
|
+
config,
|
|
105
|
+
list: parsedTask.list,
|
|
106
|
+
text: parsedTask.text,
|
|
107
|
+
order: parsedTask.order,
|
|
108
|
+
line: parsedTask.line,
|
|
109
|
+
type,
|
|
110
|
+
hasColon: !!parsedTask.colon,
|
|
111
|
+
content: file.getContent().substring(linePos),
|
|
112
|
+
pos: linePos + taskStartOnLine,
|
|
113
|
+
})
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function getTaskStartOnLine({ lineContent, parsedTask, type, config }) {
|
|
117
|
+
if (parsedTask.beforeText) return parsedTask.beforeText.length
|
|
118
|
+
if (type === Task.Types.CODE) {
|
|
119
|
+
return Math.max(0, lineContent.indexOf(parsedTask.list))
|
|
120
|
+
}
|
|
121
|
+
if (type === Task.Types.HASHTAG) {
|
|
122
|
+
const taskTokenIndex = lineContent.indexOf(`${config.tokenPrefix}${parsedTask.list}`)
|
|
123
|
+
if (taskTokenIndex > -1) return taskTokenIndex
|
|
124
|
+
}
|
|
125
|
+
return 0
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function getOriginalRawTask({
|
|
129
|
+
lineContent,
|
|
130
|
+
parsedTask,
|
|
131
|
+
taskStartOnLine,
|
|
132
|
+
type,
|
|
133
|
+
tokenPrefix,
|
|
134
|
+
config,
|
|
135
|
+
}) {
|
|
136
|
+
if (type !== Task.Types.CODE) {
|
|
137
|
+
return lineContent.slice(taskStartOnLine)
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return getRawTask({
|
|
141
|
+
tokenPrefix,
|
|
142
|
+
orderMeta: config.orderMeta,
|
|
143
|
+
beforeText: parsedTask.beforeText,
|
|
144
|
+
hasColon: !!parsedTask.colon,
|
|
145
|
+
list: parsedTask.list,
|
|
146
|
+
order: parsedTask.order,
|
|
147
|
+
text: parsedTask.text,
|
|
148
|
+
type,
|
|
149
|
+
})
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function attachStreamTasks({ file, streamTasks, config }) {
|
|
153
|
+
file.tasks = []
|
|
154
|
+
streamTasks.forEach((streamTask) => {
|
|
155
|
+
const task = toFileTask({ file, streamTask, config })
|
|
156
|
+
if (!task) return
|
|
157
|
+
file.addTask(task)
|
|
158
|
+
file.emit('task.found', task)
|
|
159
|
+
})
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function getStreamWriteBackFallbackReason(streamTasks) {
|
|
163
|
+
if (streamTasks.some((streamTask) => streamTask.inBlockComment)) {
|
|
164
|
+
return STREAM_FALLBACK_REASONS.BLOCK_COMMENT_WRITE_BACK_CONTEXT_UNSUPPORTED
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function emitParserDiagnostic(repo, file, diagnostic) {
|
|
169
|
+
repo.emit('file.parser', {
|
|
170
|
+
path: file.path,
|
|
171
|
+
...diagnostic,
|
|
172
|
+
})
|
|
173
|
+
}
|
|
42
174
|
|
|
43
175
|
function getTasksByList (
|
|
44
176
|
repo,
|
|
@@ -768,41 +900,38 @@ export class Repository extends Emitter {
|
|
|
768
900
|
|
|
769
901
|
file.on('task.found', this.taskFoundListener)
|
|
770
902
|
file.on('task.modified', this.taskModifiedListener)
|
|
771
|
-
const fileContent = file.content
|
|
772
|
-
|
|
773
|
-
logger.debug(`[INSTRUMENT] About to call extractAndTransformTasks, content length: ${fileContent?.length || 0}`)
|
|
774
|
-
file.extractAndTransformTasks(this.getConfig())
|
|
775
903
|
|
|
776
|
-
const
|
|
777
|
-
|
|
904
|
+
const streamTasks = await readStreamTasks(this.getFullPath(file), this.getConfig())
|
|
905
|
+
const fallbackReason = getStreamWriteBackFallbackReason(streamTasks)
|
|
906
|
+
if (fallbackReason) {
|
|
907
|
+
file.extractAndTransformTasks(this.getConfig())
|
|
908
|
+
emitParserDiagnostic(this, file, {
|
|
909
|
+
mode: 'legacy-fallback',
|
|
910
|
+
reason: fallbackReason,
|
|
911
|
+
})
|
|
778
912
|
|
|
779
|
-
if (!file.isModified() || fileContent === file.content) {
|
|
780
913
|
this.resetFile(file)
|
|
781
|
-
const
|
|
782
|
-
logger.debug(`[INSTRUMENT] extractTasks END (
|
|
914
|
+
const fallbackTotalTime = Date.now() - extractStartTime
|
|
915
|
+
logger.debug(`[INSTRUMENT] extractTasks END (legacy-fallback) - total ${fallbackTotalTime}ms`)
|
|
783
916
|
return file
|
|
784
917
|
}
|
|
785
918
|
|
|
786
|
-
|
|
787
|
-
file
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
919
|
+
const fileContent = file.content
|
|
920
|
+
attachStreamTasks({ file, streamTasks, config: this.getConfig() })
|
|
921
|
+
file.transformTasks(this.getConfig())
|
|
922
|
+
emitParserDiagnostic(this, file, {
|
|
923
|
+
mode: 'stream',
|
|
924
|
+
})
|
|
791
925
|
|
|
792
|
-
if (file.
|
|
793
|
-
logger.debug(
|
|
926
|
+
if (file.isModified() && fileContent !== file.content) {
|
|
927
|
+
logger.debug('[INSTRUMENT] About to writeFile (stream re-extract flow)')
|
|
794
928
|
await this.writeFile(file)
|
|
795
|
-
|
|
929
|
+
file.extractTasks(this.getConfig())
|
|
796
930
|
}
|
|
797
931
|
|
|
798
932
|
this.resetFile(file)
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
if (totalTime > 1000) {
|
|
802
|
-
logger.warn(`[INSTRUMENT] ⚠️ SLOW extractTasks: ${file.path} took ${totalTime}ms`)
|
|
803
|
-
}
|
|
804
|
-
logger.debug(`[INSTRUMENT] extractTasks END - total ${totalTime}ms`)
|
|
805
|
-
|
|
933
|
+
const streamTotalTime = Date.now() - extractStartTime
|
|
934
|
+
logger.debug(`[INSTRUMENT] extractTasks END (stream) - total ${streamTotalTime}ms`)
|
|
806
935
|
return file
|
|
807
936
|
}
|
|
808
937
|
|
|
@@ -1,5 +1,31 @@
|
|
|
1
1
|
import { pathToFileURL } from 'node:url'
|
|
2
2
|
|
|
3
|
+
const WINDOWS_DRIVE_PATH = /^[a-zA-Z]:[\\/]/
|
|
4
|
+
const WINDOWS_UNC_PATH = /^\\\\[^\\]+\\[^\\]+/
|
|
5
|
+
|
|
3
6
|
export function toFileImportSpecifier(filePath) {
|
|
7
|
+
const value = String(filePath)
|
|
8
|
+
if (/^(file|data|node):/i.test(value)) return value
|
|
9
|
+
if (WINDOWS_DRIVE_PATH.test(value)) return windowsDrivePathToFileURL(value)
|
|
10
|
+
if (WINDOWS_UNC_PATH.test(value)) return windowsUncPathToFileURL(value)
|
|
11
|
+
|
|
4
12
|
return pathToFileURL(filePath).href
|
|
5
13
|
}
|
|
14
|
+
|
|
15
|
+
function windowsDrivePathToFileURL(filePath) {
|
|
16
|
+
const normalizedPath = filePath.replace(/\\/g, '/')
|
|
17
|
+
return `file:///${encodePathSegments(normalizedPath)}`
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function windowsUncPathToFileURL(filePath) {
|
|
21
|
+
const normalizedPath = filePath.replace(/\\/g, '/').replace(/^\/+/, '')
|
|
22
|
+
const [host, ...pathSegments] = normalizedPath.split('/')
|
|
23
|
+
return `file://${host}/${pathSegments.map(encodeURIComponent).join('/')}`
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function encodePathSegments(filePath) {
|
|
27
|
+
return filePath
|
|
28
|
+
.split('/')
|
|
29
|
+
.map(segment => /^[a-zA-Z]:$/.test(segment) ? segment : encodeURIComponent(segment))
|
|
30
|
+
.join('/')
|
|
31
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "imdone-core",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.0",
|
|
4
4
|
"description": "imdone-core",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -10,10 +10,10 @@
|
|
|
10
10
|
"types": "types/index.d.ts",
|
|
11
11
|
"type": "module",
|
|
12
12
|
"bin": {
|
|
13
|
-
"imdone-
|
|
13
|
+
"imdone-core": "lib/cli.js"
|
|
14
14
|
},
|
|
15
15
|
"scripts": {
|
|
16
|
-
"prepublishOnly": "
|
|
16
|
+
"prepublishOnly": "node scripts/prepublish-only.js",
|
|
17
17
|
"build": "npm run pre-commit && npm run coverage",
|
|
18
18
|
"build:docs": "doctoc --github --notitle README.md",
|
|
19
19
|
"build:docs:index": "node scripts/index-markdown.js",
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process'
|
|
2
|
+
|
|
3
|
+
const TRUE_VALUES = new Set(['1', 'true', 'yes', 'on'])
|
|
4
|
+
|
|
5
|
+
function isTruthy(value) {
|
|
6
|
+
return TRUE_VALUES.has(String(value || '').toLowerCase())
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function shouldSkipPrepublishOnly() {
|
|
10
|
+
return isTruthy(process.env.NO_PREPUBLISH)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
if (shouldSkipPrepublishOnly()) {
|
|
14
|
+
console.log('Skipping prepublishOnly because skip prepublish override is enabled.')
|
|
15
|
+
process.exit(0)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const build = spawn('npm', ['run', 'build'], {
|
|
19
|
+
stdio: 'inherit',
|
|
20
|
+
shell: process.platform === 'win32',
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
build.on('exit', (code) => {
|
|
24
|
+
process.exit(code ?? 1)
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
build.on('error', (error) => {
|
|
28
|
+
console.error(`Unable to run prepublishOnly build: ${error.message}`)
|
|
29
|
+
process.exit(1)
|
|
30
|
+
})
|
|
@@ -3,11 +3,9 @@ export class ReadStreamCodeParser extends ReadStreamTaskParser {
|
|
|
3
3
|
lists: any;
|
|
4
4
|
filePath: any;
|
|
5
5
|
lang: any;
|
|
6
|
-
taskParsers: CodeStyleTaskParser[];
|
|
7
6
|
init(): Promise<void>;
|
|
8
7
|
cards: any[] | undefined;
|
|
9
|
-
parseCards(
|
|
10
|
-
parseComments(
|
|
8
|
+
parseCards(tokens?: string[]): Promise<any[]>;
|
|
9
|
+
parseComments(): Promise<{}>;
|
|
11
10
|
}
|
|
12
11
|
import { ReadStreamTaskParser } from './ReadStreamTaskParser.js';
|
|
13
|
-
import { CodeStyleTaskParser } from '../task/CodeStyleTaskParser.js';
|
|
@@ -1,6 +1,17 @@
|
|
|
1
1
|
export class ReadStreamMarkdownParser extends ReadStreamTaskParser {
|
|
2
2
|
constructor(readStream: any, config: any);
|
|
3
|
+
frontmatterLines: any[];
|
|
4
|
+
collectingFrontmatter: boolean;
|
|
5
|
+
frontmatterClosed: boolean;
|
|
6
|
+
ignoredByFrontmatter: boolean;
|
|
7
|
+
currentLineIsFrontmatter: boolean;
|
|
8
|
+
currentLineIsCodeFence: boolean;
|
|
9
|
+
inCodeFence: boolean;
|
|
3
10
|
taskParsers: (HashStyleTaskParser | MarkdownStyleTaskParser)[];
|
|
11
|
+
onLineRead(line: any): void;
|
|
12
|
+
updateFrontmatterState(line: any): void;
|
|
13
|
+
updateIgnoredByFrontmatter(): void;
|
|
14
|
+
updateCodeFenceState(line: any): void;
|
|
4
15
|
}
|
|
5
16
|
import { ReadStreamTaskParser } from './ReadStreamTaskParser.js';
|
|
6
17
|
import { HashStyleTaskParser } from '../task/HashStyleTaskParser.js';
|
|
@@ -7,10 +7,14 @@ export class ReadStreamTaskParser {
|
|
|
7
7
|
lineNo: number;
|
|
8
8
|
blankLines: number;
|
|
9
9
|
readInterface: ReadLine.Interface;
|
|
10
|
+
lineIterator: NodeJS.AsyncIterator<string, any, any>;
|
|
10
11
|
readTask(): Promise<any>;
|
|
12
|
+
nextTask: any;
|
|
11
13
|
readLine(): Promise<IteratorResult<string, any>>;
|
|
14
|
+
onLineRead(): void;
|
|
15
|
+
shouldParseTaskLine(): boolean;
|
|
16
|
+
getLineForTaskParsing(line: any): any;
|
|
12
17
|
isEndOfTask(line: any): boolean;
|
|
13
|
-
nextTask: any;
|
|
14
18
|
getTaskFromLine(line: any): undefined;
|
|
15
19
|
addLineToTask(line: any): void;
|
|
16
20
|
trimLinesToEndTask(): void;
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
export class CheckStyleTaskParser extends TaskParser {
|
|
2
|
-
constructor();
|
|
2
|
+
constructor(config: any);
|
|
3
3
|
get pattern(): RegExp;
|
|
4
4
|
parse(lineContent: any, line: any, matchResult: any, task: any): {
|
|
5
5
|
beforeText: any;
|
|
6
6
|
text: any;
|
|
7
|
+
list: any;
|
|
7
8
|
line: any;
|
|
8
9
|
checked: any;
|
|
9
10
|
type: any;
|