imdone-core 1.52.1 → 1.53.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.
@@ -3,48 +3,75 @@ const imageSize = require('markdown-it-imsize')
3
3
  const emoji = require('markdown-it-emoji')
4
4
  const mark = require('markdown-it-mark')
5
5
  const removeMD = require('remove-markdown')
6
- const wikilinks = require('@kwvanderlinde/markdown-it-wikilinks')
7
6
  const path = require('path');
8
7
 
9
8
  const MarkdownIt = require('markdown-it')
10
9
  let _platform = process.platform
11
10
 
12
11
  function extractWikilinkTopics(markdown) {
13
- const wikilinkRegex = /\[\[([\w\s/]+)(\|([\w\s/]+))?\]\]/g; // Match [[Topic]] or [[Topic|Display Text]]
12
+ const wikilinkRegex = /\[\[([a-zA-Z0-9\u00C0-\u017F/_\-. ]+)(?:\|([^\]]+))?\]\]/g;
14
13
  const topics = [];
15
14
  let match;
16
15
 
17
- // Use RegExp.exec to iterate through all matches
18
16
  while ((match = wikilinkRegex.exec(markdown)) !== null) {
19
- topics.push(match[1].trim()); // Extract the topic (first capture group) and trim whitespace
17
+ topics.push(match[1].trim()); // Always extract the topic (first capture group)
20
18
  }
21
19
 
22
20
  return topics;
23
21
  }
24
22
 
