todoosy 0.1.0

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.
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Todoosy Formatter
3
+ */
4
+ export declare function format(text: string): string;
5
+ //# sourceMappingURL=formatter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formatter.d.ts","sourceRoot":"","sources":["../src/formatter.ts"],"names":[],"mappings":"AAAA;;GAEG;AAwDH,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CA2G3C"}
@@ -0,0 +1,134 @@
1
+ /**
2
+ * Todoosy Formatter
3
+ */
4
+ import { parse } from './parser.js';
5
+ function formatMetadata(metadata) {
6
+ const parts = [];
7
+ if (metadata.due) {
8
+ parts.push(`due ${metadata.due}`);
9
+ }
10
+ if (metadata.priority !== null) {
11
+ parts.push(`p${metadata.priority}`);
12
+ }
13
+ if (metadata.estimate_minutes !== null) {
14
+ const minutes = metadata.estimate_minutes;
15
+ if (minutes % 480 === 0 && minutes >= 480) {
16
+ parts.push(`${minutes / 480}d`);
17
+ }
18
+ else if (minutes % 60 === 0 && minutes >= 60) {
19
+ parts.push(`${minutes / 60}h`);
20
+ }
21
+ else {
22
+ parts.push(`${minutes}m`);
23
+ }
24
+ }
25
+ return parts.length > 0 ? `(${parts.join(' ')})` : '';
26
+ }
27
+ function formatItemLine(item, indent = 0) {
28
+ const indentStr = ' '.repeat(indent);
29
+ const metaStr = formatMetadata(item.metadata);
30
+ const titleWithMeta = metaStr ? `${item.title_text} ${metaStr}` : item.title_text;
31
+ if (item.type === 'heading') {
32
+ const hashes = '#'.repeat(item.level || 1);
33
+ return `${hashes} ${titleWithMeta}`;
34
+ }
35
+ return `${indentStr}- ${titleWithMeta}`;
36
+ }
37
+ function formatComments(comments, isListItem, indent) {
38
+ if (comments.length === 0)
39
+ return [];
40
+ if (isListItem) {
41
+ // Indent is the list item's indent level; comments need +1 level
42
+ const indentStr = ' '.repeat(indent + 1);
43
+ return comments.map(c => `${indentStr}${c}`);
44
+ }
45
+ // Heading comments are not indented
46
+ return comments;
47
+ }
48
+ export function format(text) {
49
+ const { ast } = parse(text);
50
+ const lines = [];
51
+ const itemMap = new Map();
52
+ for (const item of ast.items) {
53
+ itemMap.set(item.id, item);
54
+ }
55
+ // Track Misc section
56
+ let miscSectionId = null;
57
+ // Find existing Misc section
58
+ for (const item of ast.items) {
59
+ if (item.type === 'heading' && item.title_text === 'Misc' && item.level === 1) {
60
+ miscSectionId = item.id;
61
+ break;
62
+ }
63
+ }
64
+ // Helper to format an item and its subtree
65
+ function formatItem(id, listIndent = 0, isUnderMisc = false) {
66
+ const item = itemMap.get(id);
67
+ // Skip Misc section during normal iteration (we'll add it at the end)
68
+ if (item.id === miscSectionId && !isUnderMisc) {
69
+ return;
70
+ }
71
+ // Add blank line before headings (except at start)
72
+ if (item.type === 'heading' && lines.length > 0) {
73
+ if (lines[lines.length - 1] !== '') {
74
+ lines.push('');
75
+ }
76
+ }
77
+ lines.push(formatItemLine(item, listIndent));
78
+ // Add blank line after heading before comments or children
79
+ if (item.type === 'heading') {
80
+ lines.push('');
81
+ }
82
+ // Add comments
83
+ const formattedComments = formatComments(item.comments, item.type === 'list', listIndent);
84
+ lines.push(...formattedComments);
85
+ // Add blank line after heading comments before children
86
+ if (item.type === 'heading' && item.comments.length > 0 && item.children.length > 0) {
87
+ lines.push('');
88
+ }
89
+ // Format children
90
+ for (const childId of item.children) {
91
+ const child = itemMap.get(childId);
92
+ if (child.type === 'list') {
93
+ // List items under a heading start at indent 0
94
+ // Nested list items increment indent
95
+ const nextIndent = item.type === 'heading' ? 0 : listIndent + 1;
96
+ formatItem(childId, nextIndent, isUnderMisc);
97
+ }
98
+ else {
99
+ formatItem(childId, 0, isUnderMisc);
100
+ }
101
+ }
102
+ }
103
+ // Format all root items except Misc
104
+ for (const rootId of ast.root_ids) {
105
+ if (rootId !== miscSectionId) {
106
+ formatItem(rootId, 0, false);
107
+ }
108
+ }
109
+ // Add Misc section at the end
110
+ if (lines.length > 0 && lines[lines.length - 1] !== '') {
111
+ lines.push('');
112
+ }
113
+ lines.push('# Misc');
114
+ // Add Misc items if they exist
115
+ if (miscSectionId) {
116
+ const miscItem = itemMap.get(miscSectionId);
117
+ if (miscItem.comments.length > 0) {
118
+ lines.push('');
119
+ lines.push(...miscItem.comments);
120
+ }
121
+ if (miscItem.children.length > 0) {
122
+ lines.push('');
123
+ for (const childId of miscItem.children) {
124
+ // Format misc children - they start at indent 0
125
+ const child = itemMap.get(childId);
126
+ lines.push(formatItemLine(child, 0));
127
+ const formattedComments = formatComments(child.comments, child.type === 'list', 0);
128
+ lines.push(...formattedComments);
129
+ }
130
+ }
131
+ }
132
+ return lines.join('\n') + '\n';
133
+ }
134
+ //# sourceMappingURL=formatter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formatter.js","sourceRoot":"","sources":["../src/formatter.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAGpC,SAAS,cAAc,CAAC,QAAsB;IAC5C,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,IAAI,QAAQ,CAAC,GAAG,EAAE,CAAC;QACjB,KAAK,CAAC,IAAI,CAAC,OAAO,QAAQ,CAAC,GAAG,EAAE,CAAC,CAAC;IACpC,CAAC;IAED,IAAI,QAAQ,CAAC,QAAQ,KAAK,IAAI,EAAE,CAAC;QAC/B,KAAK,CAAC,IAAI,CAAC,IAAI,QAAQ,CAAC,QAAQ,EAAE,CAAC,CAAC;IACtC,CAAC;IAED,IAAI,QAAQ,CAAC,gBAAgB,KAAK,IAAI,EAAE,CAAC;QACvC,MAAM,OAAO,GAAG,QAAQ,CAAC,gBAAgB,CAAC;QAC1C,IAAI,OAAO,GAAG,GAAG,KAAK,CAAC,IAAI,OAAO,IAAI,GAAG,EAAE,CAAC;YAC1C,KAAK,CAAC,IAAI,CAAC,GAAG,OAAO,GAAG,GAAG,GAAG,CAAC,CAAC;QAClC,CAAC;aAAM,IAAI,OAAO,GAAG,EAAE,KAAK,CAAC,IAAI,OAAO,IAAI,EAAE,EAAE,CAAC;YAC/C,KAAK,CAAC,IAAI,CAAC,GAAG,OAAO,GAAG,EAAE,GAAG,CAAC,CAAC;QACjC,CAAC;aAAM,CAAC;YACN,KAAK,CAAC,IAAI,CAAC,GAAG,OAAO,GAAG,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;AACxD,CAAC;AAED,SAAS,cAAc,CAAC,IAAc,EAAE,SAAiB,CAAC;IACxD,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IACtC,MAAM,OAAO,GAAG,cAAc,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC9C,MAAM,aAAa,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,UAAU,IAAI,OAAO,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC;IAElF,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC5B,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC;QAC3C,OAAO,GAAG,MAAM,IAAI,aAAa,EAAE,CAAC;IACtC,CAAC;IAED,OAAO,GAAG,SAAS,KAAK,aAAa,EAAE,CAAC;AAC1C,CAAC;AAED,SAAS,cAAc,CAAC,QAAkB,EAAE,UAAmB,EAAE,MAAc;IAC7E,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAErC,IAAI,UAAU,EAAE,CAAC;QACf,iEAAiE;QACjE,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAC1C,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,SAAS,GAAG,CAAC,EAAE,CAAC,CAAC;IAC/C,CAAC;IAED,oCAAoC;IACpC,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,MAAM,CAAC,IAAY;IACjC,MAAM,EAAE,GAAG,EAAE,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC;IAC5B,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,MAAM,OAAO,GAAG,IAAI,GAAG,EAAoB,CAAC;IAE5C,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,KAAK,EAAE,CAAC;QAC7B,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;IAC7B,CAAC;IAED,qBAAqB;IACrB,IAAI,aAAa,GAAkB,IAAI,CAAC;IAExC,6BAA6B;IAC7B,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,KAAK,EAAE,CAAC;QAC7B,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,UAAU,KAAK,MAAM,IAAI,IAAI,CAAC,KAAK,KAAK,CAAC,EAAE,CAAC;YAC9E,aAAa,GAAG,IAAI,CAAC,EAAE,CAAC;YACxB,MAAM;QACR,CAAC;IACH,CAAC;IAED,2CAA2C;IAC3C,SAAS,UAAU,CAAC,EAAU,EAAE,aAAqB,CAAC,EAAE,cAAuB,KAAK;QAClF,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,EAAE,CAAE,CAAC;QAE9B,sEAAsE;QACtE,IAAI,IAAI,CAAC,EAAE,KAAK,aAAa,IAAI,CAAC,WAAW,EAAE,CAAC;YAC9C,OAAO;QACT,CAAC;QAED,mDAAmD;QACnD,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAChD,IAAI,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC;gBACnC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACjB,CAAC;QACH,CAAC;QAED,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC;QAE7C,2DAA2D;QAC3D,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YAC5B,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACjB,CAAC;QAED,eAAe;QACf,MAAM,iBAAiB,GAAG,cAAc,CACtC,IAAI,CAAC,QAAQ,EACb,IAAI,CAAC,IAAI,KAAK,MAAM,EACpB,UAAU,CACX,CAAC;QACF,KAAK,CAAC,IAAI,CAAC,GAAG,iBAAiB,CAAC,CAAC;QAEjC,wDAAwD;QACxD,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACpF,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACjB,CAAC;QAED,kBAAkB;QAClB,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YACpC,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,OAAO,CAAE,CAAC;YACpC,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;gBAC1B,+CAA+C;gBAC/C,qCAAqC;gBACrC,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC;gBAChE,UAAU,CAAC,OAAO,EAAE,UAAU,EAAE,WAAW,CAAC,CAAC;YAC/C,CAAC;iBAAM,CAAC;gBACN,UAAU,CAAC,OAAO,EAAE,CAAC,EAAE,WAAW,CAAC,CAAC;YACtC,CAAC;QACH,CAAC;IACH,CAAC;IAED,oCAAoC;IACpC,KAAK,MAAM,MAAM,IAAI,GAAG,CAAC,QAAQ,EAAE,CAAC;QAClC,IAAI,MAAM,KAAK,aAAa,EAAE,CAAC;YAC7B,UAAU,CAAC,MAAM,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC;QAC/B,CAAC;IACH,CAAC;IAED,8BAA8B;IAC9B,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC;QACvD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACjB,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAErB,+BAA+B;IAC/B,IAAI,aAAa,EAAE,CAAC;QAClB,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,CAAE,CAAC;QAC7C,IAAI,QAAQ,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACjC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACf,KAAK,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC;QACnC,CAAC;QACD,IAAI,QAAQ,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACjC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACf,KAAK,MAAM,OAAO,IAAI,QAAQ,CAAC,QAAQ,EAAE,CAAC;gBACxC,gDAAgD;gBAChD,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,OAAO,CAAE,CAAC;gBACpC,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC;gBACrC,MAAM,iBAAiB,GAAG,cAAc,CACtC,KAAK,CAAC,QAAQ,EACd,KAAK,CAAC,IAAI,KAAK,MAAM,EACrB,CAAC,CACF,CAAC;gBACF,KAAK,CAAC,IAAI,CAAC,GAAG,iBAAiB,CAAC,CAAC;YACnC,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;AACjC,CAAC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Todoosy - Markdown-based todo system
3
+ */
4
+ export { parse } from './parser.js';
5
+ export type { ParseResult } from './parser.js';
6
+ export { format } from './formatter.js';
7
+ export { lint } from './linter.js';
8
+ export { queryUpcoming, queryMisc } from './query.js';
9
+ export { parseScheme } from './scheme.js';
10
+ export type { AST, ItemNode, ItemMetadata, Warning, LintResult, UpcomingItem, UpcomingResult, MiscItem, MiscResult, Scheme, ParsedToken, ParenGroup, } from './types.js';
11
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACpC,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AACxC,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AACnC,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C,YAAY,EACV,GAAG,EACH,QAAQ,EACR,YAAY,EACZ,OAAO,EACP,UAAU,EACV,YAAY,EACZ,cAAc,EACd,QAAQ,EACR,UAAU,EACV,MAAM,EACN,WAAW,EACX,UAAU,GACX,MAAM,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Todoosy - Markdown-based todo system
3
+ */
4
+ export { parse } from './parser.js';
5
+ export { format } from './formatter.js';
6
+ export { lint } from './linter.js';
7
+ export { queryUpcoming, queryMisc } from './query.js';
8
+ export { parseScheme } from './scheme.js';
9
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAGpC,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AACxC,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AACnC,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Todoosy Linter
3
+ */
4
+ import type { LintResult, Scheme } from './types.js';
5
+ export declare function lint(text: string, scheme?: Scheme): LintResult;
6
+ //# sourceMappingURL=linter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"linter.d.ts","sourceRoot":"","sources":["../src/linter.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EAAW,UAAU,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAkB9D,wBAAgB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,UAAU,CAyK9D"}
package/dist/linter.js ADDED
@@ -0,0 +1,176 @@
1
+ /**
2
+ * Todoosy Linter
3
+ */
4
+ import { parse } from './parser.js';
5
+ const INVALID_DATE_REGEX = /\bdue\s+(\S+)/gi;
6
+ const VALID_DATE_FORMATS = [
7
+ /^\d{4}-\d{2}-\d{2}$/, // YYYY-MM-DD
8
+ /^\d{1,2}\/\d{1,2}\/\d{4}$/, // MM/DD/YYYY
9
+ /^\d{1,2}\/\d{1,2}\/\d{2}$/, // MM/DD/YY
10
+ ];
11
+ const PRIORITY_REGEX = /\bp(\d+)\b/gi;
12
+ const ESTIMATE_REGEX = /\b(\d+)([mhd])\b/gi;
13
+ const INVALID_PRIORITY_REGEX = /\bp([^0-9\s)][^\s)]*)\b/gi;
14
+ const INVALID_ESTIMATE_REGEX = /\b(\d+)([^mhd\s)0-9][^\s)]*)\b/gi;
15
+ function isValidDate(dateStr) {
16
+ return VALID_DATE_FORMATS.some(regex => regex.test(dateStr));
17
+ }
18
+ export function lint(text, scheme) {
19
+ const { ast } = parse(text);
20
+ const warnings = [];
21
+ const lines = text.split('\n');
22
+ let miscSectionLine = null;
23
+ let miscSectionSpan = null;
24
+ const headingsAfterMisc = [];
25
+ // Check each item
26
+ for (const item of ast.items) {
27
+ const lineIndex = item.line - 1;
28
+ const rawLine = item.raw_line;
29
+ // Check for Misc section
30
+ if (item.type === 'heading' && item.title_text === 'Misc' && item.level === 1) {
31
+ if (miscSectionLine === null) {
32
+ miscSectionLine = item.line;
33
+ miscSectionSpan = item.item_span;
34
+ }
35
+ }
36
+ else if (item.type === 'heading' && miscSectionLine !== null) {
37
+ // Heading after Misc
38
+ headingsAfterMisc.push({ line: item.line, span: item.item_span });
39
+ }
40
+ // Check for invalid date formats in parentheses
41
+ const parenMatches = rawLine.matchAll(/\(([^)]+)\)/g);
42
+ for (const match of parenMatches) {
43
+ const content = match[1];
44
+ const parenStart = item.item_span[0] + (match.index || 0);
45
+ // Check for due dates
46
+ const dueMatches = content.matchAll(/\bdue\s+([^\s,)]+)/gi);
47
+ for (const dueMatch of dueMatches) {
48
+ const dateStr = dueMatch[1];
49
+ if (!isValidDate(dateStr)) {
50
+ const tokenStart = parenStart + 1 + (dueMatch.index || 0);
51
+ warnings.push({
52
+ code: 'INVALID_DATE_FORMAT',
53
+ message: `Invalid due date format: ${dateStr}`,
54
+ line: item.line,
55
+ column: tokenStart - item.item_span[0] + 1,
56
+ span: [tokenStart + 4, tokenStart + 4 + dateStr.length], // Skip 'due '
57
+ });
58
+ }
59
+ }
60
+ // Check for multiple due dates across all paren groups
61
+ const allDueDates = [];
62
+ const allParenMatches = rawLine.matchAll(/\(([^)]+)\)/g);
63
+ for (const pMatch of allParenMatches) {
64
+ const pContent = pMatch[1];
65
+ const pStart = item.item_span[0] + (pMatch.index || 0);
66
+ const dueDatesInGroup = pContent.matchAll(/\bdue\s+([^\s,)]+)/gi);
67
+ for (const dm of dueDatesInGroup) {
68
+ const ds = dm[1];
69
+ if (isValidDate(ds)) {
70
+ const dStart = pStart + 1 + (dm.index || 0);
71
+ allDueDates.push({
72
+ dateStr: ds,
73
+ span: [dStart, dStart + dm[0].length],
74
+ });
75
+ }
76
+ }
77
+ }
78
+ if (allDueDates.length > 1) {
79
+ // Warn for the second and subsequent ones
80
+ for (let i = 1; i < allDueDates.length; i++) {
81
+ warnings.push({
82
+ code: 'DUPLICATE_DUE_DATE',
83
+ message: 'Multiple due dates found, using last value',
84
+ line: item.line,
85
+ column: allDueDates[i].span[0] - item.item_span[0] + 1,
86
+ span: allDueDates[i].span,
87
+ });
88
+ }
89
+ break; // Only warn once per item
90
+ }
91
+ // Check for invalid priority tokens (e.g., pX)
92
+ const invalidPriorities = content.matchAll(/\bp([a-zA-Z][^\s,)]*)/gi);
93
+ for (const ipMatch of invalidPriorities) {
94
+ const tokenStart = parenStart + 1 + (ipMatch.index || 0);
95
+ warnings.push({
96
+ code: 'INVALID_TOKEN',
97
+ message: `Unrecognized token in parentheses: ${ipMatch[0]}`,
98
+ line: item.line,
99
+ column: tokenStart - item.item_span[0] + 1,
100
+ span: [tokenStart, tokenStart + ipMatch[0].length],
101
+ });
102
+ }
103
+ // Check for invalid estimate tokens (e.g., 5q)
104
+ const invalidEstimates = content.matchAll(/\b(\d+)([a-zA-Z])(?![mhdMHD])\b/gi);
105
+ for (const ieMatch of invalidEstimates) {
106
+ const unit = ieMatch[2].toLowerCase();
107
+ if (unit !== 'm' && unit !== 'h' && unit !== 'd') {
108
+ const tokenStart = parenStart + 1 + (ieMatch.index || 0);
109
+ warnings.push({
110
+ code: 'INVALID_TOKEN',
111
+ message: `Unrecognized token in parentheses: ${ieMatch[0]}`,
112
+ line: item.line,
113
+ column: tokenStart - item.item_span[0] + 1,
114
+ span: [tokenStart, tokenStart + ieMatch[0].length],
115
+ });
116
+ }
117
+ }
118
+ }
119
+ // Check for comment indentation (list items only)
120
+ if (item.type === 'list' && item.comments.length > 0) {
121
+ const listMatch = rawLine.match(/^(\s*)([-*]|\d+\.)\s/);
122
+ const expectedIndent = listMatch ? listMatch[1].length + listMatch[2].length + 1 : 2;
123
+ // Find comment lines in the original text
124
+ let currentOffset = item.item_span[0] + rawLine.length + 1;
125
+ for (let i = 0; i < item.comments.length; i++) {
126
+ const commentLineIndex = item.line + i;
127
+ if (commentLineIndex < lines.length) {
128
+ const commentLine = lines[commentLineIndex];
129
+ const leadingSpaces = commentLine.match(/^(\s*)/)?.[1].length || 0;
130
+ if (leadingSpaces < expectedIndent && commentLine.trim().length > 0) {
131
+ warnings.push({
132
+ code: 'COMMENT_INDENTATION',
133
+ message: 'List item comment should be indented',
134
+ line: commentLineIndex + 1,
135
+ column: 1,
136
+ span: [currentOffset, currentOffset + commentLine.length],
137
+ });
138
+ }
139
+ }
140
+ currentOffset += (lines[commentLineIndex]?.length || 0) + 1;
141
+ }
142
+ }
143
+ }
144
+ // Check for Misc section issues
145
+ if (miscSectionLine === null) {
146
+ warnings.push({
147
+ code: 'MISC_MISSING',
148
+ message: "Document is missing required '# Misc' section",
149
+ line: null,
150
+ column: null,
151
+ span: null,
152
+ });
153
+ }
154
+ else if (headingsAfterMisc.length > 0) {
155
+ // Misc is not at EOF
156
+ warnings.push({
157
+ code: 'MISC_NOT_AT_EOF',
158
+ message: "'# Misc' section must be at end of file",
159
+ line: miscSectionLine,
160
+ column: 1,
161
+ span: miscSectionSpan,
162
+ });
163
+ // Content after Misc warning for each heading
164
+ for (const heading of headingsAfterMisc) {
165
+ warnings.push({
166
+ code: 'CONTENT_AFTER_MISC',
167
+ message: "Heading found after '# Misc' section",
168
+ line: heading.line,
169
+ column: 1,
170
+ span: heading.span,
171
+ });
172
+ }
173
+ }
174
+ return { warnings };
175
+ }
176
+ //# sourceMappingURL=linter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"linter.js","sourceRoot":"","sources":["../src/linter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Todoosy Parser
3
+ */
4
+ import type { AST, Warning } from './types.js';
5
+ export interface ParseResult {
6
+ ast: AST;
7
+ warnings: Warning[];
8
+ }
9
+ export declare function parse(text: string): ParseResult;
10
+ //# sourceMappingURL=parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../src/parser.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,GAAG,EAAmD,OAAO,EAAE,MAAM,YAAY,CAAC;AAUhG,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,GAAG,CAAC;IACT,QAAQ,EAAE,OAAO,EAAE,CAAC;CACrB;AAsLD,wBAAgB,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CA0M/C"}
package/dist/parser.js ADDED
@@ -0,0 +1,350 @@
1
+ /**
2
+ * Todoosy Parser
3
+ */
4
+ const HEADING_REGEX = /^(#{1,6})\s+(.*)$/;
5
+ const LIST_ITEM_REGEX = /^(\s*)([-*]|\d+\.)\s+(.*)$/;
6
+ const DUE_ISO_REGEX = /^due\s+(\d{4})-(\d{2})-(\d{2})$/i;
7
+ const DUE_US_REGEX = /^due\s+(\d{1,2})\/(\d{1,2})\/(\d{4})$/i;
8
+ const DUE_US_SHORT_REGEX = /^due\s+(\d{1,2})\/(\d{1,2})\/(\d{2})$/i;
9
+ const PRIORITY_REGEX = /^p(\d+)$/i;
10
+ const ESTIMATE_REGEX = /^(\d+)([mhd])$/i;
11
+ function parseDate(dateStr) {
12
+ const isoMatch = dateStr.match(/^(\d{4})-(\d{2})-(\d{2})$/);
13
+ if (isoMatch) {
14
+ return { date: dateStr, valid: true, raw: dateStr };
15
+ }
16
+ const usMatch = dateStr.match(/^(\d{1,2})\/(\d{1,2})\/(\d{4})$/);
17
+ if (usMatch) {
18
+ const month = usMatch[1].padStart(2, '0');
19
+ const day = usMatch[2].padStart(2, '0');
20
+ const year = usMatch[3];
21
+ return { date: `${year}-${month}-${day}`, valid: true, raw: dateStr };
22
+ }
23
+ const usShortMatch = dateStr.match(/^(\d{1,2})\/(\d{1,2})\/(\d{2})$/);
24
+ if (usShortMatch) {
25
+ const month = usShortMatch[1].padStart(2, '0');
26
+ const day = usShortMatch[2].padStart(2, '0');
27
+ const year = `20${usShortMatch[3]}`;
28
+ return { date: `${year}-${month}-${day}`, valid: true, raw: dateStr };
29
+ }
30
+ return { date: null, valid: false, raw: dateStr };
31
+ }
32
+ function parseTokensInParenGroup(content, groupStart) {
33
+ const tokens = [];
34
+ // Split by comma and/or whitespace
35
+ const parts = content.split(/[,\s]+/).filter(p => p.length > 0);
36
+ let currentPos = 0;
37
+ for (const part of parts) {
38
+ const partStart = content.indexOf(part, currentPos);
39
+ const absoluteStart = groupStart + 1 + partStart; // +1 for opening paren
40
+ const absoluteEnd = absoluteStart + part.length;
41
+ currentPos = partStart + part.length;
42
+ // Check for due date
43
+ if (part.toLowerCase() === 'due') {
44
+ // Look for the next part as the date
45
+ continue;
46
+ }
47
+ // Check if previous part was 'due'
48
+ const prevPartIndex = parts.indexOf(part) - 1;
49
+ if (prevPartIndex >= 0 && parts[prevPartIndex].toLowerCase() === 'due') {
50
+ const dateResult = parseDate(part);
51
+ if (dateResult.valid) {
52
+ tokens.push({
53
+ type: 'due',
54
+ value: dateResult.date,
55
+ raw: `due ${part}`,
56
+ start: absoluteStart - 4, // Include 'due '
57
+ end: absoluteEnd,
58
+ });
59
+ }
60
+ continue;
61
+ }
62
+ // Check for priority
63
+ const priorityMatch = part.match(PRIORITY_REGEX);
64
+ if (priorityMatch) {
65
+ tokens.push({
66
+ type: 'priority',
67
+ value: parseInt(priorityMatch[1], 10),
68
+ raw: part,
69
+ start: absoluteStart,
70
+ end: absoluteEnd,
71
+ });
72
+ continue;
73
+ }
74
+ // Check for estimate
75
+ const estimateMatch = part.match(ESTIMATE_REGEX);
76
+ if (estimateMatch) {
77
+ const num = parseInt(estimateMatch[1], 10);
78
+ const unit = estimateMatch[2].toLowerCase();
79
+ let minutes;
80
+ switch (unit) {
81
+ case 'm':
82
+ minutes = num;
83
+ break;
84
+ case 'h':
85
+ minutes = num * 60;
86
+ break;
87
+ case 'd':
88
+ minutes = num * 480;
89
+ break;
90
+ default: minutes = num;
91
+ }
92
+ tokens.push({
93
+ type: 'estimate',
94
+ value: minutes,
95
+ raw: part,
96
+ start: absoluteStart,
97
+ end: absoluteEnd,
98
+ });
99
+ continue;
100
+ }
101
+ }
102
+ return {
103
+ start: groupStart,
104
+ end: groupStart + content.length + 2, // +2 for parens
105
+ content,
106
+ tokens,
107
+ hasRecognizedTokens: tokens.length > 0,
108
+ };
109
+ }
110
+ function extractParenGroups(line, lineStart) {
111
+ const groups = [];
112
+ let i = 0;
113
+ while (i < line.length) {
114
+ if (line[i] === '(') {
115
+ const start = i; // Position within the line (content)
116
+ let depth = 1;
117
+ i++;
118
+ while (i < line.length && depth > 0) {
119
+ if (line[i] === '(')
120
+ depth++;
121
+ else if (line[i] === ')')
122
+ depth--;
123
+ i++;
124
+ }
125
+ if (depth === 0) {
126
+ const content = line.slice(start + 1, i - 1);
127
+ // Pass the relative position within content string
128
+ const group = parseTokensInParenGroup(content, start);
129
+ group.start = start; // Store relative position
130
+ group.end = i; // Store relative position
131
+ groups.push(group);
132
+ }
133
+ }
134
+ else {
135
+ i++;
136
+ }
137
+ }
138
+ return groups;
139
+ }
140
+ function buildTitleText(rawText, groups) {
141
+ // Remove groups that have recognized tokens
142
+ // Process in reverse order to maintain correct positions
143
+ const sortedGroups = [...groups]
144
+ .filter(g => g.hasRecognizedTokens)
145
+ .sort((a, b) => b.start - a.start);
146
+ let result = rawText;
147
+ for (const group of sortedGroups) {
148
+ const before = result.slice(0, group.start);
149
+ const after = result.slice(group.end);
150
+ result = before + after;
151
+ }
152
+ // Clean up extra whitespace
153
+ return result.replace(/\s+/g, ' ').trim();
154
+ }
155
+ function buildMetadata(groups) {
156
+ const metadata = {
157
+ due: null,
158
+ priority: null,
159
+ estimate_minutes: null,
160
+ };
161
+ // Collect all tokens from all groups
162
+ const allTokens = groups.flatMap(g => g.tokens);
163
+ // Last occurrence wins
164
+ for (const token of allTokens) {
165
+ switch (token.type) {
166
+ case 'due':
167
+ metadata.due = token.value;
168
+ break;
169
+ case 'priority':
170
+ metadata.priority = token.value;
171
+ break;
172
+ case 'estimate':
173
+ metadata.estimate_minutes = token.value;
174
+ break;
175
+ }
176
+ }
177
+ return metadata;
178
+ }
179
+ export function parse(text) {
180
+ const lines = text.split('\n');
181
+ const items = [];
182
+ const warnings = [];
183
+ let nextId = 0;
184
+ let offset = 0;
185
+ // Stack to track current context: [itemId, indentLevel]
186
+ const listStack = [];
187
+ let currentHeadingId = null;
188
+ const rootIds = [];
189
+ // Map id -> children for building the tree
190
+ const childrenMap = new Map();
191
+ // First pass: identify all items and their basic info
192
+ for (let lineNum = 0; lineNum < lines.length; lineNum++) {
193
+ const line = lines[lineNum];
194
+ const lineStart = offset;
195
+ const lineEnd = offset + line.length;
196
+ // Check for heading
197
+ const headingMatch = line.match(HEADING_REGEX);
198
+ if (headingMatch) {
199
+ const level = headingMatch[1].length;
200
+ const content = headingMatch[2];
201
+ // Close any open list context
202
+ listStack.length = 0;
203
+ const groups = extractParenGroups(content, lineStart + headingMatch[1].length + 1);
204
+ const titleText = buildTitleText(content, groups);
205
+ const metadata = buildMetadata(groups);
206
+ const id = String(nextId++);
207
+ const item = {
208
+ id,
209
+ type: 'heading',
210
+ level,
211
+ raw_line: line,
212
+ title_text: titleText,
213
+ metadata,
214
+ comments: [],
215
+ children: [],
216
+ item_span: [lineStart, lineEnd],
217
+ subtree_span: [lineStart, lineEnd],
218
+ line: lineNum + 1,
219
+ column: 1,
220
+ };
221
+ items.push(item);
222
+ childrenMap.set(id, []);
223
+ rootIds.push(id);
224
+ currentHeadingId = id;
225
+ offset = lineEnd + 1;
226
+ continue;
227
+ }
228
+ // Check for list item
229
+ const listMatch = line.match(LIST_ITEM_REGEX);
230
+ if (listMatch) {
231
+ const indent = listMatch[1].length;
232
+ const marker = listMatch[2];
233
+ const content = listMatch[3];
234
+ const contentStart = lineStart + indent + marker.length + 1;
235
+ const groups = extractParenGroups(content, contentStart);
236
+ const titleText = buildTitleText(content, groups);
237
+ const metadata = buildMetadata(groups);
238
+ const id = String(nextId++);
239
+ const item = {
240
+ id,
241
+ type: 'list',
242
+ raw_line: line,
243
+ title_text: titleText,
244
+ metadata,
245
+ comments: [],
246
+ children: [],
247
+ item_span: [lineStart, lineEnd],
248
+ subtree_span: [lineStart, lineEnd],
249
+ line: lineNum + 1,
250
+ column: 1,
251
+ };
252
+ items.push(item);
253
+ childrenMap.set(id, []);
254
+ // Determine parent
255
+ // Pop items from stack that are at same or greater indent
256
+ while (listStack.length > 0 && listStack[listStack.length - 1].indent >= indent) {
257
+ listStack.pop();
258
+ }
259
+ if (listStack.length > 0) {
260
+ // Parent is the top of the stack
261
+ const parentId = listStack[listStack.length - 1].id;
262
+ childrenMap.get(parentId).push(id);
263
+ }
264
+ else if (currentHeadingId !== null) {
265
+ // Parent is current heading
266
+ childrenMap.get(currentHeadingId).push(id);
267
+ }
268
+ else {
269
+ // No parent, it's a root
270
+ rootIds.push(id);
271
+ }
272
+ listStack.push({ id, indent });
273
+ offset = lineEnd + 1;
274
+ continue;
275
+ }
276
+ // Not a heading or list item - could be a comment or blank line
277
+ offset = lineEnd + 1;
278
+ }
279
+ // Second pass: collect comments
280
+ offset = 0;
281
+ let currentItemIndex = -1;
282
+ let hasStartedComments = false;
283
+ let blankAfterCommentStart = false;
284
+ for (let lineNum = 0; lineNum < lines.length; lineNum++) {
285
+ const line = lines[lineNum];
286
+ const lineStart = offset;
287
+ const lineEnd = offset + line.length;
288
+ // Check if this line starts a new item
289
+ const headingMatch = line.match(HEADING_REGEX);
290
+ const listMatch = line.match(LIST_ITEM_REGEX);
291
+ if (headingMatch || listMatch) {
292
+ currentItemIndex = items.findIndex(item => item.item_span[0] === lineStart);
293
+ hasStartedComments = false;
294
+ blankAfterCommentStart = false;
295
+ offset = lineEnd + 1;
296
+ continue;
297
+ }
298
+ // Check for blank line
299
+ if (line.trim() === '') {
300
+ if (hasStartedComments) {
301
+ // Blank line after comments started = stop collecting
302
+ blankAfterCommentStart = true;
303
+ }
304
+ // Blank line before comments started (e.g., after heading) = ignore
305
+ offset = lineEnd + 1;
306
+ continue;
307
+ }
308
+ // Non-blank, non-item line - potential comment
309
+ if (currentItemIndex >= 0 && !blankAfterCommentStart) {
310
+ const currentItem = items[currentItemIndex];
311
+ currentItem.comments.push(line.trim());
312
+ currentItem.item_span[1] = lineEnd;
313
+ hasStartedComments = true;
314
+ }
315
+ offset = lineEnd + 1;
316
+ }
317
+ // Build children arrays and compute subtree spans
318
+ for (const item of items) {
319
+ item.children = childrenMap.get(item.id) || [];
320
+ }
321
+ // Compute subtree spans (post-order traversal)
322
+ function computeSubtreeSpan(id) {
323
+ const item = items.find(i => i.id === id);
324
+ let end = item.item_span[1];
325
+ for (const childId of item.children) {
326
+ const childSpan = computeSubtreeSpan(childId);
327
+ end = Math.max(end, childSpan[1]);
328
+ }
329
+ item.subtree_span = [item.item_span[0], end];
330
+ return item.subtree_span;
331
+ }
332
+ for (const rootId of rootIds) {
333
+ computeSubtreeSpan(rootId);
334
+ }
335
+ // Update root_ids to only include top-level items
336
+ const actualRootIds = items
337
+ .filter(item => {
338
+ // Check if this item is a child of any other item
339
+ return !items.some(other => other.children.includes(item.id));
340
+ })
341
+ .map(item => item.id);
342
+ return {
343
+ ast: {
344
+ items,
345
+ root_ids: actualRootIds,
346
+ },
347
+ warnings,
348
+ };
349
+ }
350
+ //# sourceMappingURL=parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.js","sourceRoot":"","sources":["../src/parser.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Todoosy Query Engine
3
+ */
4
+ import type { UpcomingResult, MiscResult, Scheme } from './types.js';
5
+ export declare function queryUpcoming(text: string, scheme?: Scheme): UpcomingResult;
6
+ export declare function queryMisc(text: string): MiscResult;
7
+ //# sourceMappingURL=query.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../src/query.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EAIV,cAAc,EAEd,UAAU,EACV,MAAM,EACP,MAAM,YAAY,CAAC;AA2BpB,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,cAAc,CA8C3E;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CAwClD"}
package/dist/query.js ADDED
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Todoosy Query Engine
3
+ */
4
+ import { parse } from './parser.js';
5
+ function buildPath(itemId, ast) {
6
+ const itemMap = new Map();
7
+ const parentMap = new Map();
8
+ for (const item of ast.items) {
9
+ itemMap.set(item.id, item);
10
+ for (const childId of item.children) {
11
+ parentMap.set(childId, item.id);
12
+ }
13
+ }
14
+ const parts = [];
15
+ let currentId = itemId;
16
+ while (currentId !== undefined) {
17
+ const item = itemMap.get(currentId);
18
+ if (item) {
19
+ parts.unshift(item.title_text);
20
+ }
21
+ currentId = parentMap.get(currentId);
22
+ }
23
+ return parts.join(' > ');
24
+ }
25
+ export function queryUpcoming(text, scheme) {
26
+ const { ast } = parse(text);
27
+ const items = [];
28
+ // Find all items with due dates
29
+ for (const item of ast.items) {
30
+ if (item.metadata.due) {
31
+ const upcomingItem = {
32
+ id: item.id,
33
+ due: item.metadata.due,
34
+ priority: item.metadata.priority,
35
+ path: buildPath(item.id, ast),
36
+ item_span: item.item_span,
37
+ };
38
+ // Add priority label if scheme is provided
39
+ if (scheme && item.metadata.priority !== null) {
40
+ const label = scheme.priorities[String(item.metadata.priority)];
41
+ if (label) {
42
+ upcomingItem.priority_label = label;
43
+ }
44
+ }
45
+ items.push(upcomingItem);
46
+ }
47
+ }
48
+ // Sort by:
49
+ // 1. Due date ascending
50
+ // 2. Priority ascending (lower is higher priority, nulls last)
51
+ // 3. Document order (by item_span start)
52
+ items.sort((a, b) => {
53
+ // Due date comparison
54
+ const dateCompare = a.due.localeCompare(b.due);
55
+ if (dateCompare !== 0)
56
+ return dateCompare;
57
+ // Priority comparison (null treated as infinity)
58
+ const aPri = a.priority ?? Infinity;
59
+ const bPri = b.priority ?? Infinity;
60
+ if (aPri !== bPri)
61
+ return aPri - bPri;
62
+ // Document order
63
+ return a.item_span[0] - b.item_span[0];
64
+ });
65
+ return { items };
66
+ }
67
+ export function queryMisc(text) {
68
+ const { ast } = parse(text);
69
+ const items = [];
70
+ // Find the Misc section
71
+ let miscSectionId = null;
72
+ for (const item of ast.items) {
73
+ if (item.type === 'heading' && item.title_text === 'Misc' && item.level === 1) {
74
+ miscSectionId = item.id;
75
+ break;
76
+ }
77
+ }
78
+ if (miscSectionId === null) {
79
+ return { items };
80
+ }
81
+ // Get all direct children of the Misc section
82
+ const miscSection = ast.items.find(i => i.id === miscSectionId);
83
+ if (!miscSection) {
84
+ return { items };
85
+ }
86
+ const itemMap = new Map();
87
+ for (const item of ast.items) {
88
+ itemMap.set(item.id, item);
89
+ }
90
+ for (const childId of miscSection.children) {
91
+ const child = itemMap.get(childId);
92
+ if (child) {
93
+ items.push({
94
+ id: child.id,
95
+ title_text: child.title_text,
96
+ item_span: child.item_span,
97
+ });
98
+ }
99
+ }
100
+ return { items };
101
+ }
102
+ //# sourceMappingURL=query.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query.js","sourceRoot":"","sources":["../src/query.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Todoosy Scheme Parser
3
+ */
4
+ import type { Scheme } from './types.js';
5
+ export declare function parseScheme(text: string): Scheme;
6
+ //# sourceMappingURL=scheme.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scheme.d.ts","sourceRoot":"","sources":["../src/scheme.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAMzC,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CA4DhD"}
package/dist/scheme.js ADDED
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Todoosy Scheme Parser
3
+ */
4
+ const TIMEZONE_HEADING_REGEX = /^#\s+Timezone\s*$/i;
5
+ const PRIORITIES_HEADING_REGEX = /^#\s+Priorities\s*$/i;
6
+ const PRIORITY_LINE_REGEX = /^[*\-]?\s*P(\d+)\s*[-–—]\s*(.+)$/i;
7
+ export function parseScheme(text) {
8
+ const lines = text.split('\n');
9
+ const scheme = {
10
+ timezone: null,
11
+ priorities: {},
12
+ };
13
+ let currentSection = 'none';
14
+ for (const line of lines) {
15
+ const trimmed = line.trim();
16
+ // Check for section headers
17
+ if (TIMEZONE_HEADING_REGEX.test(trimmed)) {
18
+ currentSection = 'timezone';
19
+ continue;
20
+ }
21
+ if (PRIORITIES_HEADING_REGEX.test(trimmed)) {
22
+ currentSection = 'priorities';
23
+ continue;
24
+ }
25
+ // Check if we hit another heading (any level)
26
+ if (/^#+\s+/.test(trimmed) && currentSection !== 'none') {
27
+ currentSection = 'none';
28
+ continue;
29
+ }
30
+ // Skip empty lines
31
+ if (trimmed === '') {
32
+ continue;
33
+ }
34
+ // Process content based on current section
35
+ if (currentSection === 'timezone') {
36
+ // First non-empty line after Timezone heading is the timezone
37
+ if (scheme.timezone === null) {
38
+ scheme.timezone = trimmed;
39
+ }
40
+ }
41
+ else if (currentSection === 'priorities') {
42
+ // Try to parse priority line
43
+ const match = trimmed.match(PRIORITY_LINE_REGEX);
44
+ if (match) {
45
+ const level = match[1];
46
+ const label = match[2].trim();
47
+ scheme.priorities[level] = label;
48
+ }
49
+ else if (!trimmed.startsWith('#')) {
50
+ // Also try format without bullet: "P0 - Label"
51
+ const altMatch = trimmed.match(/^P(\d+)\s*[-–—]\s*(.+)$/i);
52
+ if (altMatch) {
53
+ const level = altMatch[1];
54
+ const label = altMatch[2].trim();
55
+ scheme.priorities[level] = label;
56
+ }
57
+ }
58
+ }
59
+ }
60
+ return scheme;
61
+ }
62
+ //# sourceMappingURL=scheme.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scheme.js","sourceRoot":"","sources":["../src/scheme.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,MAAM,sBAAsB,GAAG,oBAAoB,CAAC;AACpD,MAAM,wBAAwB,GAAG,sBAAsB,CAAC;AACxD,MAAM,mBAAmB,GAAG,mCAAmC,CAAC;AAEhE,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC/B,MAAM,MAAM,GAAW;QACrB,QAAQ,EAAE,IAAI;QACd,UAAU,EAAE,EAAE;KACf,CAAC;IAEF,IAAI,cAAc,GAAuC,MAAM,CAAC;IAEhE,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QAE5B,4BAA4B;QAC5B,IAAI,sBAAsB,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;YACzC,cAAc,GAAG,UAAU,CAAC;YAC5B,SAAS;QACX,CAAC;QAED,IAAI,wBAAwB,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;YAC3C,cAAc,GAAG,YAAY,CAAC;YAC9B,SAAS;QACX,CAAC;QAED,8CAA8C;QAC9C,IAAI,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,cAAc,KAAK,MAAM,EAAE,CAAC;YACxD,cAAc,GAAG,MAAM,CAAC;YACxB,SAAS;QACX,CAAC;QAED,mBAAmB;QACnB,IAAI,OAAO,KAAK,EAAE,EAAE,CAAC;YACnB,SAAS;QACX,CAAC;QAED,2CAA2C;QAC3C,IAAI,cAAc,KAAK,UAAU,EAAE,CAAC;YAClC,8DAA8D;YAC9D,IAAI,MAAM,CAAC,QAAQ,KAAK,IAAI,EAAE,CAAC;gBAC7B,MAAM,CAAC,QAAQ,GAAG,OAAO,CAAC;YAC5B,CAAC;QACH,CAAC;aAAM,IAAI,cAAc,KAAK,YAAY,EAAE,CAAC;YAC3C,6BAA6B;YAC7B,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC;YACjD,IAAI,KAAK,EAAE,CAAC;gBACV,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;gBACvB,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;gBAC9B,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC;YACnC,CAAC;iBAAM,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;gBACpC,+CAA+C;gBAC/C,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC,0BAA0B,CAAC,CAAC;gBAC3D,IAAI,QAAQ,EAAE,CAAC;oBACb,MAAM,KAAK,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;oBAC1B,MAAM,KAAK,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;oBACjC,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC;gBACnC,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Todoosy Types
3
+ */
4
+ export interface ItemMetadata {
5
+ due: string | null;
6
+ priority: number | null;
7
+ estimate_minutes: number | null;
8
+ }
9
+ export interface ItemNode {
10
+ id: string;
11
+ type: 'heading' | 'list';
12
+ level?: number;
13
+ raw_line: string;
14
+ title_text: string;
15
+ metadata: ItemMetadata;
16
+ comments: string[];
17
+ children: string[];
18
+ item_span: [number, number];
19
+ subtree_span: [number, number];
20
+ line: number;
21
+ column: number;
22
+ }
23
+ export interface AST {
24
+ items: ItemNode[];
25
+ root_ids: string[];
26
+ }
27
+ export interface Warning {
28
+ code: string;
29
+ message: string;
30
+ line: number | null;
31
+ column: number | null;
32
+ span: [number, number] | null;
33
+ }
34
+ export interface LintResult {
35
+ warnings: Warning[];
36
+ }
37
+ export interface UpcomingItem {
38
+ id: string;
39
+ due: string;
40
+ priority: number | null;
41
+ priority_label?: string;
42
+ path: string;
43
+ item_span: [number, number];
44
+ }
45
+ export interface UpcomingResult {
46
+ items: UpcomingItem[];
47
+ }
48
+ export interface MiscItem {
49
+ id: string;
50
+ title_text: string;
51
+ item_span: [number, number];
52
+ }
53
+ export interface MiscResult {
54
+ items: MiscItem[];
55
+ }
56
+ export interface Scheme {
57
+ timezone: string | null;
58
+ priorities: Record<string, string>;
59
+ }
60
+ export interface ParsedToken {
61
+ type: 'due' | 'priority' | 'estimate';
62
+ value: string | number;
63
+ raw: string;
64
+ start: number;
65
+ end: number;
66
+ }
67
+ export interface ParenGroup {
68
+ start: number;
69
+ end: number;
70
+ content: string;
71
+ tokens: ParsedToken[];
72
+ hasRecognizedTokens: boolean;
73
+ }
74
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;CACjC;AAED,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,SAAS,GAAG,MAAM,CAAC;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,YAAY,CAAC;IACvB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,SAAS,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5B,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,GAAG;IAClB,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,IAAI,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC;CAC/B;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,OAAO,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC7B;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,YAAY,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC7B;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,QAAQ,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,MAAM;IACrB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACpC;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,KAAK,GAAG,UAAU,GAAG,UAAU,CAAC;IACtC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,mBAAmB,EAAE,OAAO,CAAC;CAC9B"}
package/dist/types.js ADDED
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Todoosy Types
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG"}
package/package.json ADDED
@@ -0,0 +1,29 @@
1
+ {
2
+ "name": "todoosy",
3
+ "version": "0.1.0",
4
+ "description": "Todoosy - Markdown-based todo system parser, formatter, linter, and query engine",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "type": "module",
8
+ "scripts": {
9
+ "build": "tsc",
10
+ "test": "node --experimental-vm-modules node_modules/jest/bin/jest.js",
11
+ "lint": "eslint src --ext .ts"
12
+ },
13
+ "keywords": ["todo", "markdown", "parser"],
14
+ "license": "MIT",
15
+ "devDependencies": {
16
+ "@types/jest": "^29.5.0",
17
+ "@types/node": "^20.0.0",
18
+ "jest": "^29.7.0",
19
+ "ts-jest": "^29.1.0",
20
+ "typescript": "^5.3.0"
21
+ },
22
+ "files": ["dist"],
23
+ "exports": {
24
+ ".": {
25
+ "import": "./dist/index.js",
26
+ "types": "./dist/index.d.ts"
27
+ }
28
+ }
29
+ }