imdone-core 1.54.12 → 1.54.14
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 +8 -0
- package/CHANGELOG.md +9 -0
- package/README.md +0 -1
- package/lib/adapters/parsers/task/CardContentParser.js +41 -15
- package/lib/file.js +40 -6
- package/lib/mixins/repo-watched-fs-store.js +2 -0
- package/lib/project.js +5 -7
- package/lib/repository.js +3 -1
- package/lib/task.js +34 -3
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
## 1.54.13
|
|
2
|
+
|
|
3
|
+
- **Enhancement**: `customCardTerminator` now accepts numeric values to specify the number of consecutive blank lines needed to terminate a card (e.g., `customCardTerminator: 3` requires 3 blank lines)
|
|
4
|
+
- **Enhancement**: `repo.resume()` now automatically calls `refresh()` to pick up file changes that occurred while the repository was paused
|
|
5
|
+
- **Enhancement**: `File.trimBlankLines()` now respects the `customCardTerminator` config setting, preserving the appropriate number of blank lines in card content
|
|
6
|
+
- **Fix**: `Task.updateFromContent()` now respects the `customCardTerminator` config setting when collapsing consecutive blank lines, ensuring consistency across all content operations
|
|
7
|
+
- **Tests**: Added comprehensive test coverage for numeric `customCardTerminator` values, `trimBlankLines` behavior, `updateFromContent` behavior, and `resume()` refresh functionality
|
|
8
|
+
- **Refactor**: Improved code readability by replacing comments with self-documenting function names and descriptive constants
|
|
9
|
+
|
|
1
10
|
## 1.28.8
|
|
2
11
|
- Allow Card and Board actions to return a value
|
|
3
12
|
|
package/README.md
CHANGED
|
@@ -9,7 +9,6 @@ Imdone is text based kanban processor with a simple syntax that uses [comment ta
|
|
|
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 -->
|
|
11
11
|
|
|
12
|
-
|
|
13
12
|
- [Imdone format](#imdone-format)
|
|
14
13
|
- [Code Style](#code-style)
|
|
15
14
|
- [Hash Style](#hash-style)
|
|
@@ -55,10 +55,28 @@ function getContentLines(content) {
|
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
function isCustomCardTerminator(config, line) {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
&&
|
|
58
|
+
if (!config.customCardTerminator) return false
|
|
59
|
+
|
|
60
|
+
const isStringTerminator = typeof config.customCardTerminator === 'string'
|
|
61
|
+
&& config.customCardTerminator.trim()
|
|
62
|
+
|
|
63
|
+
if (isStringTerminator) {
|
|
64
|
+
const terminatorMatches = line && line.trim() === config.customCardTerminator.trim()
|
|
65
|
+
return terminatorMatches
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return false
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const DEFAULT_BLANK_LINE_TERMINATOR_COUNT = 2
|
|
72
|
+
|
|
73
|
+
function getBlankLineTerminatorCount(config) {
|
|
74
|
+
const hasNumericTerminator = typeof config.customCardTerminator === 'number'
|
|
75
|
+
&& config.customCardTerminator > 0
|
|
76
|
+
|
|
77
|
+
return hasNumericTerminator
|
|
78
|
+
? config.customCardTerminator
|
|
79
|
+
: DEFAULT_BLANK_LINE_TERMINATOR_COUNT
|
|
62
80
|
}
|
|
63
81
|
|
|
64
82
|
function isCheckBoxTask (config, line, beforeText) {
|
|
@@ -256,8 +274,8 @@ function getTextFileTaskContent ({
|
|
|
256
274
|
const isTaskInList = isMarkDownFile && isBeforeTextMarkdownList(beforeText)
|
|
257
275
|
let openBlockCommentTokens = 0
|
|
258
276
|
let closeBlockCommentTokens = 0
|
|
259
|
-
|
|
260
|
-
let
|
|
277
|
+
const blankLineTerminatorCount = getBlankLineTerminatorCount(config)
|
|
278
|
+
let consecutiveBlankLines = 0
|
|
261
279
|
let trailingBlankLines = 0
|
|
262
280
|
const rawTaskContentLines = []
|
|
263
281
|
const taskContentLines = []
|
|
@@ -277,7 +295,7 @@ function getTextFileTaskContent ({
|
|
|
277
295
|
if (isCheckBoxTask(config, line, beforeText)) break
|
|
278
296
|
if (isTaskInList && isLineOutsideMarkdownList(line, beforeText)) break
|
|
279
297
|
if (isCustomCardTerminator(config, line)) break
|
|
280
|
-
|
|
298
|
+
|
|
281
299
|
rawTaskContentLines.push(line)
|
|
282
300
|
taskContentLines.push(`${line}`)
|
|
283
301
|
|
|
@@ -285,20 +303,28 @@ function getTextFileTaskContent ({
|
|
|
285
303
|
if (isMarkDownFile && line.trim().indexOf('<!--') > -1)
|
|
286
304
|
openBlockCommentTokens++
|
|
287
305
|
if (isMarkDownFile && line.trim().indexOf('-->') > -1)
|
|
288
|
-
closeBlockCommentTokens++
|
|
306
|
+
closeBlockCommentTokens++
|
|
289
307
|
|
|
290
308
|
const thisLineBlank = line.trim() === ''
|
|
291
309
|
|
|
292
|
-
if (thisLineBlank
|
|
293
|
-
|
|
294
|
-
|
|
310
|
+
if (thisLineBlank) {
|
|
311
|
+
consecutiveBlankLines++
|
|
312
|
+
if (consecutiveBlankLines >= blankLineTerminatorCount) {
|
|
313
|
+
trailingBlankLines = blankLineTerminatorCount
|
|
314
|
+
break
|
|
315
|
+
}
|
|
316
|
+
} else {
|
|
317
|
+
consecutiveBlankLines = 0
|
|
295
318
|
}
|
|
296
|
-
|
|
297
|
-
lastLineBlank = thisLineBlank
|
|
298
319
|
}
|
|
299
320
|
|
|
300
|
-
|
|
301
|
-
|
|
321
|
+
const reachedEndNaturally = trailingBlankLines === 0
|
|
322
|
+
const hasTrailingBlankLines = consecutiveBlankLines > 0
|
|
323
|
+
const isUsingDefaultTerminator = blankLineTerminatorCount === DEFAULT_BLANK_LINE_TERMINATOR_COUNT
|
|
324
|
+
|
|
325
|
+
if (reachedEndNaturally && hasTrailingBlankLines && isUsingDefaultTerminator) {
|
|
326
|
+
trailingBlankLines = consecutiveBlankLines
|
|
327
|
+
}
|
|
302
328
|
|
|
303
329
|
// Remove extra block comment tokens
|
|
304
330
|
if (
|
package/lib/file.js
CHANGED
|
@@ -820,17 +820,51 @@ File.prototype.modifyTaskFromHtml = function (task, html) {
|
|
|
820
820
|
}
|
|
821
821
|
|
|
822
822
|
File.prototype.modifyTaskFromContent = function (task, content, config) {
|
|
823
|
-
content = trimBlankLines(content, this.isCodeFile())
|
|
823
|
+
content = trimBlankLines(content, this.isCodeFile(), config)
|
|
824
824
|
task.updateFromContent(content)
|
|
825
825
|
this.modifyTask(task, config)
|
|
826
826
|
}
|
|
827
827
|
|
|
828
|
-
const
|
|
828
|
+
const DEFAULT_BLANK_LINE_TERMINATOR_COUNT = 2
|
|
829
|
+
const CODE_FILE_BLANK_LINE_PATTERN = /\n\s*\n/g
|
|
830
|
+
const CODE_FILE_BLANK_LINE_REPLACEMENT = '\n'
|
|
831
|
+
|
|
832
|
+
function getBlankLineTerminatorCountFromConfig(config) {
|
|
833
|
+
const hasNumericTerminator = config
|
|
834
|
+
&& typeof config.customCardTerminator === 'number'
|
|
835
|
+
&& config.customCardTerminator > 0
|
|
836
|
+
|
|
837
|
+
return hasNumericTerminator
|
|
838
|
+
? config.customCardTerminator
|
|
839
|
+
: DEFAULT_BLANK_LINE_TERMINATOR_COUNT
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
function buildExcessiveBlankLinePattern(terminatorCount) {
|
|
843
|
+
const minNewlinesToTrim = terminatorCount + 1
|
|
844
|
+
const patternParts = Array(minNewlinesToTrim).fill('\\n\\s*')
|
|
845
|
+
return new RegExp(patternParts.join(''), 'g')
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
function calculateMaxPreservedBlankLines(terminatorCount) {
|
|
849
|
+
return terminatorCount - 1
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
function buildBlankLineReplacement(maxBlankLines) {
|
|
853
|
+
const newlineCount = maxBlankLines + 1
|
|
854
|
+
return '\n'.repeat(newlineCount)
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
const trimBlankLines = File.trimBlankLines = function (content, isCodeFile, config) {
|
|
829
858
|
if (isCodeFile) {
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
859
|
+
return content.replace(CODE_FILE_BLANK_LINE_PATTERN, CODE_FILE_BLANK_LINE_REPLACEMENT)
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
const terminatorCount = getBlankLineTerminatorCountFromConfig(config)
|
|
863
|
+
const excessiveBlankLinePattern = buildExcessiveBlankLinePattern(terminatorCount)
|
|
864
|
+
const maxBlankLines = calculateMaxPreservedBlankLines(terminatorCount)
|
|
865
|
+
const replacement = buildBlankLineReplacement(maxBlankLines)
|
|
866
|
+
|
|
867
|
+
return content.replace(excessiveBlankLinePattern, replacement)
|
|
834
868
|
}
|
|
835
869
|
|
|
836
870
|
File.prototype.modifyDescription = function (task, config) {
|
|
@@ -112,6 +112,7 @@ function mixin(repo, fs = require('fs')) {
|
|
|
112
112
|
repo.pause = async function () {
|
|
113
113
|
log('Pausing watcher for:', repo.path)
|
|
114
114
|
paused = true
|
|
115
|
+
repo.emit('paused')
|
|
115
116
|
return Promise.resolve()
|
|
116
117
|
}
|
|
117
118
|
|
|
@@ -124,6 +125,7 @@ function mixin(repo, fs = require('fs')) {
|
|
|
124
125
|
console.error('Error refreshing repo on resume', err)
|
|
125
126
|
return reject(err)
|
|
126
127
|
}
|
|
128
|
+
repo.emit('resumed')
|
|
127
129
|
resolve(files)
|
|
128
130
|
})
|
|
129
131
|
})
|
package/lib/project.js
CHANGED
|
@@ -32,17 +32,15 @@ function calculateTotals(lists = []) {
|
|
|
32
32
|
return totals
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
|
|
36
|
-
project.emit(event, data)
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
const EVENTS = [
|
|
35
|
+
const REPO_EVENTS_EMITTED = [
|
|
40
36
|
'file.processed',
|
|
41
37
|
'files.found',
|
|
42
38
|
'file.update',
|
|
43
39
|
'file.saved',
|
|
44
40
|
'list.modified',
|
|
45
41
|
'config.update',
|
|
42
|
+
'paused',
|
|
43
|
+
'resumed',
|
|
46
44
|
]
|
|
47
45
|
|
|
48
46
|
module.exports = class WorkerProject extends Project {
|
|
@@ -157,8 +155,8 @@ module.exports = class WorkerProject extends Project {
|
|
|
157
155
|
|
|
158
156
|
console.log('data', this.data)
|
|
159
157
|
console.log('dataKeys', this.dataKeys)
|
|
160
|
-
|
|
161
|
-
this.repo.on(event, (data) =>
|
|
158
|
+
REPO_EVENTS_EMITTED.forEach((event) => {
|
|
159
|
+
this.repo.on(event, (data) => this.emit(event, data))
|
|
162
160
|
})
|
|
163
161
|
|
|
164
162
|
this.repo.on('task.found', (task) => this.pluginManager.onTaskFound(task))
|
package/lib/repository.js
CHANGED
|
@@ -1156,7 +1156,9 @@ Repository.prototype.appendTask = function({file, content, list}, cb) {
|
|
|
1156
1156
|
: description.join(eol.lf)
|
|
1157
1157
|
|
|
1158
1158
|
let appendContent = File.trimBlankLines(
|
|
1159
|
-
`${taskPrefix}${rawTask}${eol.lf}${taskContent}
|
|
1159
|
+
`${taskPrefix}${rawTask}${eol.lf}${taskContent}`,
|
|
1160
|
+
file.isCodeFile(),
|
|
1161
|
+
config
|
|
1160
1162
|
)
|
|
1161
1163
|
|
|
1162
1164
|
fileContent = `${fileContent}${sep}`
|
package/lib/task.js
CHANGED
|
@@ -14,7 +14,7 @@ var _clone = require('lodash.clone'),
|
|
|
14
14
|
{ escapeRegExp } = require('./tools'),
|
|
15
15
|
{ extractWikilinkTopics } = require('./adapters/markdown');
|
|
16
16
|
|
|
17
|
-
const {
|
|
17
|
+
const {
|
|
18
18
|
CHECK_REGEX,
|
|
19
19
|
TASK_TYPES,
|
|
20
20
|
getCheckedData,
|
|
@@ -22,6 +22,33 @@ const {
|
|
|
22
22
|
isNumber
|
|
23
23
|
} = require('./adapters/parsers/task/CardContentParser.js')
|
|
24
24
|
|
|
25
|
+
const DEFAULT_BLANK_LINE_TERMINATOR_COUNT = 2
|
|
26
|
+
|
|
27
|
+
function getBlankLineTerminatorCountFromConfig(config) {
|
|
28
|
+
const hasNumericTerminator = config
|
|
29
|
+
&& typeof config.customCardTerminator === 'number'
|
|
30
|
+
&& config.customCardTerminator > 0
|
|
31
|
+
|
|
32
|
+
return hasNumericTerminator
|
|
33
|
+
? config.customCardTerminator
|
|
34
|
+
: DEFAULT_BLANK_LINE_TERMINATOR_COUNT
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function buildExcessiveBlankLinePattern(terminatorCount) {
|
|
38
|
+
const minNewlinesToTrim = terminatorCount + 1
|
|
39
|
+
const patternParts = Array(minNewlinesToTrim).fill('\\n\\s*')
|
|
40
|
+
return new RegExp(patternParts.join(''), 'g')
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function calculateMaxPreservedBlankLines(terminatorCount) {
|
|
44
|
+
return terminatorCount - 1
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function buildBlankLineReplacement(maxBlankLines) {
|
|
48
|
+
const newlineCount = maxBlankLines + 1
|
|
49
|
+
return '\n'.repeat(newlineCount)
|
|
50
|
+
}
|
|
51
|
+
|
|
25
52
|
/**
|
|
26
53
|
* Description
|
|
27
54
|
* @method Task
|
|
@@ -177,8 +204,12 @@ class Task {
|
|
|
177
204
|
}
|
|
178
205
|
|
|
179
206
|
updateFromContent(content) {
|
|
180
|
-
|
|
181
|
-
|
|
207
|
+
const terminatorCount = getBlankLineTerminatorCountFromConfig(this.config)
|
|
208
|
+
const excessiveBlankLinePattern = buildExcessiveBlankLinePattern(terminatorCount)
|
|
209
|
+
const maxBlankLines = calculateMaxPreservedBlankLines(terminatorCount)
|
|
210
|
+
const replacement = buildBlankLineReplacement(maxBlankLines)
|
|
211
|
+
|
|
212
|
+
content = content.replace(excessiveBlankLinePattern, replacement)
|
|
182
213
|
let lines = eol.split(content)
|
|
183
214
|
this.text = lines.shift().trimStart()
|
|
184
215
|
if (lines && lines.length > 1 && lines[lines.length - 1].trim() === '') lines.pop()
|