-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
-
19
-
20
-
21
-
22
-
23
-
24
-
25
-
26
-
27
-
28
-
29
-
30
-
31
-
32
-
33
-
34
-
35
-
36
-
37
-
38
-
39
-
40
-
41
-
42
-
43
-
44
-
45
-
46
-
47
-
48
-
49
-
50
-
51
-
52
-
53
-
54
-
55
-
56
-
57
-
58
-
59
-
60
-
61
-
62
-
63
-
64
-
65
-
66
-
67
-
68
-
69
-
70
-
71
-
72
-
73
-
74
-
75
-
76
-
77
-
78
-
79
-
80
-
81
-
82
-
83
-
84
-
85
-
86
-
87
-
88
-
89
-
90
-
91
-
92
-
93
-
94
-
95
-
96
-
97
-
98
-
99
-
100
-
101
-
102
-
103
-
104
-
105
-
106
-
107
-
108
// SPDX-FileCopyrightText: 2024 Shota FUJI <pockawoooh@gmail.com>
//
// SPDX-License-Identifier: Apache-2.0
import { extname } from "../../deps/deno.land/std/path/mod.ts";
import type * as Mdast from "../../deps/npm/mdast/types.ts";
import type { ContentParser, ParseParameters } from "./interface.ts";
import type { DocumentContent } from "../types.ts";
import { isJSONCanvas, type JSONCanvas } from "./json_canvas/types.ts";
import { mapNodeAsync } from "./json_canvas/utils.ts";
import { parseMarkdown } from "./obsidian_markdown.ts";
const PROBABLY_URL_PATTERN = /^[a-z0-9]+:/i;
const SEPARATOR = "/";
export class JSONCanvasParseError extends Error {}
export class InvalidJSONCanvasError extends JSONCanvasParseError {
constructor() {
super("The data is not valid JSONCanvas data");
}
}
export class InvalidJSONError extends JSONCanvasParseError {
constructor(cause: unknown) {
super();
const subMessage = cause instanceof Error ? cause.message : String(cause);
this.message = `JSONCanvas data MUST be valid JSON string: ${subMessage}`;
this.cause = cause;
}
}
export type JSONCanvasDocument<T> = DocumentContent<
"json_canvas",
JSONCanvas<T>
>;
/**
* Content parser for JSONCanvas documents.
*
* This parser uses Obsidian Markdown parser internally.
*/
export class JSONCanvasParser
implements ContentParser<JSONCanvasDocument<Mdast.Nodes>> {
async parse(
{ fileReader, getDocumentToken, getAssetToken }: ParseParameters,
): Promise<JSONCanvasDocument<Mdast.Nodes>> {
const text = new TextDecoder().decode(await fileReader.read());
let json: unknown;
try {
json = JSON.parse(text);
} catch (err) {
throw new InvalidJSONError(err);
}
if (!isJSONCanvas(json)) {
throw new InvalidJSONCanvasError();
}
return {
kind: "json_canvas",
content: await mapNodeAsync(json, async (node) => {
switch (node.type) {
case "text": {
return {
...node,
text: await parseMarkdown(node.text, {
getAssetToken,
getDocumentToken,
}),
};
}
case "file": {
if (PROBABLY_URL_PATTERN.test(node.file)) {
return node;
}
const path = node.file.split(SEPARATOR);
const ext = extname(node.file);
const token = (!ext || /^\.md$/i.test(ext))
? await getDocumentToken(path)
: await getAssetToken(path);
return {
...node,
file: token,
};
}
default: {
return node;
}
}
}),
getHash(fragments) {
const n = fileReader.path.join(SEPARATOR);
throw new Error(
`You can't reference part of JSONCanvas via hash syntax.` +
`Requested ${n} # ${fragments.join(" > ")}`,
);
},
};
}
}