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.
package/lib/adapters/markdown.js
CHANGED
|
@@ -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 = /\[\[([\
|
|
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()); //
|
|
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(
|
|
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(
|
|
33
|
-
|
|
34
|
-
|
|
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
|
|
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
|
-
|
|
61
|
-
|
|
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,
|
|
154
|
+
renderMarkdown (markdown, filePath) {
|
|
88
155
|
markdown = renderCancelledTasks(markdown)
|
|
89
|
-
return getRenderer(
|
|
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.
|
|
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",
|