imdone-core 1.44.5 → 1.45.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/lib/adapters/file-gateway.js +16 -3
- package/lib/adapters/parsers/task/CardContentParser.js +10 -2
- package/lib/card.js +7 -2
- package/lib/config.js +9 -0
- package/lib/file.js +2 -0
- package/lib/mixins/repo-fs-store.js +9 -3
- package/lib/plugins/epic-plugin.js +1 -0
- package/lib/project.js +39 -37
- package/lib/repository.js +2 -1
- package/package.json +1 -1
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
const tools = require('../tools')
|
|
2
|
-
|
|
2
|
+
const _path = require('path')
|
|
3
3
|
let fs = require('fs')
|
|
4
|
+
const sanitize = require('sanitize-filename')
|
|
5
|
+
|
|
4
6
|
|
|
5
7
|
module.exports = {
|
|
6
8
|
init(fileSystem = fs) {
|
|
7
9
|
fs = fileSystem
|
|
8
10
|
},
|
|
9
11
|
|
|
10
|
-
sep:
|
|
12
|
+
sep: _path.sep,
|
|
11
13
|
|
|
12
14
|
existsSync(...args) {
|
|
13
15
|
console.warn('sync call')
|
|
@@ -61,7 +63,10 @@ module.exports = {
|
|
|
61
63
|
|
|
62
64
|
statSync(path) {
|
|
63
65
|
console.warn('sync call')
|
|
64
|
-
|
|
66
|
+
try {
|
|
67
|
+
return fs.statSync(path)
|
|
68
|
+
} catch {
|
|
69
|
+
}
|
|
65
70
|
},
|
|
66
71
|
|
|
67
72
|
readdirSyncRecursive(path) {
|
|
@@ -73,4 +78,12 @@ module.exports = {
|
|
|
73
78
|
console.warn('sync call')
|
|
74
79
|
return fs.readdirSync(path, { withFileTypes: true })
|
|
75
80
|
},
|
|
81
|
+
sanitizeFileName(fileName, replaceSpacesWith) {
|
|
82
|
+
// Remove markdown emoji
|
|
83
|
+
fileName = fileName.replace(/:\w+:/g, '').trim()
|
|
84
|
+
fileName = sanitize(fileName)
|
|
85
|
+
if (replaceSpacesWith)
|
|
86
|
+
fileName = fileName.replace(/ /g, replaceSpacesWith)
|
|
87
|
+
return fileName
|
|
88
|
+
}
|
|
76
89
|
}
|
|
@@ -43,6 +43,13 @@ function getContentLines(content) {
|
|
|
43
43
|
})
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
+
function isCustomCardTerminator(config, line) {
|
|
47
|
+
return config.customCardTerminator
|
|
48
|
+
&& config.customCardTerminator.trim()
|
|
49
|
+
&& line
|
|
50
|
+
&& line.trim() === config.customCardTerminator
|
|
51
|
+
}
|
|
52
|
+
|
|
46
53
|
function isCheckBoxTask (config, line, beforeText) {
|
|
47
54
|
if (!config.isAddCheckBoxTasks()) return
|
|
48
55
|
|
|
@@ -146,6 +153,7 @@ function getCardTagsTaskContent ({
|
|
|
146
153
|
}
|
|
147
154
|
}
|
|
148
155
|
|
|
156
|
+
// This finds the end of task
|
|
149
157
|
function getCodeFileTaskContent ({
|
|
150
158
|
config,
|
|
151
159
|
content,
|
|
@@ -208,13 +216,13 @@ function getTextFileTaskContent ({
|
|
|
208
216
|
|
|
209
217
|
for (let i = 1; i < lines.length; i++) {
|
|
210
218
|
let line = lines[i]
|
|
211
|
-
let taskContentLine = `${line}`
|
|
212
219
|
if (hasTaskInText(config, line)) break
|
|
213
220
|
if (isCheckBoxTask(config, line, beforeText)) break
|
|
214
221
|
if (isTaskInList && isLineOutsideMarkdownList(line, beforeText)) break
|
|
222
|
+
if (isCustomCardTerminator(config, line)) break
|
|
215
223
|
|
|
216
|
-
taskContentLines.push(taskContentLine)
|
|
217
224
|
rawTaskContentLines.push(line)
|
|
225
|
+
taskContentLines.push(`${line}`)
|
|
218
226
|
|
|
219
227
|
// Check for matching block comments in markdown files
|
|
220
228
|
if (isMarkDownFile && line.trim().indexOf('<!--') > -1)
|
package/lib/card.js
CHANGED
|
@@ -56,7 +56,12 @@ module.exports = function newCard(task, _project, dontParse) {
|
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
onTaskUpdate() {
|
|
59
|
-
|
|
59
|
+
// TODO We should be mapping to the imdone-api task
|
|
60
|
+
// #imdone-1.45.0
|
|
61
|
+
const interpretedContent = pluginManager.onTaskUpdate(this)
|
|
62
|
+
if (interpretedContent && interpretedContent.length > 0) {
|
|
63
|
+
this.interpretedContent = interpretedContent
|
|
64
|
+
}
|
|
60
65
|
}
|
|
61
66
|
|
|
62
67
|
initProps() {
|
|
@@ -239,7 +244,7 @@ module.exports = function newCard(task, _project, dontParse) {
|
|
|
239
244
|
format(content, mustache) {
|
|
240
245
|
const data = this.data
|
|
241
246
|
|
|
242
|
-
const opts = { interpolate: /(
|
|
247
|
+
const opts = { interpolate: /(?<![`\\])\${([\s\S]+?)}/g }
|
|
243
248
|
|
|
244
249
|
if (mustache) content = removeDisplayComments(content)
|
|
245
250
|
|
package/lib/config.js
CHANGED
|
@@ -20,6 +20,7 @@ class Config {
|
|
|
20
20
|
_assign(this, opts)
|
|
21
21
|
if (!this.settings) this.settings = {}
|
|
22
22
|
if (!this.settings.views) this.settings.views = []
|
|
23
|
+
if (!this.settings.cards) this.settings.cards = {}
|
|
23
24
|
}
|
|
24
25
|
|
|
25
26
|
get defaultFilter() {
|
|
@@ -94,6 +95,14 @@ class Config {
|
|
|
94
95
|
return _get(this, 'settings.cards.addCompletedMeta', false)
|
|
95
96
|
}
|
|
96
97
|
|
|
98
|
+
get customCardTerminator() {
|
|
99
|
+
return _get(this, 'settings.cards.customCardTerminator')
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
set customCardTerminator(terminator) {
|
|
103
|
+
this.settings.cards.customCardTerminator = terminator
|
|
104
|
+
}
|
|
105
|
+
|
|
97
106
|
get markdownOnly() {
|
|
98
107
|
return this.settings.markdownOnly
|
|
99
108
|
}
|
package/lib/file.js
CHANGED
|
@@ -278,6 +278,7 @@ File.prototype.transformTask = function ({config, modify, task}) {
|
|
|
278
278
|
content = File.parseRemindDate(config, content)
|
|
279
279
|
content = File.parseDeferDate(config, content)
|
|
280
280
|
content = File.addCompleted({ task, content, config })
|
|
281
|
+
content = task.format(content)
|
|
281
282
|
if (
|
|
282
283
|
content.trim() !== task.content.trim()
|
|
283
284
|
|| trackListChanges.beforeTextModified
|
|
@@ -946,6 +947,7 @@ File.prototype.extractTaskWithDescription = function ({
|
|
|
946
947
|
task.updateOrderMeta(config)
|
|
947
948
|
|
|
948
949
|
task.orderModified = task.order + "" !== order + "" && !bothAreUndefNull(task.order, order)
|
|
950
|
+
task.init()
|
|
949
951
|
|
|
950
952
|
return task
|
|
951
953
|
}
|
|
@@ -85,9 +85,14 @@ function mixin(repo, fs = require('fs')) {
|
|
|
85
85
|
})
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
-
repo.addFilePath = function (path) {
|
|
89
|
-
|
|
90
|
-
|
|
88
|
+
repo.addFilePath = async function (path) {
|
|
89
|
+
var relPath = repo.getRelativePath(path)
|
|
90
|
+
var fullPath = repo.getFullPath(path)
|
|
91
|
+
|
|
92
|
+
const stat = await fs.promises.lstat(fullPath)
|
|
93
|
+
if (stat.isDirectory()) relPath += _path.sep
|
|
94
|
+
if (!repo.allFiles.includes(relPath)) {
|
|
95
|
+
repo.allFiles.push(relPath)
|
|
91
96
|
}
|
|
92
97
|
}
|
|
93
98
|
|
|
@@ -329,6 +334,7 @@ function mixin(repo, fs = require('fs')) {
|
|
|
329
334
|
|
|
330
335
|
file.setModifiedTime(stats.mtime)
|
|
331
336
|
file.modified = false
|
|
337
|
+
repo.addFilePath(filePath)
|
|
332
338
|
if (emitFileUpdate) repo.emit('file.saved', file)
|
|
333
339
|
cb(null, file)
|
|
334
340
|
})
|
package/lib/project.js
CHANGED
|
@@ -3,10 +3,10 @@ const PluginManager = require('./plugins/plugin-manager')
|
|
|
3
3
|
const Repository = require('./repository')
|
|
4
4
|
const _cloneDeep = require('lodash.clonedeep')
|
|
5
5
|
const newCard = require('./card')
|
|
6
|
-
const sanitize = require('sanitize-filename')
|
|
7
6
|
const { JOURNAL_TYPE } = require('./constants')
|
|
8
7
|
const _path = require('path')
|
|
9
8
|
const moment = require('moment')
|
|
9
|
+
const { getIsoDateWithOffset } = require('./adapters/date-time')
|
|
10
10
|
const fileGateway = require('./adapters/file-gateway')
|
|
11
11
|
const matter = require('gray-matter')
|
|
12
12
|
const _isObject = require('lodash.isobject')
|
|
@@ -175,6 +175,10 @@ module.exports = class WorkerProject extends Project {
|
|
|
175
175
|
return this.getCards(this.filter)
|
|
176
176
|
}
|
|
177
177
|
|
|
178
|
+
get isoDateWithOffset() {
|
|
179
|
+
return getIsoDateWithOffset()
|
|
180
|
+
}
|
|
181
|
+
|
|
178
182
|
removeList(list) {
|
|
179
183
|
this.repo.removeList(list)
|
|
180
184
|
}
|
|
@@ -412,6 +416,22 @@ module.exports = class WorkerProject extends Project {
|
|
|
412
416
|
this.emit('project.saveFile', { file: filePath, content })
|
|
413
417
|
}
|
|
414
418
|
|
|
419
|
+
preparePathForWriting(path) {
|
|
420
|
+
let stat = fileGateway.statSync(path)
|
|
421
|
+
if (!stat) {
|
|
422
|
+
let { dir, ext } = _path.parse(path)
|
|
423
|
+
if (!ext) {
|
|
424
|
+
dir = path
|
|
425
|
+
}
|
|
426
|
+
fileGateway.mkdirpSync(dir)
|
|
427
|
+
stat = fileGateway.statSync(path)
|
|
428
|
+
}
|
|
429
|
+
return {
|
|
430
|
+
isFile: stat && stat.isFile(),
|
|
431
|
+
isDirectory: stat && stat.isDirectory()
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
|
|
415
435
|
/*
|
|
416
436
|
* @param {Object} opts - The options object
|
|
417
437
|
* @param {String} opts.list - The list name to add the card to
|
|
@@ -422,25 +442,23 @@ module.exports = class WorkerProject extends Project {
|
|
|
422
442
|
* @param {Boolean} opts.emit - Whether to emit the new card event
|
|
423
443
|
*/
|
|
424
444
|
newCard({ list, path, template, title, comments, emit = true }) {
|
|
425
|
-
if (path) {
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
} // TODO: Need a way to handle new cards using new fie for each card
|
|
431
|
-
else {
|
|
432
|
-
path = this.getFullPath(this.getNewCardsFile({title}))
|
|
433
|
-
}
|
|
434
|
-
const stat = fileGateway.statSync(path)
|
|
435
|
-
if (!template) template = this.getNewCardTemplate(path, stat)
|
|
445
|
+
if (!path || !_path.parse(path).ext) path = this.getFullPath(this.getNewCardsFile({title}))
|
|
446
|
+
|
|
447
|
+
const { isFile, isDirectory } = this.preparePathForWriting(path)
|
|
448
|
+
|
|
449
|
+
if (!template) template = this.getNewCardTemplate(path, isFile)
|
|
436
450
|
|
|
437
451
|
if (comments) template = Task.addToLastCommentInContent(template, comments, this.config.isMetaNewLine())
|
|
438
452
|
|
|
453
|
+
let relativePath = _path.relative(this.path, path)
|
|
454
|
+
if (isDirectory) relativePath += _path.sep
|
|
455
|
+
|
|
439
456
|
const data = {
|
|
440
457
|
list,
|
|
441
458
|
path,
|
|
459
|
+
relativePath,
|
|
442
460
|
template,
|
|
443
|
-
isDirectory
|
|
461
|
+
isDirectory,
|
|
444
462
|
}
|
|
445
463
|
if (emit) this.emit('project.newCard', data)
|
|
446
464
|
return data
|
|
@@ -475,7 +493,6 @@ module.exports = class WorkerProject extends Project {
|
|
|
475
493
|
|
|
476
494
|
this.repo.moveTask({ task, newList, newPos }, (err) => {
|
|
477
495
|
if (err) return reject(err)
|
|
478
|
-
|
|
479
496
|
resolve({ file, task })
|
|
480
497
|
})
|
|
481
498
|
})
|
|
@@ -545,9 +562,9 @@ module.exports = class WorkerProject extends Project {
|
|
|
545
562
|
setFilter(filter) {
|
|
546
563
|
this.emit('project.filter', { filter })
|
|
547
564
|
}
|
|
548
|
-
|
|
549
|
-
getNewCardTemplate(file,
|
|
550
|
-
const frontMatter = this.getNewCardFileFrontMatter(file,
|
|
565
|
+
|
|
566
|
+
getNewCardTemplate(file, isFile) {
|
|
567
|
+
const frontMatter = this.getNewCardFileFrontMatter(file, isFile)
|
|
551
568
|
const card = newCard(
|
|
552
569
|
{
|
|
553
570
|
frontMatter,
|
|
@@ -562,9 +579,9 @@ module.exports = class WorkerProject extends Project {
|
|
|
562
579
|
return card.formatContent(frontMatter.template).content
|
|
563
580
|
}
|
|
564
581
|
|
|
565
|
-
getNewCardFileFrontMatter(file,
|
|
582
|
+
getNewCardFileFrontMatter(file, isFile) {
|
|
566
583
|
let fileContent = ''
|
|
567
|
-
if (file &&
|
|
584
|
+
if (file && isFile) {
|
|
568
585
|
fileContent = fileGateway.readFileSync(file, 'utf8')
|
|
569
586
|
} else if (JOURNAL_TYPE.NEW_FILE === this.config.journlType) {
|
|
570
587
|
fileContent = this.config.journalTemplate
|
|
@@ -597,8 +614,7 @@ module.exports = class WorkerProject extends Project {
|
|
|
597
614
|
if (!this.config) return ''
|
|
598
615
|
const filePath = this.appendNewCardsTo(title)
|
|
599
616
|
if (!filePath) return ''
|
|
600
|
-
|
|
601
|
-
return relPath ? filePath.replace(this.path, '') : filePath
|
|
617
|
+
return filePath
|
|
602
618
|
}
|
|
603
619
|
|
|
604
620
|
appendNewCardsTo(title) {
|
|
@@ -613,20 +629,12 @@ module.exports = class WorkerProject extends Project {
|
|
|
613
629
|
const fileFolder = this.getFullPath(this.config.journalPath)
|
|
614
630
|
const filePath = _path.join(fileFolder, fileName)
|
|
615
631
|
|
|
616
|
-
if (!fileGateway.existsSync(fileFolder))
|
|
617
|
-
fileGateway.mkdirpSync(fileFolder)
|
|
618
|
-
if (!fileGateway.existsSync(filePath))
|
|
619
|
-
fileGateway.writeFileSync(filePath, this.config.journalTemplate)
|
|
620
|
-
|
|
621
632
|
return filePath
|
|
622
633
|
}
|
|
623
634
|
}
|
|
624
635
|
|
|
625
|
-
sanitizeFileName(
|
|
626
|
-
|
|
627
|
-
if (this.config.replaceSpacesWith)
|
|
628
|
-
fileName = fileName.replace(/ /g, this.config.replaceSpacesWith)
|
|
629
|
-
return fileName
|
|
636
|
+
sanitizeFileName(fileName) {
|
|
637
|
+
return fileGateway.sanitizeFileName(fileName, this.config.replaceSpacesWith)
|
|
630
638
|
}
|
|
631
639
|
|
|
632
640
|
getJournalFile() {
|
|
@@ -641,13 +649,7 @@ module.exports = class WorkerProject extends Project {
|
|
|
641
649
|
`${journalFilePrefix}${today}${journalFileSuffix}.md`
|
|
642
650
|
)
|
|
643
651
|
|
|
644
|
-
const fullFolderPath = this.getFullPath(folderPath)
|
|
645
652
|
const fullFilePath = this.getFullPath(filePath)
|
|
646
|
-
if (!fileGateway.existsSync(fullFolderPath))
|
|
647
|
-
fileGateway.mkdirpSync(fullFolderPath)
|
|
648
|
-
if (!fileGateway.existsSync(fullFilePath)) {
|
|
649
|
-
fileGateway.writeFileSync(fullFilePath, this.config.journalTemplate)
|
|
650
|
-
}
|
|
651
653
|
return { filePath, fullFilePath }
|
|
652
654
|
}
|
|
653
655
|
|
package/lib/repository.js
CHANGED
|
@@ -1117,7 +1117,8 @@ Repository.prototype.appendTask = function({file, content, list}, cb) {
|
|
|
1117
1117
|
}
|
|
1118
1118
|
appendContent = File.trimBlankLines(appendContent)
|
|
1119
1119
|
fileContent = `${fileContent}${sep}`
|
|
1120
|
-
|
|
1120
|
+
const cardTerminator = "\n".repeat(2)
|
|
1121
|
+
file.setContent(`${fileContent}${appendContent}${cardTerminator}`)
|
|
1121
1122
|
this.writeAndExtract(file, true, (err, file) => {
|
|
1122
1123
|
if (err) return cb(err)
|
|
1123
1124
|
const task = file.getTasks().find(task => task.text === text && task.list === list)
|