@cad0p/napkin 0.8.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/LICENSE +21 -0
- package/README.md +342 -0
- package/dist/commands/aliases.d.ts +7 -0
- package/dist/commands/aliases.js +25 -0
- package/dist/commands/bases.d.ts +23 -0
- package/dist/commands/bases.js +139 -0
- package/dist/commands/bookmarks.d.ts +15 -0
- package/dist/commands/bookmarks.js +51 -0
- package/dist/commands/canvas.d.ts +49 -0
- package/dist/commands/canvas.js +186 -0
- package/dist/commands/config.d.ts +13 -0
- package/dist/commands/config.js +48 -0
- package/dist/commands/crud.d.ts +40 -0
- package/dist/commands/crud.js +195 -0
- package/dist/commands/daily.d.ts +20 -0
- package/dist/commands/daily.js +58 -0
- package/dist/commands/files.d.ts +23 -0
- package/dist/commands/files.js +132 -0
- package/dist/commands/graph.d.ts +4 -0
- package/dist/commands/graph.js +461 -0
- package/dist/commands/init.d.ts +7 -0
- package/dist/commands/init.js +52 -0
- package/dist/commands/links.d.ts +26 -0
- package/dist/commands/links.js +119 -0
- package/dist/commands/outline.d.ts +7 -0
- package/dist/commands/outline.js +48 -0
- package/dist/commands/overview.d.ts +6 -0
- package/dist/commands/overview.js +40 -0
- package/dist/commands/properties.d.ts +24 -0
- package/dist/commands/properties.js +115 -0
- package/dist/commands/search.d.ts +13 -0
- package/dist/commands/search.js +48 -0
- package/dist/commands/tags.d.ts +13 -0
- package/dist/commands/tags.js +51 -0
- package/dist/commands/tasks.d.ts +22 -0
- package/dist/commands/tasks.js +106 -0
- package/dist/commands/templates.d.ts +16 -0
- package/dist/commands/templates.js +70 -0
- package/dist/commands/vault.d.ts +4 -0
- package/dist/commands/vault.js +17 -0
- package/dist/commands/wordcount.d.ts +7 -0
- package/dist/commands/wordcount.js +43 -0
- package/dist/core/aliases.d.ts +5 -0
- package/dist/core/aliases.js +26 -0
- package/dist/core/bases.d.ts +29 -0
- package/dist/core/bases.js +67 -0
- package/dist/core/bookmarks.d.ts +14 -0
- package/dist/core/bookmarks.js +34 -0
- package/dist/core/canvas.d.ts +74 -0
- package/dist/core/canvas.js +125 -0
- package/dist/core/config.d.ts +7 -0
- package/dist/core/config.js +35 -0
- package/dist/core/crud.d.ts +32 -0
- package/dist/core/crud.js +119 -0
- package/dist/core/daily.d.ts +12 -0
- package/dist/core/daily.js +102 -0
- package/dist/core/files.d.ts +15 -0
- package/dist/core/files.js +30 -0
- package/dist/core/init.d.ts +31 -0
- package/dist/core/init.js +119 -0
- package/dist/core/links.d.ts +11 -0
- package/dist/core/links.js +66 -0
- package/dist/core/outline.d.ts +3 -0
- package/dist/core/outline.js +12 -0
- package/dist/core/overview.d.ts +15 -0
- package/dist/core/overview.js +384 -0
- package/dist/core/properties.d.ts +14 -0
- package/dist/core/properties.js +60 -0
- package/dist/core/search.d.ts +17 -0
- package/dist/core/search.js +153 -0
- package/dist/core/tags.d.ts +11 -0
- package/dist/core/tags.js +40 -0
- package/dist/core/tasks.d.ts +35 -0
- package/dist/core/tasks.js +97 -0
- package/dist/core/templates.d.ts +14 -0
- package/dist/core/templates.js +55 -0
- package/dist/core/vault.d.ts +10 -0
- package/dist/core/vault.js +37 -0
- package/dist/core/wordcount.d.ts +5 -0
- package/dist/core/wordcount.js +16 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.js +1 -0
- package/dist/main.d.ts +2 -0
- package/dist/main.js +715 -0
- package/dist/sdk.d.ts +179 -0
- package/dist/sdk.js +232 -0
- package/dist/templates/coding.d.ts +2 -0
- package/dist/templates/coding.js +104 -0
- package/dist/templates/company.d.ts +2 -0
- package/dist/templates/company.js +121 -0
- package/dist/templates/index.d.ts +4 -0
- package/dist/templates/index.js +15 -0
- package/dist/templates/personal.d.ts +2 -0
- package/dist/templates/personal.js +91 -0
- package/dist/templates/product.d.ts +2 -0
- package/dist/templates/product.js +123 -0
- package/dist/templates/research.d.ts +2 -0
- package/dist/templates/research.js +114 -0
- package/dist/templates/types.d.ts +7 -0
- package/dist/templates/types.js +1 -0
- package/dist/utils/bases.d.ts +61 -0
- package/dist/utils/bases.js +661 -0
- package/dist/utils/config.d.ts +42 -0
- package/dist/utils/config.js +112 -0
- package/dist/utils/exit-codes.d.ts +5 -0
- package/dist/utils/exit-codes.js +5 -0
- package/dist/utils/files.d.ts +135 -0
- package/dist/utils/files.js +299 -0
- package/dist/utils/formula.d.ts +28 -0
- package/dist/utils/formula.js +462 -0
- package/dist/utils/frontmatter.d.ts +17 -0
- package/dist/utils/frontmatter.js +34 -0
- package/dist/utils/markdown.d.ts +31 -0
- package/dist/utils/markdown.js +80 -0
- package/dist/utils/output.d.ts +28 -0
- package/dist/utils/output.js +48 -0
- package/dist/utils/search-cache.d.ts +29 -0
- package/dist/utils/search-cache.js +41 -0
- package/dist/utils/test-helpers.d.ts +13 -0
- package/dist/utils/test-helpers.js +40 -0
- package/dist/utils/vault.d.ts +21 -0
- package/dist/utils/vault.js +144 -0
- package/package.json +76 -0
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { Napkin } from "../sdk.js";
|
|
2
|
+
import { EXIT_NOT_FOUND, EXIT_USER_ERROR } from "../utils/exit-codes.js";
|
|
3
|
+
import { suggestFile } from "../utils/files.js";
|
|
4
|
+
import { dim, error, fileNotFound, output, } from "../utils/output.js";
|
|
5
|
+
export async function backlinks(opts) {
|
|
6
|
+
const n = new Napkin(opts.vault || process.cwd());
|
|
7
|
+
if (!opts.file) {
|
|
8
|
+
error("No file specified. Use --file <name>");
|
|
9
|
+
process.exit(EXIT_USER_ERROR);
|
|
10
|
+
}
|
|
11
|
+
let links;
|
|
12
|
+
try {
|
|
13
|
+
links = n.linksBack(opts.file);
|
|
14
|
+
}
|
|
15
|
+
catch (e) {
|
|
16
|
+
const msg = e.message;
|
|
17
|
+
if (msg.startsWith("File not found:")) {
|
|
18
|
+
fileNotFound(opts.file, suggestFile(n.vault.contentPath, opts.file));
|
|
19
|
+
process.exit(EXIT_NOT_FOUND);
|
|
20
|
+
}
|
|
21
|
+
throw e;
|
|
22
|
+
}
|
|
23
|
+
output(opts, {
|
|
24
|
+
json: () => (opts.total ? { total: links.length } : { backlinks: links }),
|
|
25
|
+
human: () => {
|
|
26
|
+
if (opts.total)
|
|
27
|
+
console.log(links.length);
|
|
28
|
+
else
|
|
29
|
+
for (const l of links)
|
|
30
|
+
console.log(l);
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
export async function links(opts) {
|
|
35
|
+
const n = new Napkin(opts.vault || process.cwd());
|
|
36
|
+
if (!opts.file) {
|
|
37
|
+
error("No file specified. Use --file <name>");
|
|
38
|
+
process.exit(EXIT_USER_ERROR);
|
|
39
|
+
}
|
|
40
|
+
let outgoing;
|
|
41
|
+
try {
|
|
42
|
+
outgoing = n.linksOut(opts.file);
|
|
43
|
+
}
|
|
44
|
+
catch (e) {
|
|
45
|
+
const msg = e.message;
|
|
46
|
+
if (msg.startsWith("File not found:")) {
|
|
47
|
+
fileNotFound(opts.file, suggestFile(n.vault.contentPath, opts.file));
|
|
48
|
+
process.exit(EXIT_NOT_FOUND);
|
|
49
|
+
}
|
|
50
|
+
throw e;
|
|
51
|
+
}
|
|
52
|
+
output(opts, {
|
|
53
|
+
json: () => (opts.total ? { total: outgoing.length } : { links: outgoing }),
|
|
54
|
+
human: () => {
|
|
55
|
+
if (opts.total)
|
|
56
|
+
console.log(outgoing.length);
|
|
57
|
+
else
|
|
58
|
+
for (const l of outgoing)
|
|
59
|
+
console.log(l);
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
export async function unresolvedLinks(opts) {
|
|
64
|
+
const n = new Napkin(opts.vault || process.cwd());
|
|
65
|
+
const entries = n.linksUnresolved();
|
|
66
|
+
output(opts, {
|
|
67
|
+
json: () => {
|
|
68
|
+
if (opts.total)
|
|
69
|
+
return { total: entries.length };
|
|
70
|
+
if (opts.counts || opts.verbose)
|
|
71
|
+
return {
|
|
72
|
+
unresolved: Object.fromEntries(entries.map(([k, v]) => [k, opts.verbose ? v : v.length])),
|
|
73
|
+
};
|
|
74
|
+
return { unresolved: entries.map(([k]) => k) };
|
|
75
|
+
},
|
|
76
|
+
human: () => {
|
|
77
|
+
if (opts.total) {
|
|
78
|
+
console.log(entries.length);
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
for (const [target, sources] of entries) {
|
|
82
|
+
console.log(opts.counts ? `${target}\t${sources.length}` : target);
|
|
83
|
+
if (opts.verbose) {
|
|
84
|
+
for (const s of sources)
|
|
85
|
+
console.log(` ${dim(s)}`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
export async function orphans(opts) {
|
|
93
|
+
const n = new Napkin(opts.vault || process.cwd());
|
|
94
|
+
const result = n.orphans();
|
|
95
|
+
output(opts, {
|
|
96
|
+
json: () => (opts.total ? { total: result.length } : { orphans: result }),
|
|
97
|
+
human: () => {
|
|
98
|
+
if (opts.total)
|
|
99
|
+
console.log(result.length);
|
|
100
|
+
else
|
|
101
|
+
for (const f of result)
|
|
102
|
+
console.log(f);
|
|
103
|
+
},
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
export async function deadends(opts) {
|
|
107
|
+
const n = new Napkin(opts.vault || process.cwd());
|
|
108
|
+
const result = n.deadends();
|
|
109
|
+
output(opts, {
|
|
110
|
+
json: () => (opts.total ? { total: result.length } : { deadends: result }),
|
|
111
|
+
human: () => {
|
|
112
|
+
if (opts.total)
|
|
113
|
+
console.log(result.length);
|
|
114
|
+
else
|
|
115
|
+
for (const f of result)
|
|
116
|
+
console.log(f);
|
|
117
|
+
},
|
|
118
|
+
});
|
|
119
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { Napkin } from "../sdk.js";
|
|
2
|
+
import { EXIT_NOT_FOUND, EXIT_USER_ERROR } from "../utils/exit-codes.js";
|
|
3
|
+
import { suggestFile } from "../utils/files.js";
|
|
4
|
+
import { error, fileNotFound, output, } from "../utils/output.js";
|
|
5
|
+
export async function outline(opts) {
|
|
6
|
+
const n = new Napkin(opts.vault || process.cwd());
|
|
7
|
+
if (!opts.file) {
|
|
8
|
+
error("No file specified. Use --file <name>");
|
|
9
|
+
process.exit(EXIT_USER_ERROR);
|
|
10
|
+
}
|
|
11
|
+
let headings;
|
|
12
|
+
try {
|
|
13
|
+
headings = n.outline(opts.file);
|
|
14
|
+
}
|
|
15
|
+
catch (e) {
|
|
16
|
+
const msg = e.message;
|
|
17
|
+
if (msg.startsWith("File not found:")) {
|
|
18
|
+
fileNotFound(opts.file, suggestFile(n.vault.contentPath, opts.file));
|
|
19
|
+
process.exit(EXIT_NOT_FOUND);
|
|
20
|
+
}
|
|
21
|
+
throw e;
|
|
22
|
+
}
|
|
23
|
+
output(opts, {
|
|
24
|
+
json: () => (opts.total ? { total: headings.length } : { headings }),
|
|
25
|
+
human: () => {
|
|
26
|
+
if (opts.total) {
|
|
27
|
+
console.log(headings.length);
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
const fmt = opts.format || "tree";
|
|
31
|
+
if (fmt === "json") {
|
|
32
|
+
console.log(JSON.stringify(headings, null, 2));
|
|
33
|
+
}
|
|
34
|
+
else if (fmt === "md") {
|
|
35
|
+
for (const h of headings) {
|
|
36
|
+
console.log(`${"#".repeat(h.level)} ${h.text}`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
// tree format
|
|
41
|
+
for (const h of headings) {
|
|
42
|
+
const indent = " ".repeat(h.level - 1);
|
|
43
|
+
console.log(`${indent}${h.text}`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
});
|
|
48
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Napkin } from "../sdk.js";
|
|
2
|
+
import { bold, dim, output, warn, } from "../utils/output.js";
|
|
3
|
+
export async function overview(opts) {
|
|
4
|
+
const n = new Napkin(opts.vault || process.cwd());
|
|
5
|
+
const result = n.overview({
|
|
6
|
+
depth: opts.depth ? Number.parseInt(opts.depth, 10) : undefined,
|
|
7
|
+
keywords: opts.keywords ? Number.parseInt(opts.keywords, 10) : undefined,
|
|
8
|
+
});
|
|
9
|
+
for (const w of result.warnings ?? []) {
|
|
10
|
+
warn(w);
|
|
11
|
+
}
|
|
12
|
+
output(opts, {
|
|
13
|
+
json: () => result,
|
|
14
|
+
human: () => {
|
|
15
|
+
console.log(dim("WORKFLOW: overview (you are here) → search <query> → read <file>"));
|
|
16
|
+
console.log("");
|
|
17
|
+
if (result.context) {
|
|
18
|
+
console.log(bold("CONTEXT"));
|
|
19
|
+
console.log(result.context);
|
|
20
|
+
console.log("");
|
|
21
|
+
}
|
|
22
|
+
if (result.overview.length === 0) {
|
|
23
|
+
console.log("Empty vault");
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
for (const f of result.overview) {
|
|
27
|
+
console.log(bold(f.path === "/" ? "./" : `${f.path}/`));
|
|
28
|
+
if (f.keywords.length > 0) {
|
|
29
|
+
console.log(` ${dim("keywords:")} ${f.keywords.join(", ")}`);
|
|
30
|
+
}
|
|
31
|
+
if (f.tags.length > 0) {
|
|
32
|
+
console.log(` ${dim("tags:")} ${f.tags.map((t) => `#${t}`).join(", ")}`);
|
|
33
|
+
}
|
|
34
|
+
console.log(` ${dim("notes:")} ${f.notes}`);
|
|
35
|
+
}
|
|
36
|
+
console.log("");
|
|
37
|
+
console.log(dim("HINT: Use napkin search <query> to find specific content. Use napkin read <file> to open a file."));
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { type OutputOptions } from "../utils/output.js";
|
|
2
|
+
export declare function properties(opts: OutputOptions & {
|
|
3
|
+
vault?: string;
|
|
4
|
+
file?: string;
|
|
5
|
+
counts?: boolean;
|
|
6
|
+
total?: boolean;
|
|
7
|
+
sort?: string;
|
|
8
|
+
}): Promise<void>;
|
|
9
|
+
export declare function propertySet(opts: OutputOptions & {
|
|
10
|
+
vault?: string;
|
|
11
|
+
file?: string;
|
|
12
|
+
name?: string;
|
|
13
|
+
value?: string;
|
|
14
|
+
}): Promise<void>;
|
|
15
|
+
export declare function propertyRemove(opts: OutputOptions & {
|
|
16
|
+
vault?: string;
|
|
17
|
+
file?: string;
|
|
18
|
+
name?: string;
|
|
19
|
+
}): Promise<void>;
|
|
20
|
+
export declare function propertyRead(opts: OutputOptions & {
|
|
21
|
+
vault?: string;
|
|
22
|
+
file?: string;
|
|
23
|
+
name?: string;
|
|
24
|
+
}): Promise<void>;
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { Napkin } from "../sdk.js";
|
|
2
|
+
import { EXIT_NOT_FOUND, EXIT_USER_ERROR } from "../utils/exit-codes.js";
|
|
3
|
+
import { suggestFile } from "../utils/files.js";
|
|
4
|
+
import { error, fileNotFound, output, success, } from "../utils/output.js";
|
|
5
|
+
export async function properties(opts) {
|
|
6
|
+
const n = new Napkin(opts.vault || process.cwd());
|
|
7
|
+
const propCounts = n.properties(opts.file);
|
|
8
|
+
const entries = [...propCounts.entries()];
|
|
9
|
+
if (opts.sort === "count") {
|
|
10
|
+
entries.sort((a, b) => b[1] - a[1]);
|
|
11
|
+
}
|
|
12
|
+
else {
|
|
13
|
+
entries.sort((a, b) => a[0].localeCompare(b[0]));
|
|
14
|
+
}
|
|
15
|
+
output(opts, {
|
|
16
|
+
json: () => {
|
|
17
|
+
if (opts.total)
|
|
18
|
+
return { total: entries.length };
|
|
19
|
+
if (opts.counts)
|
|
20
|
+
return { properties: Object.fromEntries(entries) };
|
|
21
|
+
return { properties: entries.map(([p]) => p) };
|
|
22
|
+
},
|
|
23
|
+
human: () => {
|
|
24
|
+
if (opts.total) {
|
|
25
|
+
console.log(entries.length);
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
for (const [prop, count] of entries) {
|
|
29
|
+
console.log(opts.counts ? `${prop}\t${count}` : prop);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
export async function propertySet(opts) {
|
|
36
|
+
const n = new Napkin(opts.vault || process.cwd());
|
|
37
|
+
if (!opts.name || opts.value === undefined) {
|
|
38
|
+
error("Usage: property:set --name <name> --value <value> --file <file>");
|
|
39
|
+
process.exit(EXIT_USER_ERROR);
|
|
40
|
+
}
|
|
41
|
+
if (!opts.file) {
|
|
42
|
+
error("No file specified. Use --file <name>");
|
|
43
|
+
process.exit(EXIT_USER_ERROR);
|
|
44
|
+
}
|
|
45
|
+
let result;
|
|
46
|
+
try {
|
|
47
|
+
result = n.propertySet(opts.file, opts.name, opts.value);
|
|
48
|
+
}
|
|
49
|
+
catch (e) {
|
|
50
|
+
const msg = e.message;
|
|
51
|
+
if (msg.startsWith("File not found:")) {
|
|
52
|
+
fileNotFound(opts.file, suggestFile(n.vault.contentPath, opts.file));
|
|
53
|
+
process.exit(EXIT_NOT_FOUND);
|
|
54
|
+
}
|
|
55
|
+
throw e;
|
|
56
|
+
}
|
|
57
|
+
output(opts, {
|
|
58
|
+
json: () => result,
|
|
59
|
+
human: () => success(`Set ${result.property} = ${opts.value} on ${result.path}`),
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
export async function propertyRemove(opts) {
|
|
63
|
+
const n = new Napkin(opts.vault || process.cwd());
|
|
64
|
+
if (!opts.name) {
|
|
65
|
+
error("No property name specified. Use --name <name>");
|
|
66
|
+
process.exit(EXIT_USER_ERROR);
|
|
67
|
+
}
|
|
68
|
+
if (!opts.file) {
|
|
69
|
+
error("No file specified. Use --file <name>");
|
|
70
|
+
process.exit(EXIT_USER_ERROR);
|
|
71
|
+
}
|
|
72
|
+
let result;
|
|
73
|
+
try {
|
|
74
|
+
result = n.propertyRemove(opts.file, opts.name);
|
|
75
|
+
}
|
|
76
|
+
catch (e) {
|
|
77
|
+
const msg = e.message;
|
|
78
|
+
if (msg.startsWith("File not found:")) {
|
|
79
|
+
fileNotFound(opts.file, suggestFile(n.vault.contentPath, opts.file));
|
|
80
|
+
process.exit(EXIT_NOT_FOUND);
|
|
81
|
+
}
|
|
82
|
+
throw e;
|
|
83
|
+
}
|
|
84
|
+
output(opts, {
|
|
85
|
+
json: () => result,
|
|
86
|
+
human: () => success(`Removed ${result.removed} from ${result.path}`),
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
export async function propertyRead(opts) {
|
|
90
|
+
const n = new Napkin(opts.vault || process.cwd());
|
|
91
|
+
if (!opts.name) {
|
|
92
|
+
error("No property name specified. Use --name <name>");
|
|
93
|
+
process.exit(EXIT_USER_ERROR);
|
|
94
|
+
}
|
|
95
|
+
if (!opts.file) {
|
|
96
|
+
error("No file specified. Use --file <name>");
|
|
97
|
+
process.exit(EXIT_USER_ERROR);
|
|
98
|
+
}
|
|
99
|
+
let result;
|
|
100
|
+
try {
|
|
101
|
+
result = n.propertyGet(opts.file, opts.name);
|
|
102
|
+
}
|
|
103
|
+
catch (e) {
|
|
104
|
+
const msg = e.message;
|
|
105
|
+
if (msg.startsWith("File not found:")) {
|
|
106
|
+
fileNotFound(opts.file, suggestFile(n.vault.contentPath, opts.file));
|
|
107
|
+
process.exit(EXIT_NOT_FOUND);
|
|
108
|
+
}
|
|
109
|
+
throw e;
|
|
110
|
+
}
|
|
111
|
+
output(opts, {
|
|
112
|
+
json: () => result,
|
|
113
|
+
human: () => console.log(result.value !== null ? String(result.value) : ""),
|
|
114
|
+
});
|
|
115
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type OutputOptions } from "../utils/output.js";
|
|
2
|
+
interface SearchOpts extends OutputOptions {
|
|
3
|
+
vault?: string;
|
|
4
|
+
query?: string;
|
|
5
|
+
path?: string;
|
|
6
|
+
limit?: string;
|
|
7
|
+
total?: boolean;
|
|
8
|
+
snippetLines?: string;
|
|
9
|
+
snippets?: boolean;
|
|
10
|
+
score?: boolean;
|
|
11
|
+
}
|
|
12
|
+
export declare function search(opts: SearchOpts): Promise<void>;
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { Napkin } from "../sdk.js";
|
|
2
|
+
import { EXIT_USER_ERROR } from "../utils/exit-codes.js";
|
|
3
|
+
import { bold, dim, error, output, } from "../utils/output.js";
|
|
4
|
+
export async function search(opts) {
|
|
5
|
+
const n = new Napkin(opts.vault || process.cwd());
|
|
6
|
+
if (!opts.query) {
|
|
7
|
+
error("No query specified. Use --query <text>");
|
|
8
|
+
process.exit(EXIT_USER_ERROR);
|
|
9
|
+
}
|
|
10
|
+
const top = n.search(opts.query, {
|
|
11
|
+
path: opts.path,
|
|
12
|
+
limit: opts.limit ? Number.parseInt(opts.limit, 10) : undefined,
|
|
13
|
+
snippetLines: opts.snippetLines
|
|
14
|
+
? Number.parseInt(opts.snippetLines, 10)
|
|
15
|
+
: undefined,
|
|
16
|
+
snippets: opts.snippets,
|
|
17
|
+
});
|
|
18
|
+
output(opts, {
|
|
19
|
+
json: () => {
|
|
20
|
+
if (opts.total)
|
|
21
|
+
return { total: top.length };
|
|
22
|
+
const mapResult = (r) => {
|
|
23
|
+
const { score: _score, snippets, ...rest } = r;
|
|
24
|
+
const out = { ...rest };
|
|
25
|
+
if (opts.score)
|
|
26
|
+
out.score = r.score;
|
|
27
|
+
if (opts.snippets !== false)
|
|
28
|
+
out.snippets = snippets;
|
|
29
|
+
return out;
|
|
30
|
+
};
|
|
31
|
+
return { results: top.map(mapResult) };
|
|
32
|
+
},
|
|
33
|
+
human: () => {
|
|
34
|
+
if (opts.total) {
|
|
35
|
+
console.log(top.length);
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
for (const r of top) {
|
|
39
|
+
console.log(`${bold(r.file)} ${dim(`(${opts.score ? `score: ${r.score}, ` : ""}links: ${r.links}, modified: ${r.modified})`)}`);
|
|
40
|
+
for (const s of r.snippets) {
|
|
41
|
+
console.log(` ${dim(`${s.line}:`)} ${s.text}`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
console.log("");
|
|
45
|
+
console.log(dim("HINT: Use napkin read <file> to open a full file. Use napkin outline --file <file> to see its structure."));
|
|
46
|
+
},
|
|
47
|
+
});
|
|
48
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type OutputOptions } from "../utils/output.js";
|
|
2
|
+
export declare function tags(opts: OutputOptions & {
|
|
3
|
+
vault?: string;
|
|
4
|
+
file?: string;
|
|
5
|
+
counts?: boolean;
|
|
6
|
+
total?: boolean;
|
|
7
|
+
sort?: string;
|
|
8
|
+
}): Promise<void>;
|
|
9
|
+
export declare function tag(opts: OutputOptions & {
|
|
10
|
+
vault?: string;
|
|
11
|
+
name?: string;
|
|
12
|
+
verbose?: boolean;
|
|
13
|
+
}): Promise<void>;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { Napkin } from "../sdk.js";
|
|
2
|
+
import { EXIT_USER_ERROR } from "../utils/exit-codes.js";
|
|
3
|
+
import { bold, dim, error, output, } from "../utils/output.js";
|
|
4
|
+
export async function tags(opts) {
|
|
5
|
+
const n = new Napkin(opts.vault || process.cwd());
|
|
6
|
+
const { tagCounts } = n.tags(opts.file);
|
|
7
|
+
const entries = [...tagCounts.entries()];
|
|
8
|
+
if (opts.sort === "count") {
|
|
9
|
+
entries.sort((a, b) => b[1] - a[1]);
|
|
10
|
+
}
|
|
11
|
+
else {
|
|
12
|
+
entries.sort((a, b) => a[0].localeCompare(b[0]));
|
|
13
|
+
}
|
|
14
|
+
output(opts, {
|
|
15
|
+
json: () => {
|
|
16
|
+
if (opts.total)
|
|
17
|
+
return { total: entries.length };
|
|
18
|
+
if (opts.counts)
|
|
19
|
+
return { tags: Object.fromEntries(entries) };
|
|
20
|
+
return { tags: entries.map(([t]) => t) };
|
|
21
|
+
},
|
|
22
|
+
human: () => {
|
|
23
|
+
if (opts.total) {
|
|
24
|
+
console.log(entries.length);
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
for (const [tag, count] of entries) {
|
|
28
|
+
console.log(opts.counts ? `${tag}\t${count}` : tag);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
export async function tag(opts) {
|
|
35
|
+
const n = new Napkin(opts.vault || process.cwd());
|
|
36
|
+
if (!opts.name) {
|
|
37
|
+
error("No tag name specified. Use --name <tag>");
|
|
38
|
+
process.exit(EXIT_USER_ERROR);
|
|
39
|
+
}
|
|
40
|
+
const { tag: _tag, count, files } = n.tagInfo(opts.name);
|
|
41
|
+
output(opts, {
|
|
42
|
+
json: () => ({ tag: opts.name, count, ...(opts.verbose ? { files } : {}) }),
|
|
43
|
+
human: () => {
|
|
44
|
+
console.log(`${bold(opts.name)} ${count} occurrence${count !== 1 ? "s" : ""}`);
|
|
45
|
+
if (opts.verbose) {
|
|
46
|
+
for (const f of files)
|
|
47
|
+
console.log(` ${dim(f)}`);
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type OutputOptions } from "../utils/output.js";
|
|
2
|
+
export declare function tasks(opts: OutputOptions & {
|
|
3
|
+
vault?: string;
|
|
4
|
+
file?: string;
|
|
5
|
+
done?: boolean;
|
|
6
|
+
todo?: boolean;
|
|
7
|
+
total?: boolean;
|
|
8
|
+
verbose?: boolean;
|
|
9
|
+
daily?: boolean;
|
|
10
|
+
status?: string;
|
|
11
|
+
}): Promise<void>;
|
|
12
|
+
export declare function task(opts: OutputOptions & {
|
|
13
|
+
vault?: string;
|
|
14
|
+
file?: string;
|
|
15
|
+
line?: string;
|
|
16
|
+
ref?: string;
|
|
17
|
+
toggle?: boolean;
|
|
18
|
+
done?: boolean;
|
|
19
|
+
todo?: boolean;
|
|
20
|
+
status?: string;
|
|
21
|
+
daily?: boolean;
|
|
22
|
+
}): Promise<void>;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { resolveTaskLocation } from "../core/tasks.js";
|
|
2
|
+
import { Napkin } from "../sdk.js";
|
|
3
|
+
import { EXIT_NOT_FOUND, EXIT_USER_ERROR } from "../utils/exit-codes.js";
|
|
4
|
+
import { suggestFile } from "../utils/files.js";
|
|
5
|
+
import { bold, dim, error, fileNotFound, output, } from "../utils/output.js";
|
|
6
|
+
export async function tasks(opts) {
|
|
7
|
+
const n = new Napkin(opts.vault || process.cwd());
|
|
8
|
+
const result = n.tasks({
|
|
9
|
+
file: opts.file,
|
|
10
|
+
daily: opts.daily,
|
|
11
|
+
done: opts.done,
|
|
12
|
+
todo: opts.todo,
|
|
13
|
+
status: opts.status,
|
|
14
|
+
});
|
|
15
|
+
output(opts, {
|
|
16
|
+
json: () => (opts.total ? { total: result.length } : { tasks: result }),
|
|
17
|
+
human: () => {
|
|
18
|
+
if (opts.total) {
|
|
19
|
+
console.log(result.length);
|
|
20
|
+
}
|
|
21
|
+
else if (opts.verbose) {
|
|
22
|
+
const byFile = new Map();
|
|
23
|
+
for (const t of result) {
|
|
24
|
+
if (!byFile.has(t.file))
|
|
25
|
+
byFile.set(t.file, []);
|
|
26
|
+
byFile.get(t.file)?.push(t);
|
|
27
|
+
}
|
|
28
|
+
for (const [file, tasks] of byFile) {
|
|
29
|
+
console.log(bold(file));
|
|
30
|
+
for (const t of tasks) {
|
|
31
|
+
console.log(` ${dim(`${t.line}:`)} [${t.status}] ${t.text}`);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
for (const t of result) {
|
|
37
|
+
console.log(`[${t.status}] ${t.text}`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
export async function task(opts) {
|
|
44
|
+
const n = new Napkin(opts.vault || process.cwd());
|
|
45
|
+
let filePath;
|
|
46
|
+
let lineNum;
|
|
47
|
+
try {
|
|
48
|
+
({ filePath, lineNum } = resolveTaskLocation(n.vault, opts));
|
|
49
|
+
}
|
|
50
|
+
catch (e) {
|
|
51
|
+
const msg = e.message;
|
|
52
|
+
if (msg.includes("File not found")) {
|
|
53
|
+
const ref = opts.ref?.split(":")[0] || opts.file || "";
|
|
54
|
+
fileNotFound(ref, suggestFile(n.vault.contentPath, ref));
|
|
55
|
+
process.exit(EXIT_NOT_FOUND);
|
|
56
|
+
}
|
|
57
|
+
error(msg);
|
|
58
|
+
process.exit(EXIT_USER_ERROR);
|
|
59
|
+
}
|
|
60
|
+
let taskInfo;
|
|
61
|
+
try {
|
|
62
|
+
taskInfo = n.taskShow(filePath, lineNum);
|
|
63
|
+
}
|
|
64
|
+
catch (e) {
|
|
65
|
+
const msg = e.message;
|
|
66
|
+
error(msg);
|
|
67
|
+
process.exit(msg.includes("is not a task") ? EXIT_USER_ERROR : EXIT_NOT_FOUND);
|
|
68
|
+
}
|
|
69
|
+
const { currentStatus } = taskInfo;
|
|
70
|
+
const isMutating = opts.toggle || opts.done || opts.todo || opts.status;
|
|
71
|
+
if (isMutating) {
|
|
72
|
+
let newStatus;
|
|
73
|
+
if (opts.status)
|
|
74
|
+
newStatus = opts.status;
|
|
75
|
+
else if (opts.done)
|
|
76
|
+
newStatus = "x";
|
|
77
|
+
else if (opts.todo)
|
|
78
|
+
newStatus = " ";
|
|
79
|
+
else if (opts.toggle)
|
|
80
|
+
newStatus = currentStatus === " " ? "x" : " ";
|
|
81
|
+
else
|
|
82
|
+
newStatus = currentStatus;
|
|
83
|
+
const result = n.taskUpdate(filePath, lineNum, newStatus);
|
|
84
|
+
output(opts, {
|
|
85
|
+
json: () => result,
|
|
86
|
+
human: () => console.log(`[${result.status}] ${result.text}`),
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
output(opts, {
|
|
91
|
+
json: () => ({
|
|
92
|
+
file: filePath,
|
|
93
|
+
line: lineNum,
|
|
94
|
+
status: currentStatus,
|
|
95
|
+
text: taskInfo.text,
|
|
96
|
+
done: currentStatus === "x" || currentStatus === "X",
|
|
97
|
+
}),
|
|
98
|
+
human: () => {
|
|
99
|
+
console.log(`${dim("file")} ${filePath}`);
|
|
100
|
+
console.log(`${dim("line")} ${lineNum}`);
|
|
101
|
+
console.log(`${dim("status")} [${currentStatus}]`);
|
|
102
|
+
console.log(`${dim("text")} ${taskInfo.text}`);
|
|
103
|
+
},
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type OutputOptions } from "../utils/output.js";
|
|
2
|
+
export declare function templates(opts: OutputOptions & {
|
|
3
|
+
vault?: string;
|
|
4
|
+
total?: boolean;
|
|
5
|
+
}): Promise<void>;
|
|
6
|
+
export declare function templateRead(opts: OutputOptions & {
|
|
7
|
+
vault?: string;
|
|
8
|
+
name?: string;
|
|
9
|
+
resolve?: boolean;
|
|
10
|
+
title?: string;
|
|
11
|
+
}): Promise<void>;
|
|
12
|
+
export declare function templateInsert(opts: OutputOptions & {
|
|
13
|
+
vault?: string;
|
|
14
|
+
name?: string;
|
|
15
|
+
file?: string;
|
|
16
|
+
}): Promise<void>;
|