25
- function getRenderer(projectPath) {
23
+ function getRenderer(filePath) {
26
24
  const md = new MarkdownIt({html: true, breaks: true})
27
25
 
28
26
  md.use(checkbox)
29
27
  .use(mark)
30
28
  .use(emoji)
31
29
  .use(imageSize)
32
- .use(wikilinks(
33
- {
34
- linkPattern: /\[\[([\w\u00C0-\u017F\s\d-/]+)(\|([\w\u00C0-\u017F\s\d-/]+))?\]\]/,
35
- uriSuffix: '.md',
36
- postProcessPageName (pagename) {
37
- return pagename.trim()
38
- }
39
- }
40
- ))
41
- .use(replaceImagePaths(projectPath))
30
+ .use(obsidianTopicLinks(filePath))
31
+ .use(replaceImagePaths(filePath))
32
+ .use(replaceLinkPaths(filePath))
42
33
  .validateLink = () => true
43
34
 
44
35
  return md
45
36
  }
46
37
 
47
- function replaceImagePaths(projectPath) {
38
+ function obsidianTopicLinks(filePath) {
39
+ return function(md) {
40
+ const obsidianLinkRegex = /^\[\[([a-zA-Z0-9\u00C0-\u017F/_\-. ]+)(?:\|([^\]]+))?\]\]/; // No 'g' flag
41
+
42
+ function obsidianLinkRenderer(state, silent) {
43
+ const pos = state.pos;
44
+ const match = state.src.slice(pos).match(obsidianLinkRegex); // Always start from `pos`
45
+
46
+ if (!match) return false;
47
+ if (silent) return true; // Don't process further in silent mode
48
+
49
+ const fullMatch = match[0];
50
+ let topic = match[1].trim();
51
+ const alias = match[2] ? match[2].trim() : topic;
52
+ if (!topic.endsWith('.md')) topic = `${topic}.md`;
53
+ const href = encodeURI(resolveFileUrl(topic, filePath));
54
+
55
+ // Create a new token
56
+ const token = state.push("obsidian_link", "", 0);
57
+ token.content = `<a href="${href}">${md.utils.escapeHtml(alias)}</a>`;
58
+
59
+ // Move parsing position forward
60
+ state.pos += fullMatch.length;
61
+ return true;
62
+ }
63
+
64
+ function render(tokens, idx) {
65
+ return tokens[idx].content;
66
+ }
67
+
68
+ md.inline.ruler.before("link", "obsidian_link", obsidianLinkRenderer);
69
+ md.renderer.rules.obsidian_link = render;
70
+ }
71
+ }
72
+
73
+
74
+ function replaceImagePaths(filePath) {
48
75
 
49
76
  return function(md) {
50
77
  const defaultRender = md.renderer.rules.image || function(tokens, idx, options, env, self) {
@@ -54,14 +81,31 @@ function replaceImagePaths(projectPath) {
54
81
  md.renderer.rules.image = function(tokens, idx, options, env, self) {
55
82
  const token = tokens[idx];
56
83
  const srcIndex = token.attrIndex('src');
84
+ if (srcIndex >= 0) {
85
+ const src = token.attrs[srcIndex][1];
86
+ const srcUrl = !isUrl(src) && resolveFileUrl(src, filePath)
87
+ if (srcUrl) token.attrs[srcIndex][1] = srcUrl;
88
+ }
57
89
 
90
+ return defaultRender(tokens, idx, options, env, self);
91
+ };
92
+ }
93
+ }
94
+
95
+ function replaceLinkPaths(filePath) {
96
+
97
+ return function(md) {
98
+ const defaultRender = md.renderer.rules.link_open || function(tokens, idx, options, env, self) {
99
+ return self.renderToken(tokens, idx, options);
100
+ };
101
+
102
+ md.renderer.rules.link_open = function(tokens, idx, options, env, self) {
103
+ const token = tokens[idx];
104
+ const srcIndex = token.attrIndex('href');
58
105
  if (srcIndex >= 0) {
59
106
  const src = token.attrs[srcIndex][1];
60
- if (!src.startsWith('http')) {
61
- const filePath = projectPath ? path.join(projectPath, src) : path.resolve(src);
62
- const fileUrl = pathToFileURL(filePath);
63
- token.attrs[srcIndex][1] = fileUrl;
64
- }
107
+ const srcUrl = !isUrl(src) && resolveFileUrl(src, filePath)
108
+ if (srcUrl) token.attrs[srcIndex][1] = srcUrl;
65
109
  }
66
110
 
67
111
  return defaultRender(tokens, idx, options, env, self);
@@ -69,6 +113,29 @@ function replaceImagePaths(projectPath) {
69
113
  }
70
114
  }
71
115
 
116
+ function isUrl(href) {
117
+ try {
118
+ new URL(href);
119
+ return true;
120
+ } catch (e) {
121
+ return false;
122
+ }
123
+ }
124
+
125
+ function resolveFileUrl(src, filePath) {
126
+ const dirname = _platform === 'win32' ? path.win32.dirname : path.dirname;
127
+ const resolve = _platform === 'win32' ? path.win32.resolve : path.resolve;
128
+
129
+ if (src.startsWith('file://')) return src;
130
+ if (src === '/') src = './';
131
+ const srcDir = dirname(filePath);
132
+ const srcPath = resolve(srcDir, src) // filePath ? path.join(filePath, src) : path.resolve(src);
133
+ const srcUrl = pathToFileURL(srcPath);
134
+
135
+ return srcUrl;
136
+
137
+ }
138
+
72
139
  function pathToFileURL(absolutePath) {
73
140
  if (_platform === 'win32') {
74
141
  absolutePath = '/' + absolutePath.replace(/\\/g, '/');
@@ -84,9 +151,9 @@ module.exports = {
84
151
  _setPlatform(platform) {
85
152
  _platform = platform
86
153
  },
87
- renderMarkdown (markdown, projectPath) {
154
+ renderMarkdown (markdown, filePath) {
88
155
  markdown = renderCancelledTasks(markdown)
89
- return getRenderer(projectPath).render(markdown)
156
+ return getRenderer(filePath).render(markdown)
90
157
  },
91
158
  extractWikilinkTopics,
92
159
  removeMD
package/lib/card.js CHANGED
@@ -283,28 +283,13 @@ module.exports = function newCard(task, _project, dontParse) {
283
283
  return { totalLines, markdown, rawMarkdown }
284
284
  }
285
285
 
286
- // replaceImagePaths(content) {
287
- // return content.replace(
288
- // /(!\[.*?\]\()(.*?)(\))/g,
289
- // (match, p1, imagePath, p3) => {
290
- // if (/^http/.test(imagePath)) return match
291
- // imagePath = _path.join(
292
- // _path.dirname(this.fullPath),
293
- // imagePath
294
- // ).replace(/ /g, '%20')
295
- // const imageURL = `file://${imagePath}`
296
- // return p1 + imageURL + p3
297
- // }
298
- // )
299
- // }
300
-
301
286
  getHtml(content) {
302
- const html = project.renderMarkdown(content)
287
+ const html = project.renderMarkdown(content, this.fullPath)
303
288
  const mdArray = eol.split(content)
304
289
  let truncHtml = null
305
290
  if (mdArray.length > this.truncLines) {
306
291
  mdArray.length = this.truncLines
307
- truncHtml = project.renderMarkdown(mdArray.join(eol.lf))
292
+ truncHtml = project.renderMarkdown(mdArray.join(eol.lf), this.fullPath)
308
293
  }
309
294
  return { html, truncHtml }
310
295
  }
@@ -36,7 +36,7 @@ module.exports = class DefaultBoardActionsPlugin extends Plugin {
36
36
  keys: ['mod+t'],
37
37
  icon: 'clone',
38
38
  action: (task) => {
39
- const title = project.renderMarkdown(task.text).replaceAll(/<\/*p>/gi, '')
39
+ const title = project.renderMarkdown(task.text, task.fullPath).replaceAll(/<\/*p>/gi, '')
40
40
  return project.copyToClipboard(title, `"${title}" copied to clipboard`)
41
41
  },
42
42
  },
@@ -159,7 +159,7 @@ module.exports = class EpicPlugin extends Plugin {
159
159
  content += '<ul style="list-style: none;">'
160
160
  content += tasks
161
161
  .map((task) => {
162
- const taskText = this.project.renderMarkdown(task.text).replaceAll(/<p>|<\/p>/ig, '') // removeMD(task.text)
162
+ const taskText = this.project.renderMarkdown(task.text, task.fullPath).replaceAll(/<p>|<\/p>/ig, '') // removeMD(task.text)
163
163
  const checked =
164
164
  task.list === this.project.doneList ? ' checked="true"' : ''
165
165
  const taskFilePath = encodeURI(
package/lib/project.js CHANGED
@@ -800,8 +800,8 @@ module.exports = class WorkerProject extends Project {
800
800
  })
801
801
  }
802
802
 
803
- renderMarkdown(content) {
804
- return renderMarkdown(content, this.path)
803
+ renderMarkdown(content, filePath) {
804
+ return renderMarkdown(content, filePath || this.path)
805
805
  }
806
806
 
807
807
  extractWikilinkTopics(markdown) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "imdone-core",
3
- "version": "1.52.1",
3
+ "version": "1.53.1",
4
4
  "description": "imdone-core",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -42,8 +42,6 @@
42
42
  }
43
43
  },
44
44
  "dependencies": {
45
- "@inquirer/editor": "^1.2.12",
46
- "@kwvanderlinde/markdown-it-wikilinks": "^1.0.2",
47
45
  "async": "~1.5.0",
48
46
  "chalk": "^4.1.2",
49
47
  "checksum": "^0.1.1",