-
Notifications
You must be signed in to change notification settings - Fork 17
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[ #60 , extract tasks ] #71
Changes from 5 commits
e88ded8
78506e8
a0a29dc
be5f06c
8341ee9
e1923b3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
--- | ||
"mddb": minor | ||
--- | ||
|
||
[ #60 , extract tasks ] | ||
Add tasks extraction from files. e.g `- [ ] task` |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,5 @@ | ||
import { Knex } from "knex"; | ||
import { | ||
MddbFile, | ||
MddbTag, | ||
MddbLink, | ||
MddbFileTag, | ||
File, | ||
} from "./schema.js"; | ||
import { MddbFile, MddbTag, MddbLink, MddbFileTag, File } from "./schema.js"; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For me this "linting" stuff creates noise in the PRs. I strongly suggest we do this separately (it can just be a direct push to main if just linting). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For future: we can lint the whole repo once and then we don't get running into these. |
||
import path from "path"; | ||
import { WikiLink } from "./parseFile.js"; | ||
|
||
|
@@ -18,12 +12,12 @@ | |
} | ||
} | ||
|
||
export function mapFileToInsert(file: any) { | ||
const { _id, file_path, extension, url_path, filetype, metadata } = file; | ||
return { _id, file_path, extension, url_path, filetype, metadata }; | ||
} | ||
|
||
export function mapLinksToInsert(filesToInsert: File[], file: any) { | ||
return file.links.map((link: WikiLink) => { | ||
let to: string | undefined; | ||
if (!link.internal) { | ||
|
@@ -51,12 +45,12 @@ | |
}); | ||
} | ||
|
||
export function isLinkToDefined(link: any) { | ||
return link.to !== undefined; | ||
} | ||
|
||
export function mapFileTagsToInsert(file: any) { | ||
return file.tags.map((tag: any) => ({ | ||
file: file._id, | ||
tag: tag as unknown as string, | ||
})); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,6 +24,9 @@ | |
// Links | ||
const links = extractWikiLinks(ast, options); | ||
|
||
const tasks = extractTasks(ast); | ||
metadata.tasks = tasks; | ||
|
||
return { | ||
metadata, | ||
links, | ||
|
@@ -61,7 +64,7 @@ | |
|
||
const nodes = selectAll("*", ast); | ||
for (let index = 0; index < nodes.length; index++) { | ||
const node: any = nodes[index]; | ||
if (node.value) { | ||
const textTags = node.value.match(/(?:^|\s)(#(\w+|\/|-|_)+)/g); | ||
if (textTags) { | ||
|
@@ -74,7 +77,7 @@ | |
}; | ||
|
||
export interface LinkExtractors { | ||
[test: string]: (node: any) => WikiLink; | ||
} | ||
|
||
export interface WikiLink { | ||
|
@@ -93,7 +96,7 @@ | |
const directory = path.dirname(from); | ||
|
||
const extractors: LinkExtractors = { | ||
link: (node: any) => { | ||
const to = !node.url.startsWith("http") | ||
? path.posix.join(directory, node.url) | ||
: node.url; | ||
|
@@ -106,7 +109,7 @@ | |
internal: !node.url.startsWith("http"), | ||
}; | ||
}, | ||
image: (node: any) => ({ | ||
from: from, | ||
to: path.posix.join(directory, node.url), | ||
toRaw: node.url, | ||
|
@@ -155,6 +158,40 @@ | |
return wikiLinks; | ||
}; | ||
|
||
export interface Task { | ||
description: string; | ||
checked: boolean; | ||
} | ||
|
||
export const extractTasks = (ast: Root) => { | ||
const nodes = selectAll("*", ast); | ||
const tasks: Task[] = []; | ||
nodes.map((node: any) => { | ||
if (node.type === "listItem") { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This looks like we will extract all list items as tasks which is not correct .... |
||
const description = recursivelyExtractText(node).trim(); | ||
const checked = node.checked; | ||
if (checked !== null) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @rufuspollock |
||
tasks.push({ | ||
description, | ||
checked, | ||
}); | ||
} | ||
} | ||
}); | ||
|
||
return tasks; | ||
}; | ||
|
||
function recursivelyExtractText(node: any) { | ||
if (node.value) { | ||
return node.value; | ||
} else if (node.children) { | ||
return node.children.map(recursivelyExtractText).join(" "); | ||
} else { | ||
return ""; | ||
} | ||
} | ||
|
||
// links = extractWikiLinks({ | ||
// source, | ||
// // TODO pass slug instead of file path as hrefs/srcs are sluggified too | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
import { extractTasks, processAST } from "../lib/parseFile"; | ||
|
||
const getTasksFromSource = (source: string) => { | ||
const ast = processAST(source, {}); | ||
const tasks = extractTasks(ast); | ||
return tasks; | ||
}; | ||
|
||
describe("extractTasks", () => { | ||
test("should extract uncompleted tasks from body", () => { | ||
const tasks = getTasksFromSource( | ||
"- [] uncompleted task 1\n- [ ] uncompleted task 2" | ||
); | ||
const expectedTasks = [ | ||
{ description: "uncompleted task 2", checked: false }, | ||
]; | ||
expect(tasks).toEqual(expectedTasks); | ||
}); | ||
|
||
test("should extract completed tasks from body", () => { | ||
const tasks = getTasksFromSource( | ||
"- [x] completed task 1\n- [X] completed task 2" | ||
); | ||
const expectedTasks = [ | ||
{ description: "completed task 1", checked: true }, | ||
{ description: "completed task 2", checked: true }, | ||
]; | ||
expect(tasks).toEqual(expectedTasks); | ||
}); | ||
|
||
test("should handle mixed completed and uncompleted tasks", () => { | ||
const tasks = getTasksFromSource( | ||
"- [x] completed task\n- [ ] uncompleted task" | ||
); | ||
const expectedTasks = [ | ||
{ description: "completed task", checked: true }, | ||
{ description: "uncompleted task", checked: false }, | ||
]; | ||
expect(tasks).toEqual(expectedTasks); | ||
}); | ||
|
||
test("should handle tasks with leading and trailing spaces", () => { | ||
const tasks = getTasksFromSource( | ||
"- [x] completed task \n- [ ] uncompleted task " | ||
); | ||
const expectedTasks = [ | ||
{ description: "completed task", checked: true }, | ||
{ description: "uncompleted task", checked: false }, | ||
]; | ||
expect(tasks).toEqual(expectedTasks); | ||
}); | ||
|
||
test("should handle tasks with different checkbox formats", () => { | ||
const tasks = getTasksFromSource( | ||
"- [x] task 1\n- [X] task 2\n- [ ] task 3" | ||
); | ||
const expectedTasks = [ | ||
{ description: "task 1", checked: true }, | ||
{ description: "task 2", checked: true }, | ||
{ description: "task 3", checked: false }, | ||
]; | ||
expect(tasks).toEqual(expectedTasks); | ||
}); | ||
|
||
test("should handle tasks with special characters", () => { | ||
const tasks = getTasksFromSource("- [x] task with $pecial character$"); | ||
const expectedTasks = [ | ||
{ description: "task with $pecial character$", checked: true }, | ||
]; | ||
expect(tasks).toEqual(expectedTasks); | ||
}); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Surely we need a pure list item ... which is not a task and check it is not showing up in our tasks list ...
We are in theory extracting tasks not just all list items
i.e. something like ...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, of course, I tested for those before committing.
Actually, this exact line
- [] uncompleted task 1
is a list item that's not being identified as a task because it's[]
and not[ ]
, i.e., missing a space between the brackets, thus not a valid task (not valid in Obsidian, Github markdown, or even remark-parse).There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mohamedsalem401 ok that wasn't obvious because of the name. 😄