imdone-core 2.0.0 → 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/ISSUE_TEMPLATE/bug_report.md +37 -0
- package/.github/workflows/ci.yml +24 -0
- package/.imdoneignore +13 -0
- package/.mocharc.json +10 -0
- package/.prettierrc +6 -0
- package/CHANGELOG.md +160 -0
- package/_index.md +7 -0
- package/_navbar.md +1 -0
- package/build.js +57 -0
- package/esm-migration.md +446 -0
- package/index.html +184 -0
- package/lib/FileProjectContext.js +13 -0
- package/lib/ProjectContext.js +43 -0
- package/lib/adapters/date-time.js +15 -0
- package/lib/adapters/environment.js +3 -0
- package/lib/adapters/file-gateway.js +154 -0
- package/lib/adapters/git-download.js +55 -0
- package/lib/adapters/index.js +9 -0
- package/lib/adapters/logger.js +136 -0
- package/lib/adapters/markdown.js +180 -0
- package/lib/adapters/parsers/DateLanguageParser.js +12 -0
- package/lib/adapters/parsers/content-transformer.js +116 -0
- package/lib/adapters/parsers/file/LocalFileParserFactory.js +36 -0
- package/lib/adapters/parsers/file/ReadStreamCodeParser.js +126 -0
- package/lib/adapters/parsers/file/ReadStreamMarkdownParser.js +17 -0
- package/lib/adapters/parsers/file/ReadStreamTaskParser.js +106 -0
- package/lib/adapters/parsers/file/index.js +4 -0
- package/lib/adapters/parsers/function-parser.js +25 -0
- package/lib/adapters/parsers/index.js +5 -0
- package/lib/adapters/parsers/task/CardContentParser.js +367 -0
- package/lib/adapters/parsers/task/CheckStyleTaskParser.js +28 -0
- package/lib/adapters/parsers/task/CodeStyleTaskParser.js +24 -0
- package/lib/adapters/parsers/task/HashStyleTaskParser.js +27 -0
- package/lib/adapters/parsers/task/MarkdownStyleTaskParser.js +24 -0
- package/lib/adapters/parsers/task/TaskParser.js +38 -0
- package/lib/adapters/parsers/task/index.js +6 -0
- package/lib/adapters/storage/config.js +44 -0
- package/lib/adapters/storage/index.js +2 -0
- package/lib/adapters/storage/tags.js +29 -0
- package/lib/adapters/yaml.js +9 -0
- package/lib/card.js +299 -0
- package/lib/checksum.js +22 -0
- package/lib/config.js +249 -0
- package/lib/constants.js +68 -0
- package/lib/context/ApplicationContext.js +35 -0
- package/lib/context/index.js +1 -0
- package/lib/default-settings.js +37 -0
- package/lib/domain/entities/View.js +23 -0
- package/lib/domain/entities/index.js +1 -0
- package/lib/domain/index.js +2 -0
- package/lib/domain/usecases/GetViewsUsecase.js +44 -0
- package/lib/domain/usecases/SaveViewUsecase.js +51 -0
- package/lib/domain/usecases/index.js +2 -0
- package/lib/file.js +1391 -0
- package/lib/get-tasks-to-modify.js +117 -0
- package/lib/languages.js +113 -0
- package/lib/list.js +56 -0
- package/lib/migrate-config.js +165 -0
- package/lib/mixins/index.js +2 -0
- package/lib/mixins/repo-fs-store.js +359 -0
- package/lib/mixins/repo-watched-fs-store.js +206 -0
- package/lib/plugins/archive-plugin.js +72 -0
- package/lib/plugins/default-board-actions-plugin.js +56 -0
- package/lib/plugins/default-board-properties-plugin.js +101 -0
- package/lib/plugins/default-plugins.js +7 -0
- package/lib/plugins/epic-plugin.js +177 -0
- package/lib/plugins/extension-plugin.js +94 -0
- package/lib/plugins/index.js +9 -0
- package/lib/plugins/persist-tags-plugin.js +14 -0
- package/lib/plugins/plugin-manager.js +458 -0
- package/lib/plugins/plugin-registry.js +57 -0
- package/lib/project-factory.js +42 -0
- package/lib/project.js +864 -0
- package/lib/repository.js +1514 -0
- package/lib/task.js +780 -0
- package/lib/tools.js +176 -0
- package/lib/usecases/actions.js +32 -0
- package/lib/usecases/get-imdone-url.js +6 -0
- package/lib/usecases/get-project-tags.js +7 -0
- package/lib/usecases/get-tasks-in-file.js +26 -0
- package/lib/usecases/index.js +4 -0
- package/package.json +2 -6
- package/scripts/delete-markdown-indexes.js +87 -0
- package/scripts/generate-index.js +35 -0
- package/scripts/index-markdown.js +55 -0
- 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
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
import eol from 'eol'
|
|
2
|
+
import XRegExp from 'xregexp'
|
|
3
|
+
|
|
4
|
+
export const FILE_TYPES = {
|
|
5
|
+
MARKDOWN: 'markdown',
|
|
6
|
+
CODE: 'code',
|
|
7
|
+
}
|
|
8
|
+
export const TASK_TYPES = {
|
|
9
|
+
CODE: 'CODE',
|
|
10
|
+
HASHTAG: 'HASHTAG',
|
|
11
|
+
MARKDOWN: 'MARKDOWN',
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const DEFAULT_TOKEN_PREFIX = '#'
|
|
15
|
+
const START_TAG = '<card>'
|
|
16
|
+
const END_TAG = '</card>'
|
|
17
|
+
const CODE_STYLE_PATTERN = '([A-Z]+[A-Z-_]+?)((:)(-?[\\d.]+(?:e-?\\d+)?)?)?[ \\t]+(.+)$'
|
|
18
|
+
|
|
19
|
+
export const LIST_NAME_PATTERN = '[\\p{L}0-9-_]{2,}' // [a-zA-Z-_]+?
|
|
20
|
+
export const LINK_STYLE_REGEX = new XRegExp(
|
|
21
|
+
`(\\[.*\\]\\s?)?(\\[(.+)\\]\\(#(${LIST_NAME_PATTERN})(:)(-?[\\d.]+(?:e-?\\d+)?)?\\))`,
|
|
22
|
+
'gm'
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
export const CHECK_REGEX = /^(\s*- )\[([x ])\]/
|
|
26
|
+
|
|
27
|
+
export function getHashStyleRegex(tokenPrefix = DEFAULT_TOKEN_PREFIX, orderMeta = false) {
|
|
28
|
+
return orderMeta ?
|
|
29
|
+
new XRegExp(
|
|
30
|
+
`${tokenPrefix}(${LIST_NAME_PATTERN})[ \\t]+(.+)$`, 'gm'
|
|
31
|
+
) :
|
|
32
|
+
new XRegExp(
|
|
33
|
+
`${tokenPrefix}(${LIST_NAME_PATTERN})(:(-?[\\d.]+(?:e-?\\d+)?)?)?[ \\t]+(.+)$`,
|
|
34
|
+
'gm'
|
|
35
|
+
)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function getCheckedData(content) {
|
|
39
|
+
const taskRegex = new RegExp(CHECK_REGEX)
|
|
40
|
+
const result = taskRegex.exec(content)
|
|
41
|
+
return result
|
|
42
|
+
? {
|
|
43
|
+
pad: result[1].length,
|
|
44
|
+
checked: result[2].trim() !== '',
|
|
45
|
+
}
|
|
46
|
+
: null
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function getContentLines(content) {
|
|
50
|
+
let foundContent = false
|
|
51
|
+
return eol.split(content).filter((line) => {
|
|
52
|
+
const hasContent = line.trim()
|
|
53
|
+
if (!foundContent && hasContent) foundContent = true
|
|
54
|
+
return foundContent || hasContent
|
|
55
|
+
})
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function isCustomCardTerminator(config, line) {
|
|
59
|
+
return config.customCardTerminator
|
|
60
|
+
&& config.customCardTerminator.trim()
|
|
61
|
+
&& line
|
|
62
|
+
&& line.trim() === config.customCardTerminator
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function isCheckBoxTask (config, line, beforeText) {
|
|
66
|
+
if (!config.isAddCheckBoxTasks()) return
|
|
67
|
+
|
|
68
|
+
const beforeTextCheckData = getCheckedData(beforeText)
|
|
69
|
+
if (!beforeTextCheckData) return
|
|
70
|
+
|
|
71
|
+
const lineCheckData = getCheckedData(line)
|
|
72
|
+
if (!lineCheckData) return
|
|
73
|
+
|
|
74
|
+
return lineCheckData.pad <= beforeTextCheckData.pad
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function hasTaskInText(config, text, isCodeFile) {
|
|
78
|
+
const hashStyleRegex = new XRegExp(getHashStyleRegex(config.tokenPrefix));
|
|
79
|
+
const linkStyleRegex = new XRegExp(LINK_STYLE_REGEX);
|
|
80
|
+
|
|
81
|
+
const inlineCodeRe = /`[^`]*`/g;
|
|
82
|
+
|
|
83
|
+
// Function to check if a match is within inline code
|
|
84
|
+
function isWithinInlineCode(index) {
|
|
85
|
+
let match;
|
|
86
|
+
while ((match = inlineCodeRe.exec(text)) !== null) {
|
|
87
|
+
const isInCode = index >= match.index && index < match.index + match[0].length
|
|
88
|
+
if (isInCode) return true;
|
|
89
|
+
}
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Check for code style tasks
|
|
94
|
+
if (isCodeFile && hasCodeStyleTask(config, text)) {
|
|
95
|
+
return true;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Check for hash style tasks
|
|
99
|
+
let result;
|
|
100
|
+
if ((result = hashStyleRegex.exec(text)) !== null && !isWithinInlineCode(result.index)) {
|
|
101
|
+
return !!config.lists.find((list) => text.includes(`${config.tokenPrefix}${list.name}`));
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Check for link style tasks
|
|
105
|
+
if ((result = linkStyleRegex.exec(text)) !== null && !isWithinInlineCode(result.index)) {
|
|
106
|
+
return !!config.lists.find((list) => text.includes(`${config.tokenPrefix}${list.name}`));
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export function isBeforeTextMarkdownList(beforeText) {
|
|
113
|
+
return /^\s*(\*|-|- \[[x| ]\]|\d+\.|[a-zA-Z]\.)\s$/.test(beforeText)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function isMarkdownListItem(line) {
|
|
117
|
+
return /^\s*(\*|-|- \[[x| ]\]|\d+\.|[a-zA-Z]\.)\s/.test(line)
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export function padDescription(description = [], beforeText = '') {
|
|
121
|
+
if (!isBeforeTextMarkdownList(beforeText)) return description
|
|
122
|
+
return description.map((line) => {
|
|
123
|
+
return line.padStart(line.length + beforeText.length)
|
|
124
|
+
})
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function isLineOutsideMarkdownList(line, beforeText) {
|
|
128
|
+
return isBeforeTextMarkdownList(beforeText) &&
|
|
129
|
+
isMarkdownListItem(line) &&
|
|
130
|
+
line.search(/\S/) <= beforeText.search(/\S/)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function hasCodeStyleTask(config, text) {
|
|
134
|
+
const codeStylePatternRe = new RegExp(CODE_STYLE_PATTERN);
|
|
135
|
+
let result = codeStylePatternRe.exec(text);
|
|
136
|
+
|
|
137
|
+
if (!result) return false;
|
|
138
|
+
|
|
139
|
+
// Check if the match is within inline code
|
|
140
|
+
const inlineCodeRe = /`[^`]*`/g;
|
|
141
|
+
let match;
|
|
142
|
+
while ((match = inlineCodeRe.exec(text)) !== null) {
|
|
143
|
+
if (result.index >= match.index && result.index < match.index + match[0].length) {
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return config.includeList(result[1]);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function getCardTagsTaskContent ({
|
|
152
|
+
content,
|
|
153
|
+
fileType
|
|
154
|
+
}) {
|
|
155
|
+
const isCodeFile = fileType === FILE_TYPES.CODE
|
|
156
|
+
if (isCodeFile) return
|
|
157
|
+
|
|
158
|
+
const isMarkDownFile = fileType === FILE_TYPES.MARKDOWN
|
|
159
|
+
let lines = getContentLines(content)
|
|
160
|
+
const hasCardStartTag =
|
|
161
|
+
isMarkDownFile && lines.length > 1 && lines[1].trim() === START_TAG
|
|
162
|
+
if (!hasCardStartTag) return
|
|
163
|
+
|
|
164
|
+
let openBlockCommentTokens = 0
|
|
165
|
+
let closeBlockCommentTokens = 0
|
|
166
|
+
let hasCardEndTag = false
|
|
167
|
+
const rawTaskContentLines = []
|
|
168
|
+
const taskContentLines = []
|
|
169
|
+
for (let i = 1; i < lines.length; i++) {
|
|
170
|
+
let line = lines[i]
|
|
171
|
+
// Check for matching block comments in markdown files
|
|
172
|
+
if (isMarkDownFile && line.trim().indexOf('<!--') > -1)
|
|
173
|
+
openBlockCommentTokens++
|
|
174
|
+
if (isMarkDownFile && line.trim().indexOf('-->') > -1)
|
|
175
|
+
closeBlockCommentTokens++
|
|
176
|
+
|
|
177
|
+
rawTaskContentLines.push(line)
|
|
178
|
+
|
|
179
|
+
if (line.trim() === START_TAG) continue
|
|
180
|
+
if (line.trim() === END_TAG) {
|
|
181
|
+
hasCardEndTag = true
|
|
182
|
+
break
|
|
183
|
+
}
|
|
184
|
+
taskContentLines.push(line)
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Remove extra block comment tokens
|
|
188
|
+
if (
|
|
189
|
+
isMarkDownFile &&
|
|
190
|
+
rawTaskContentLines.length &&
|
|
191
|
+
rawTaskContentLines[rawTaskContentLines.length - 1].trim() === '-->' &&
|
|
192
|
+
openBlockCommentTokens !== closeBlockCommentTokens
|
|
193
|
+
)
|
|
194
|
+
rawTaskContentLines.pop()
|
|
195
|
+
|
|
196
|
+
const isWrappedWithCardTag = hasCardStartTag && hasCardEndTag
|
|
197
|
+
|
|
198
|
+
return {
|
|
199
|
+
rawTaskContentLines,
|
|
200
|
+
taskContentLines,
|
|
201
|
+
isWrappedWithCardTag,
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// This finds the end of task
|
|
206
|
+
function getCodeFileTaskContent ({
|
|
207
|
+
config,
|
|
208
|
+
content,
|
|
209
|
+
inBlockComment,
|
|
210
|
+
fileType,
|
|
211
|
+
lang
|
|
212
|
+
}) {
|
|
213
|
+
const isCodeFile = fileType === FILE_TYPES.CODE
|
|
214
|
+
if (!isCodeFile) return
|
|
215
|
+
|
|
216
|
+
const rawTaskContentLines = []
|
|
217
|
+
let lines = getContentLines(content)
|
|
218
|
+
for (let i = 1; i < lines.length; i++) {
|
|
219
|
+
let line = lines[i]
|
|
220
|
+
// Another task ends a task
|
|
221
|
+
if (hasTaskInText(config, line, isCodeFile)) break
|
|
222
|
+
if (
|
|
223
|
+
!inBlockComment &&
|
|
224
|
+
(line.indexOf(lang.symbol) < 0 ||
|
|
225
|
+
line.trim().indexOf(lang.symbol) > 0 ||
|
|
226
|
+
line.trim() === lang.symbol)
|
|
227
|
+
)
|
|
228
|
+
break
|
|
229
|
+
if (lang.block && line.trim() === lang.block.end)
|
|
230
|
+
break
|
|
231
|
+
if (lang.block && line.trim() === lang.block.ignore)
|
|
232
|
+
break
|
|
233
|
+
if (line && lang && lang.block) line = line.replace(lang.block.end, '')
|
|
234
|
+
|
|
235
|
+
rawTaskContentLines.push(line)
|
|
236
|
+
}
|
|
237
|
+
return {
|
|
238
|
+
rawTaskContentLines,
|
|
239
|
+
taskContentLines: rawTaskContentLines,
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
function getTextFileTaskContent ({
|
|
244
|
+
config,
|
|
245
|
+
content,
|
|
246
|
+
beforeText,
|
|
247
|
+
fileType,
|
|
248
|
+
}) {
|
|
249
|
+
const isCodeFile = fileType === FILE_TYPES.CODE
|
|
250
|
+
if (isCodeFile) return
|
|
251
|
+
|
|
252
|
+
let lines = getContentLines(content)
|
|
253
|
+
const hasCardStartTag = lines.length > 1 && lines[1].trim() === START_TAG
|
|
254
|
+
if (hasCardStartTag) return
|
|
255
|
+
|
|
256
|
+
const isMarkDownFile = fileType === FILE_TYPES.MARKDOWN
|
|
257
|
+
const isTaskInList = isMarkDownFile && isBeforeTextMarkdownList(beforeText)
|
|
258
|
+
let openBlockCommentTokens = 0
|
|
259
|
+
let closeBlockCommentTokens = 0
|
|
260
|
+
let lastLineBlank = false
|
|
261
|
+
let endsWithDoubleBlank = false
|
|
262
|
+
let trailingBlankLines = 0
|
|
263
|
+
const rawTaskContentLines = []
|
|
264
|
+
const taskContentLines = []
|
|
265
|
+
|
|
266
|
+
let inCodeBlock = false
|
|
267
|
+
|
|
268
|
+
for (let i = 1; i < lines.length; i++) {
|
|
269
|
+
let line = lines[i]
|
|
270
|
+
|
|
271
|
+
// Check for markdown code blocks
|
|
272
|
+
if (isMarkDownFile && line.trim().startsWith('```')) {
|
|
273
|
+
inCodeBlock = !inCodeBlock
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// Only break if the task is not in a markdown code block or code span
|
|
277
|
+
if (!inCodeBlock && hasTaskInText(config, line)) break
|
|
278
|
+
if (isCheckBoxTask(config, line, beforeText)) break
|
|
279
|
+
if (isTaskInList && isLineOutsideMarkdownList(line, beforeText)) break
|
|
280
|
+
if (isCustomCardTerminator(config, line)) break
|
|
281
|
+
|
|
282
|
+
rawTaskContentLines.push(line)
|
|
283
|
+
taskContentLines.push(`${line}`)
|
|
284
|
+
|
|
285
|
+
// Check for matching block comments in markdown files
|
|
286
|
+
if (isMarkDownFile && line.trim().indexOf('<!--') > -1)
|
|
287
|
+
openBlockCommentTokens++
|
|
288
|
+
if (isMarkDownFile && line.trim().indexOf('-->') > -1)
|
|
289
|
+
closeBlockCommentTokens++
|
|
290
|
+
|
|
291
|
+
const thisLineBlank = line.trim() === ''
|
|
292
|
+
|
|
293
|
+
if (thisLineBlank && lastLineBlank) {
|
|
294
|
+
endsWithDoubleBlank = true
|
|
295
|
+
break
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
lastLineBlank = thisLineBlank
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
if (endsWithDoubleBlank) trailingBlankLines = 2
|
|
302
|
+
else if (lastLineBlank) trailingBlankLines = 1
|
|
303
|
+
|
|
304
|
+
// Remove extra block comment tokens
|
|
305
|
+
if (
|
|
306
|
+
isMarkDownFile &&
|
|
307
|
+
rawTaskContentLines.length &&
|
|
308
|
+
rawTaskContentLines[rawTaskContentLines.length - 1].trim() === '-->' &&
|
|
309
|
+
openBlockCommentTokens !== closeBlockCommentTokens
|
|
310
|
+
) {
|
|
311
|
+
rawTaskContentLines.pop()
|
|
312
|
+
taskContentLines.pop()
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
return {
|
|
316
|
+
rawTaskContentLines,
|
|
317
|
+
taskContentLines: trailingBlankLines
|
|
318
|
+
? taskContentLines.slice(0, -trailingBlankLines)
|
|
319
|
+
: taskContentLines,
|
|
320
|
+
trailingBlankLines,
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
export function getTaskContent ({
|
|
325
|
+
config,
|
|
326
|
+
content,
|
|
327
|
+
inBlockComment,
|
|
328
|
+
beforeText,
|
|
329
|
+
fileType,
|
|
330
|
+
lang
|
|
331
|
+
}) {
|
|
332
|
+
return getCardTagsTaskContent({ content, fileType }) ||
|
|
333
|
+
getCodeFileTaskContent({ config, content, inBlockComment, fileType, lang }) ||
|
|
334
|
+
getTextFileTaskContent({ config, content, beforeText, fileType })
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
export function getRawTask ({
|
|
338
|
+
tokenPrefix = DEFAULT_TOKEN_PREFIX,
|
|
339
|
+
orderMeta = true,
|
|
340
|
+
beforeText = '',
|
|
341
|
+
hasColon = false,
|
|
342
|
+
list,
|
|
343
|
+
order = '',
|
|
344
|
+
text,
|
|
345
|
+
type = TASK_TYPES.HASHTAG
|
|
346
|
+
}) {
|
|
347
|
+
if (type === TASK_TYPES.MARKDOWN) {
|
|
348
|
+
return `${beforeText || ''}[${text}](${tokenPrefix}${list}:${
|
|
349
|
+
orderMeta ? '' : order
|
|
350
|
+
})`
|
|
351
|
+
} else {
|
|
352
|
+
const colon = hasColon || (isNumber(order) && !orderMeta) ? ':' : '';
|
|
353
|
+
return `${beforeText || ''}${tokenPrefix}${list}${colon}${
|
|
354
|
+
orderMeta ? '' : order
|
|
355
|
+
} ${text}`
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
export function isNumber(value) {
|
|
360
|
+
return !isNaN(value) && isFinite(Number(value));
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
export function toNumber(value) {
|
|
364
|
+
if (value == null || value == undefined) return undefined; // Convert null or undefined to undefined
|
|
365
|
+
const num = Number(value);
|
|
366
|
+
return isNaN(num) ? undefined : num; // Return 0 if conversion fails, otherwise return the number
|
|
367
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { TaskParser } from "./TaskParser.js"
|
|
2
|
+
|
|
3
|
+
export class CheckStyleTaskParser extends TaskParser {
|
|
4
|
+
constructor() {
|
|
5
|
+
super()
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
get pattern() {
|
|
9
|
+
return /^(\s*- \[([x ])\]\s)(.+$)/gm
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
parse(lineContent, line, matchResult, task) {
|
|
13
|
+
let [match, beforeText, checked, text] = matchResult
|
|
14
|
+
if (
|
|
15
|
+
(task && !task.beforeText) ||
|
|
16
|
+
(task && task.beforeText.length !== beforeText.length)
|
|
17
|
+
)
|
|
18
|
+
return
|
|
19
|
+
checked = checked.trim() === 'x'
|
|
20
|
+
return {
|
|
21
|
+
beforeText,
|
|
22
|
+
text,
|
|
23
|
+
line,
|
|
24
|
+
checked,
|
|
25
|
+
type: this.config.getNewCardSyntax(),
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { TaskParser } from './TaskParser.js'
|
|
2
|
+
|
|
3
|
+
export class CodeStyleTaskParser extends TaskParser {
|
|
4
|
+
constructor(config) {
|
|
5
|
+
super('CODE', config)
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
get pattern() {
|
|
9
|
+
return /^(.*?[ #]?)([a-zA-Z-_]+?)(:)(-?[\d.]+(?:e-?\d+)?)?[ \t]+(.+)$/gm
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
parse(lineContent, line, matchResult) {
|
|
13
|
+
const [match, beforeText, list, colon, order, text] = matchResult
|
|
14
|
+
return {
|
|
15
|
+
beforeText,
|
|
16
|
+
text,
|
|
17
|
+
order,
|
|
18
|
+
list,
|
|
19
|
+
line,
|
|
20
|
+
colon,
|
|
21
|
+
type: this.type,
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { TaskParser } from './TaskParser.js'
|
|
2
|
+
import { getHashStyleRegex } from './CardContentParser.js'
|
|
3
|
+
|
|
4
|
+
export class HashStyleTaskParser extends TaskParser {
|
|
5
|
+
constructor(config) {
|
|
6
|
+
super('HASHTAG', config)
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
get pattern() {
|
|
10
|
+
const config = this.config
|
|
11
|
+
return getHashStyleRegex(config.tokenPrefix, config.orderMeta)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
parse(lineContent, line, matchResult) {
|
|
15
|
+
const [rawTask, list, orderGroup, order, text] = matchResult
|
|
16
|
+
|
|
17
|
+
return {
|
|
18
|
+
// beforeText,
|
|
19
|
+
text,
|
|
20
|
+
order,
|
|
21
|
+
list,
|
|
22
|
+
line,
|
|
23
|
+
colon: orderGroup && orderGroup.startsWith(':'),
|
|
24
|
+
type: this.type,
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { TaskParser } from './TaskParser.js'
|
|
2
|
+
|
|
3
|
+
export class MarkdownStyleTaskParser extends TaskParser {
|
|
4
|
+
constructor(config) {
|
|
5
|
+
super('MARKDOWN', config)
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
get pattern() {
|
|
9
|
+
return /^(.*)(\[(.+?)\]\(#([a-zA-Z-_]+?)(:)(-?[\d.]+(?:e-?\d+)?)?\))/gm
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
parse(lineContent, line, matchResult) {
|
|
13
|
+
const [match, beforeText, rawTask, text, list, colon, order] = matchResult
|
|
14
|
+
return {
|
|
15
|
+
beforeText,
|
|
16
|
+
text,
|
|
17
|
+
order,
|
|
18
|
+
list,
|
|
19
|
+
line,
|
|
20
|
+
colon,
|
|
21
|
+
type: this.type,
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
|
|
2
|
+
class Task {
|
|
3
|
+
constructor({ beforeText, text, list, line, order, checked, colon, type }) {
|
|
4
|
+
this.contentLength = 0
|
|
5
|
+
this.description = []
|
|
6
|
+
this.beforeText = beforeText
|
|
7
|
+
this.text = text
|
|
8
|
+
this.list = list
|
|
9
|
+
this.line = line
|
|
10
|
+
this.order = order
|
|
11
|
+
this.checked = checked
|
|
12
|
+
this.colon = colon
|
|
13
|
+
this.type = type
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export class TaskParser {
|
|
18
|
+
constructor(type, config) {
|
|
19
|
+
this.config = config
|
|
20
|
+
this.type = type
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
get pattern() {
|
|
24
|
+
throw new Error('Unimplemented')
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
parseLine(lineContent, line, task) {
|
|
28
|
+
const re = new RegExp(this.pattern)
|
|
29
|
+
const result = re.exec(lineContent)
|
|
30
|
+
const parseResult = result && this.parse(lineContent, line, result, task)
|
|
31
|
+
|
|
32
|
+
if (parseResult && this.config.lists && !this.config.listExists(parseResult.list)) {
|
|
33
|
+
return
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return parseResult && new Task(parseResult)
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { readFile, writeFile, exists } from '../file-gateway.js'
|
|
2
|
+
import { constants } from '../../constants.js'
|
|
3
|
+
import { loadYAML, dumpYAML } from '../yaml.js'
|
|
4
|
+
import { findUp } from 'find-up-simple'
|
|
5
|
+
import _path from 'path'
|
|
6
|
+
import { Config } from '../../config.js'
|
|
7
|
+
import { logger } from '../logger.js'
|
|
8
|
+
|
|
9
|
+
const { CONFIG_DIR, CONFIG_FILE_YML } = constants
|
|
10
|
+
export async function load(projectPath, configPath = _path.join(projectPath, CONFIG_FILE_YML)) {
|
|
11
|
+
const configLike = await loadYamlConfig(configPath)
|
|
12
|
+
return configLike && new Config(configLike)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export async function save(config, projectPath) {
|
|
16
|
+
const configPath = _path.join(projectPath, CONFIG_FILE_YML)
|
|
17
|
+
await writeFile(configPath, dumpYAML(config))
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export async function loadForFilePath(filePath) {
|
|
21
|
+
const projectPath = await findImdonePath(filePath)
|
|
22
|
+
return load(projectPath)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export async function loadYamlConfig(filePath) {
|
|
26
|
+
if (!(await exists(filePath))) return
|
|
27
|
+
const configData = await readFile(filePath, 'utf-8')
|
|
28
|
+
let configLike = {}
|
|
29
|
+
try {
|
|
30
|
+
configLike = loadYAML(configData.toString())
|
|
31
|
+
if (configLike.exclude) delete configLike.exclude
|
|
32
|
+
if (configLike.watcher) delete configLike.watcher
|
|
33
|
+
|
|
34
|
+
} catch (e) {
|
|
35
|
+
logger.error(`Error parsing config file: ${filePath}`)
|
|
36
|
+
}
|
|
37
|
+
return configLike
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export async function findImdonePath(cwd) {
|
|
41
|
+
const configDir = await findUp(CONFIG_DIR, { cwd, type: 'directory' })
|
|
42
|
+
return _path.dirname(configDir)
|
|
43
|
+
}
|
|
44
|
+
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { readFile, writeFile, exists } from '../file-gateway.js'
|
|
2
|
+
import { constants } from '../../constants.js'
|
|
3
|
+
const { CONFIG_DIR } = constants
|
|
4
|
+
import { loadYAML, dumpYAML } from '../yaml.js'
|
|
5
|
+
import _path from 'path'
|
|
6
|
+
import { logger } from '../logger.js'
|
|
7
|
+
|
|
8
|
+
export const TAGS_FILE_PATH = _path.join(CONFIG_DIR, 'tags.yml')
|
|
9
|
+
|
|
10
|
+
export async function load(projectPath) {
|
|
11
|
+
const tagsPath = getTagsPath(projectPath)
|
|
12
|
+
if (!(await exists(tagsPath))) return
|
|
13
|
+
const tagsData = await readFile(tagsPath, 'utf-8')
|
|
14
|
+
try {
|
|
15
|
+
const { tags } = loadYAML(tagsData)
|
|
16
|
+
return tags
|
|
17
|
+
} catch (e) {
|
|
18
|
+
logger.error(e)
|
|
19
|
+
return
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export async function save(tags, projectPath) {
|
|
24
|
+
await writeFile(getTagsPath(projectPath), dumpYAML({ tags }))
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function getTagsPath(projectPath) {
|
|
28
|
+
return _path.join(projectPath, TAGS_FILE_PATH)
|
|
29
|
+
}
|