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.
@@ -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: require('path').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
- return fs.statSync(path)
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
- pluginManager.onTaskUpdate(this)
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: /(?<!`)\${([\s\S]+?)}/g }
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
- if (!repo.allFiles.includes(path)) {
90
- repo.allFiles.push(path)
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
  })
@@ -13,6 +13,7 @@ function getEpicMeta(task) {
13
13
  module.exports = class EpicPlugin extends Plugin {
14
14
  constructor(project) {
15
15
  super(project)
16
+ this.epics = {}
16
17
  }
17
18
 
18
19
  onBeforeBoardUpdate() {
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
- path = this.getFullPath(path)
427
- if (!fileGateway.existsSync(path)) {
428
- fileGateway.writeFileSync(path, '')
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: stat.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, stat) {
550
- const frontMatter = this.getNewCardFileFrontMatter(file, stat)
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, stat) {
582
+ getNewCardFileFrontMatter(file, isFile) {
566
583
  let fileContent = ''
567
- if (file && stat.isFile()) {
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
- if (fileGateway.existsSync(filePath))
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(name) {
626
- let fileName = sanitize(name)
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
- file.setContent(`${fileContent}${appendContent}${"\n".repeat(2)}`)
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)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "imdone-core",
3
- "version": "1.44.5",
3
+ "version": "1.45.0",
4
4
  "description": "imdone-core",
5
5
  "main": "index.js",
6
6
  "scripts": {