@rejot-dev/thalo 0.0.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.
Files changed (237) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +396 -0
  3. package/dist/ast/ast-types.d.ts +469 -0
  4. package/dist/ast/ast-types.d.ts.map +1 -0
  5. package/dist/ast/ast-types.js +11 -0
  6. package/dist/ast/ast-types.js.map +1 -0
  7. package/dist/ast/builder.js +158 -0
  8. package/dist/ast/builder.js.map +1 -0
  9. package/dist/ast/extract.js +748 -0
  10. package/dist/ast/extract.js.map +1 -0
  11. package/dist/ast/node-at-position.d.ts +147 -0
  12. package/dist/ast/node-at-position.d.ts.map +1 -0
  13. package/dist/ast/node-at-position.js +382 -0
  14. package/dist/ast/node-at-position.js.map +1 -0
  15. package/dist/ast/visitor.js +232 -0
  16. package/dist/ast/visitor.js.map +1 -0
  17. package/dist/checker/check.d.ts +53 -0
  18. package/dist/checker/check.d.ts.map +1 -0
  19. package/dist/checker/check.js +105 -0
  20. package/dist/checker/check.js.map +1 -0
  21. package/dist/checker/rules/actualize-missing-updated.js +34 -0
  22. package/dist/checker/rules/actualize-missing-updated.js.map +1 -0
  23. package/dist/checker/rules/actualize-unresolved-target.js +42 -0
  24. package/dist/checker/rules/actualize-unresolved-target.js.map +1 -0
  25. package/dist/checker/rules/alter-before-define.js +53 -0
  26. package/dist/checker/rules/alter-before-define.js.map +1 -0
  27. package/dist/checker/rules/alter-undefined-entity.js +32 -0
  28. package/dist/checker/rules/alter-undefined-entity.js.map +1 -0
  29. package/dist/checker/rules/create-requires-section.js +34 -0
  30. package/dist/checker/rules/create-requires-section.js.map +1 -0
  31. package/dist/checker/rules/define-entity-requires-section.js +31 -0
  32. package/dist/checker/rules/define-entity-requires-section.js.map +1 -0
  33. package/dist/checker/rules/duplicate-entity-definition.js +37 -0
  34. package/dist/checker/rules/duplicate-entity-definition.js.map +1 -0
  35. package/dist/checker/rules/duplicate-field-in-schema.js +38 -0
  36. package/dist/checker/rules/duplicate-field-in-schema.js.map +1 -0
  37. package/dist/checker/rules/duplicate-link-id.js +52 -0
  38. package/dist/checker/rules/duplicate-link-id.js.map +1 -0
  39. package/dist/checker/rules/duplicate-metadata-key.js +21 -0
  40. package/dist/checker/rules/duplicate-metadata-key.js.map +1 -0
  41. package/dist/checker/rules/duplicate-section-heading.js +41 -0
  42. package/dist/checker/rules/duplicate-section-heading.js.map +1 -0
  43. package/dist/checker/rules/duplicate-section-in-schema.js +38 -0
  44. package/dist/checker/rules/duplicate-section-in-schema.js.map +1 -0
  45. package/dist/checker/rules/duplicate-timestamp.js +104 -0
  46. package/dist/checker/rules/duplicate-timestamp.js.map +1 -0
  47. package/dist/checker/rules/empty-required-value.js +45 -0
  48. package/dist/checker/rules/empty-required-value.js.map +1 -0
  49. package/dist/checker/rules/empty-section.js +21 -0
  50. package/dist/checker/rules/empty-section.js.map +1 -0
  51. package/dist/checker/rules/invalid-date-range-value.js +56 -0
  52. package/dist/checker/rules/invalid-date-range-value.js.map +1 -0
  53. package/dist/checker/rules/invalid-default-value.js +86 -0
  54. package/dist/checker/rules/invalid-default-value.js.map +1 -0
  55. package/dist/checker/rules/invalid-field-type.js +45 -0
  56. package/dist/checker/rules/invalid-field-type.js.map +1 -0
  57. package/dist/checker/rules/missing-required-field.js +48 -0
  58. package/dist/checker/rules/missing-required-field.js.map +1 -0
  59. package/dist/checker/rules/missing-required-section.js +51 -0
  60. package/dist/checker/rules/missing-required-section.js.map +1 -0
  61. package/dist/checker/rules/missing-title.js +56 -0
  62. package/dist/checker/rules/missing-title.js.map +1 -0
  63. package/dist/checker/rules/remove-undefined-field.js +42 -0
  64. package/dist/checker/rules/remove-undefined-field.js.map +1 -0
  65. package/dist/checker/rules/remove-undefined-section.js +42 -0
  66. package/dist/checker/rules/remove-undefined-section.js.map +1 -0
  67. package/dist/checker/rules/rules.d.ts +71 -0
  68. package/dist/checker/rules/rules.d.ts.map +1 -0
  69. package/dist/checker/rules/rules.js +102 -0
  70. package/dist/checker/rules/rules.js.map +1 -0
  71. package/dist/checker/rules/synthesis-empty-query.js +35 -0
  72. package/dist/checker/rules/synthesis-empty-query.js.map +1 -0
  73. package/dist/checker/rules/synthesis-missing-prompt.js +42 -0
  74. package/dist/checker/rules/synthesis-missing-prompt.js.map +1 -0
  75. package/dist/checker/rules/synthesis-missing-sources.js +32 -0
  76. package/dist/checker/rules/synthesis-missing-sources.js.map +1 -0
  77. package/dist/checker/rules/synthesis-unknown-query-entity.js +39 -0
  78. package/dist/checker/rules/synthesis-unknown-query-entity.js.map +1 -0
  79. package/dist/checker/rules/timestamp-out-of-order.js +55 -0
  80. package/dist/checker/rules/timestamp-out-of-order.js.map +1 -0
  81. package/dist/checker/rules/unknown-entity.js +32 -0
  82. package/dist/checker/rules/unknown-entity.js.map +1 -0
  83. package/dist/checker/rules/unknown-field.js +40 -0
  84. package/dist/checker/rules/unknown-field.js.map +1 -0
  85. package/dist/checker/rules/unknown-section.js +47 -0
  86. package/dist/checker/rules/unknown-section.js.map +1 -0
  87. package/dist/checker/rules/unresolved-link.js +34 -0
  88. package/dist/checker/rules/unresolved-link.js.map +1 -0
  89. package/dist/checker/rules/update-without-create.js +65 -0
  90. package/dist/checker/rules/update-without-create.js.map +1 -0
  91. package/dist/checker/visitor.d.ts +69 -0
  92. package/dist/checker/visitor.d.ts.map +1 -0
  93. package/dist/checker/visitor.js +67 -0
  94. package/dist/checker/visitor.js.map +1 -0
  95. package/dist/checker/workspace-index.d.ts +50 -0
  96. package/dist/checker/workspace-index.d.ts.map +1 -0
  97. package/dist/checker/workspace-index.js +108 -0
  98. package/dist/checker/workspace-index.js.map +1 -0
  99. package/dist/commands/actualize.d.ts +113 -0
  100. package/dist/commands/actualize.d.ts.map +1 -0
  101. package/dist/commands/actualize.js +111 -0
  102. package/dist/commands/actualize.js.map +1 -0
  103. package/dist/commands/check.d.ts +65 -0
  104. package/dist/commands/check.d.ts.map +1 -0
  105. package/dist/commands/check.js +61 -0
  106. package/dist/commands/check.js.map +1 -0
  107. package/dist/commands/format.d.ts +90 -0
  108. package/dist/commands/format.d.ts.map +1 -0
  109. package/dist/commands/format.js +80 -0
  110. package/dist/commands/format.js.map +1 -0
  111. package/dist/commands/query.d.ts +152 -0
  112. package/dist/commands/query.d.ts.map +1 -0
  113. package/dist/commands/query.js +151 -0
  114. package/dist/commands/query.js.map +1 -0
  115. package/dist/constants.d.ts +31 -0
  116. package/dist/constants.d.ts.map +1 -0
  117. package/dist/constants.js +51 -0
  118. package/dist/constants.js.map +1 -0
  119. package/dist/files.d.ts +58 -0
  120. package/dist/files.d.ts.map +1 -0
  121. package/dist/files.js +103 -0
  122. package/dist/files.js.map +1 -0
  123. package/dist/formatters.d.ts +39 -0
  124. package/dist/formatters.d.ts.map +1 -0
  125. package/dist/formatters.js +200 -0
  126. package/dist/formatters.js.map +1 -0
  127. package/dist/fragment.d.ts +22 -0
  128. package/dist/fragment.d.ts.map +1 -0
  129. package/dist/git/git.js +240 -0
  130. package/dist/git/git.js.map +1 -0
  131. package/dist/merge/conflict-detector.d.ts +89 -0
  132. package/dist/merge/conflict-detector.d.ts.map +1 -0
  133. package/dist/merge/conflict-detector.js +352 -0
  134. package/dist/merge/conflict-detector.js.map +1 -0
  135. package/dist/merge/conflict-formatter.js +143 -0
  136. package/dist/merge/conflict-formatter.js.map +1 -0
  137. package/dist/merge/driver.d.ts +54 -0
  138. package/dist/merge/driver.d.ts.map +1 -0
  139. package/dist/merge/driver.js +112 -0
  140. package/dist/merge/driver.js.map +1 -0
  141. package/dist/merge/entry-matcher.d.ts +50 -0
  142. package/dist/merge/entry-matcher.d.ts.map +1 -0
  143. package/dist/merge/entry-matcher.js +141 -0
  144. package/dist/merge/entry-matcher.js.map +1 -0
  145. package/dist/merge/entry-merger.js +194 -0
  146. package/dist/merge/entry-merger.js.map +1 -0
  147. package/dist/merge/merge-result-builder.d.ts +62 -0
  148. package/dist/merge/merge-result-builder.d.ts.map +1 -0
  149. package/dist/merge/merge-result-builder.js +89 -0
  150. package/dist/merge/merge-result-builder.js.map +1 -0
  151. package/dist/mod.d.ts +31 -0
  152. package/dist/mod.js +23 -0
  153. package/dist/model/document.d.ts +134 -0
  154. package/dist/model/document.d.ts.map +1 -0
  155. package/dist/model/document.js +275 -0
  156. package/dist/model/document.js.map +1 -0
  157. package/dist/model/line-index.d.ts +85 -0
  158. package/dist/model/line-index.d.ts.map +1 -0
  159. package/dist/model/line-index.js +159 -0
  160. package/dist/model/line-index.js.map +1 -0
  161. package/dist/model/workspace.d.ts +296 -0
  162. package/dist/model/workspace.d.ts.map +1 -0
  163. package/dist/model/workspace.js +562 -0
  164. package/dist/model/workspace.js.map +1 -0
  165. package/dist/parser.js +27 -0
  166. package/dist/parser.js.map +1 -0
  167. package/dist/parser.native.d.ts +51 -0
  168. package/dist/parser.native.d.ts.map +1 -0
  169. package/dist/parser.native.js +62 -0
  170. package/dist/parser.native.js.map +1 -0
  171. package/dist/parser.shared.d.ts +99 -0
  172. package/dist/parser.shared.d.ts.map +1 -0
  173. package/dist/parser.shared.js +124 -0
  174. package/dist/parser.shared.js.map +1 -0
  175. package/dist/parser.web.d.ts +67 -0
  176. package/dist/parser.web.d.ts.map +1 -0
  177. package/dist/parser.web.js +49 -0
  178. package/dist/parser.web.js.map +1 -0
  179. package/dist/schema/registry.d.ts +108 -0
  180. package/dist/schema/registry.d.ts.map +1 -0
  181. package/dist/schema/registry.js +281 -0
  182. package/dist/schema/registry.js.map +1 -0
  183. package/dist/semantic/analyzer.d.ts +107 -0
  184. package/dist/semantic/analyzer.d.ts.map +1 -0
  185. package/dist/semantic/analyzer.js +261 -0
  186. package/dist/semantic/analyzer.js.map +1 -0
  187. package/dist/services/change-tracker/change-tracker.d.ts +111 -0
  188. package/dist/services/change-tracker/change-tracker.d.ts.map +1 -0
  189. package/dist/services/change-tracker/change-tracker.js +62 -0
  190. package/dist/services/change-tracker/change-tracker.js.map +1 -0
  191. package/dist/services/change-tracker/create-tracker.d.ts +42 -0
  192. package/dist/services/change-tracker/create-tracker.d.ts.map +1 -0
  193. package/dist/services/change-tracker/create-tracker.js +53 -0
  194. package/dist/services/change-tracker/create-tracker.js.map +1 -0
  195. package/dist/services/change-tracker/git-tracker.d.ts +59 -0
  196. package/dist/services/change-tracker/git-tracker.d.ts.map +1 -0
  197. package/dist/services/change-tracker/git-tracker.js +218 -0
  198. package/dist/services/change-tracker/git-tracker.js.map +1 -0
  199. package/dist/services/change-tracker/timestamp-tracker.d.ts +22 -0
  200. package/dist/services/change-tracker/timestamp-tracker.d.ts.map +1 -0
  201. package/dist/services/change-tracker/timestamp-tracker.js +74 -0
  202. package/dist/services/change-tracker/timestamp-tracker.js.map +1 -0
  203. package/dist/services/definition.d.ts +37 -0
  204. package/dist/services/definition.d.ts.map +1 -0
  205. package/dist/services/definition.js +43 -0
  206. package/dist/services/definition.js.map +1 -0
  207. package/dist/services/entity-navigation.d.ts +200 -0
  208. package/dist/services/entity-navigation.d.ts.map +1 -0
  209. package/dist/services/entity-navigation.js +211 -0
  210. package/dist/services/entity-navigation.js.map +1 -0
  211. package/dist/services/hover.d.ts +81 -0
  212. package/dist/services/hover.d.ts.map +1 -0
  213. package/dist/services/hover.js +669 -0
  214. package/dist/services/hover.js.map +1 -0
  215. package/dist/services/query.d.ts +116 -0
  216. package/dist/services/query.d.ts.map +1 -0
  217. package/dist/services/query.js +225 -0
  218. package/dist/services/query.js.map +1 -0
  219. package/dist/services/references.d.ts +52 -0
  220. package/dist/services/references.d.ts.map +1 -0
  221. package/dist/services/references.js +66 -0
  222. package/dist/services/references.js.map +1 -0
  223. package/dist/services/semantic-tokens.d.ts +54 -0
  224. package/dist/services/semantic-tokens.d.ts.map +1 -0
  225. package/dist/services/semantic-tokens.js +213 -0
  226. package/dist/services/semantic-tokens.js.map +1 -0
  227. package/dist/services/synthesis.d.ts +90 -0
  228. package/dist/services/synthesis.d.ts.map +1 -0
  229. package/dist/services/synthesis.js +113 -0
  230. package/dist/services/synthesis.js.map +1 -0
  231. package/dist/source-map.d.ts +42 -0
  232. package/dist/source-map.d.ts.map +1 -0
  233. package/dist/source-map.js +170 -0
  234. package/dist/source-map.js.map +1 -0
  235. package/package.json +128 -0
  236. package/tree-sitter-thalo.wasm +0 -0
  237. package/web-tree-sitter.wasm +0 -0
@@ -0,0 +1,469 @@
1
+ //#region src/ast/ast-types.d.ts
2
+ /**
3
+ * AST (Abstract Syntax Tree) type definitions for the Thalo language.
4
+ *
5
+ * ## CST vs AST
6
+ *
7
+ * This module defines the **AST** - a cleaned-up, typed representation of Thalo source code.
8
+ * It is built from the **CST** (Concrete Syntax Tree) produced by tree-sitter.
9
+ *
10
+ * **CST (from tree-sitter grammar):**
11
+ * - Raw parse tree with all syntactic details
12
+ * - Node types like `primitive_type`, `unknown_type`, `timestamp`, etc.
13
+ * - May contain ERROR nodes for invalid syntax
14
+ * - Accessed via `SyntaxNode` interface
15
+ *
16
+ * **AST (this module):**
17
+ * - Typed, validated representation for semantic analysis
18
+ * - Converts CST nodes to typed interfaces (e.g., `PrimitiveType`, `Timestamp`)
19
+ * - Handles syntax errors gracefully via `SyntaxErrorNode` (e.g., unknown types become errors)
20
+ * - Uses `Result<T, E>` pattern for fields that may contain recoverable errors
21
+ *
22
+ * **Example:** The CST node `unknown_type` (for typos like "date-time") is converted to a
23
+ * `SyntaxErrorNode<"unknown_type">` in the AST, allowing the rest of the document to parse
24
+ * while still reporting the error precisely.
25
+ *
26
+ * The conversion happens in `extract.ts` (CST → AST) and `builder.ts` (timestamp decomposition).
27
+ *
28
+ * @module
29
+ */
30
+ /**
31
+ * Tree-sitter Point interface (row and column).
32
+ *
33
+ * Compatible with both tree-sitter (native) and web-tree-sitter (web).
34
+ */
35
+ interface Point {
36
+ row: number;
37
+ column: number;
38
+ }
39
+ /**
40
+ * Minimal SyntaxNode interface compatible with both tree-sitter and web-tree-sitter.
41
+ *
42
+ * This interface represents the common subset of properties and methods available
43
+ * in both tree-sitter's `SyntaxNode` and web-tree-sitter's `Node`.
44
+ *
45
+ * We define our own interface rather than importing from tree-sitter because:
46
+ * 1. tree-sitter is a peer dependency, not a regular dependency
47
+ * 2. The native and web versions have slightly different interfaces
48
+ * 3. We only need a minimal subset of the full tree-sitter API
49
+ *
50
+ * Note: In web-tree-sitter, namedChildren, children, and childrenForFieldName can
51
+ * contain null values. Native tree-sitter doesn't include nulls, but the type
52
+ * `(SyntaxNode | null)[]` is compatible with `SyntaxNode[]` (contravariance).
53
+ * Code should filter out nulls when needed using `.filter((c): c is SyntaxNode => c !== null)`.
54
+ */
55
+ interface SyntaxNode {
56
+ readonly id: number;
57
+ readonly type: string;
58
+ readonly text: string;
59
+ readonly startIndex: number;
60
+ readonly endIndex: number;
61
+ readonly startPosition: Point;
62
+ readonly endPosition: Point;
63
+ readonly namedChildren: readonly (SyntaxNode | null)[];
64
+ readonly children: readonly (SyntaxNode | null)[];
65
+ readonly parent: SyntaxNode | null;
66
+ childForFieldName(fieldName: string): SyntaxNode | null;
67
+ childrenForFieldName(fieldName: string): (SyntaxNode | null)[];
68
+ descendantForPosition(start: Point, end?: Point): SyntaxNode | null;
69
+ descendantsOfType(type: string | string[], startPosition?: Point, endPosition?: Point): (SyntaxNode | null)[];
70
+ readonly hasError: boolean;
71
+ }
72
+ /**
73
+ * Location information for an AST node
74
+ */
75
+ interface Location {
76
+ startIndex: number;
77
+ endIndex: number;
78
+ startPosition: Point;
79
+ endPosition: Point;
80
+ }
81
+ /**
82
+ * Base interface for all AST nodes
83
+ */
84
+ interface AstNode {
85
+ type: string;
86
+ location: Location;
87
+ /** The underlying tree-sitter node */
88
+ syntaxNode: SyntaxNode;
89
+ }
90
+ /**
91
+ * Known syntax error codes that can be emitted by the AST builder.
92
+ * These represent recoverable syntax errors where we can still produce a partial AST.
93
+ */
94
+ type SyntaxErrorCode = "missing_timezone" | "missing_entity" | "missing_title" | "missing_link_id" | "invalid_directive" | "invalid_timestamp" | "malformed_metadata" | "unknown_type" | "parse_error";
95
+ /**
96
+ * A syntax error node that can appear inline in the AST.
97
+ * Represents recoverable syntax errors that don't prevent further parsing.
98
+ *
99
+ * @example
100
+ * // A timestamp without timezone would have:
101
+ * timestamp: {
102
+ * type: "timestamp",
103
+ * value: "2026-01-05T18:00",
104
+ * date: { ... },
105
+ * time: { ... },
106
+ * timezone: {
107
+ * type: "syntax_error",
108
+ * code: "missing_timezone",
109
+ * message: "Timestamp requires timezone",
110
+ * text: "2026-01-05T18:00"
111
+ * }
112
+ * }
113
+ */
114
+ interface SyntaxErrorNode<Code extends SyntaxErrorCode = SyntaxErrorCode> extends AstNode {
115
+ type: "syntax_error";
116
+ /** The specific error code */
117
+ code: Code;
118
+ /** Human-readable error message */
119
+ message: string;
120
+ /** The malformed source text that caused the error */
121
+ text: string;
122
+ }
123
+ /**
124
+ * Result type for AST nodes that may contain syntax errors.
125
+ * Used to represent optional or validated fields that can fail gracefully.
126
+ *
127
+ * @example
128
+ * // In Timestamp type:
129
+ * timezone: Result<TimezonePart, "missing_timezone">
130
+ * // Can be either a valid TimezonePart or a SyntaxErrorNode with code "missing_timezone"
131
+ */
132
+ type Result<T, E extends SyntaxErrorCode> = T | SyntaxErrorNode<E>;
133
+ /**
134
+ * Type guard to check if a Result is a SyntaxErrorNode
135
+ */
136
+ declare function isSyntaxError<T, E extends SyntaxErrorCode>(result: Result<T, E>): result is SyntaxErrorNode<E>;
137
+ interface SourceFile extends AstNode {
138
+ type: "source_file";
139
+ entries: Entry[];
140
+ /** Root-level syntax errors (malformed entries that couldn't be parsed) */
141
+ syntaxErrors: SyntaxErrorNode[];
142
+ }
143
+ type Entry = InstanceEntry | SchemaEntry | SynthesisEntry | ActualizeEntry;
144
+ interface InstanceEntry extends AstNode {
145
+ type: "instance_entry";
146
+ header: InstanceHeader;
147
+ metadata: Metadata[];
148
+ content: Content | null;
149
+ }
150
+ interface InstanceHeader extends AstNode {
151
+ type: "instance_header";
152
+ timestamp: Timestamp;
153
+ directive: InstanceDirective;
154
+ entity: Entity;
155
+ title: Title;
156
+ link: Link | null;
157
+ tags: Tag[];
158
+ }
159
+ type InstanceDirective = "create" | "update";
160
+ type Entity = "lore" | "opinion" | "reference" | "journal";
161
+ interface SchemaEntry extends AstNode {
162
+ type: "schema_entry";
163
+ header: SchemaHeader;
164
+ metadataBlock: MetadataBlock | null;
165
+ sectionsBlock: SectionsBlock | null;
166
+ removeMetadataBlock: RemoveMetadataBlock | null;
167
+ removeSectionsBlock: RemoveSectionsBlock | null;
168
+ }
169
+ interface SchemaHeader extends AstNode {
170
+ type: "schema_header";
171
+ timestamp: Timestamp;
172
+ directive: SchemaDirective;
173
+ entityName: Identifier;
174
+ title: Title;
175
+ link: Link | null;
176
+ tags: Tag[];
177
+ }
178
+ type SchemaDirective = "define-entity" | "alter-entity";
179
+ interface SynthesisEntry extends AstNode {
180
+ type: "synthesis_entry";
181
+ header: SynthesisHeader;
182
+ metadata: Metadata[];
183
+ content: Content | null;
184
+ }
185
+ interface SynthesisHeader extends AstNode {
186
+ type: "synthesis_header";
187
+ timestamp: Timestamp;
188
+ title: Title;
189
+ linkId: Link;
190
+ tags: Tag[];
191
+ }
192
+ interface ActualizeEntry extends AstNode {
193
+ type: "actualize_entry";
194
+ header: ActualizeHeader;
195
+ metadata: Metadata[];
196
+ }
197
+ interface ActualizeHeader extends AstNode {
198
+ type: "actualize_header";
199
+ timestamp: Timestamp;
200
+ target: Link;
201
+ }
202
+ interface MetadataBlock extends AstNode {
203
+ type: "metadata_block";
204
+ fields: FieldDefinition[];
205
+ }
206
+ interface SectionsBlock extends AstNode {
207
+ type: "sections_block";
208
+ sections: SectionDefinition[];
209
+ }
210
+ interface RemoveMetadataBlock extends AstNode {
211
+ type: "remove_metadata_block";
212
+ fields: FieldRemoval[];
213
+ }
214
+ interface RemoveSectionsBlock extends AstNode {
215
+ type: "remove_sections_block";
216
+ sections: SectionRemoval[];
217
+ }
218
+ interface FieldDefinition extends AstNode {
219
+ type: "field_definition";
220
+ name: FieldName;
221
+ optional: boolean;
222
+ /** The type expression, or SyntaxErrorNode if an unknown type was used */
223
+ typeExpr: Result<TypeExpression, "unknown_type">;
224
+ defaultValue: DefaultValue | null;
225
+ description: Description | null;
226
+ }
227
+ interface FieldRemoval extends AstNode {
228
+ type: "field_removal";
229
+ name: FieldName;
230
+ reason: Description | null;
231
+ }
232
+ interface SectionDefinition extends AstNode {
233
+ type: "section_definition";
234
+ name: SectionName;
235
+ optional: boolean;
236
+ description: Description | null;
237
+ }
238
+ interface SectionRemoval extends AstNode {
239
+ type: "section_removal";
240
+ name: SectionName;
241
+ reason: Description | null;
242
+ }
243
+ type TypeExpression = PrimitiveType | LiteralType | ArrayType | UnionType;
244
+ interface PrimitiveType extends AstNode {
245
+ type: "primitive_type";
246
+ name: "string" | "datetime" | "daterange" | "link" | "number";
247
+ }
248
+ interface LiteralType extends AstNode {
249
+ type: "literal_type";
250
+ value: string;
251
+ }
252
+ interface ArrayType extends AstNode {
253
+ type: "array_type";
254
+ elementType: PrimitiveType | LiteralType | UnionType;
255
+ }
256
+ interface UnionType extends AstNode {
257
+ type: "union_type";
258
+ members: (PrimitiveType | LiteralType | ArrayType)[];
259
+ }
260
+ interface Metadata extends AstNode {
261
+ type: "metadata";
262
+ key: Key;
263
+ value: Value;
264
+ }
265
+ interface Content extends AstNode {
266
+ type: "content";
267
+ children: (MarkdownHeader | ContentLine)[];
268
+ }
269
+ interface MarkdownHeader extends AstNode {
270
+ type: "markdown_header";
271
+ text: string;
272
+ }
273
+ interface ContentLine extends AstNode {
274
+ type: "content_line";
275
+ text: string;
276
+ }
277
+ /**
278
+ * The date portion of a timestamp (YYYY-MM-DD)
279
+ */
280
+ interface DatePart extends AstNode {
281
+ type: "date_part";
282
+ year: number;
283
+ month: number;
284
+ day: number;
285
+ /** The formatted date string (YYYY-MM-DD) */
286
+ value: string;
287
+ }
288
+ /**
289
+ * The time portion of a timestamp (HH:MM)
290
+ */
291
+ interface TimePart extends AstNode {
292
+ type: "time_part";
293
+ hour: number;
294
+ minute: number;
295
+ /** The formatted time string (HH:MM) */
296
+ value: string;
297
+ }
298
+ /**
299
+ * The timezone portion of a timestamp (e.g., "Z", "+05:30", "-08:00")
300
+ */
301
+ interface TimezonePart extends AstNode {
302
+ type: "timezone_part";
303
+ /** The timezone string (e.g., "Z", "+05:30", "-08:00") */
304
+ value: string;
305
+ /** Offset from UTC in minutes (0 for Z, positive for east, negative for west) */
306
+ offsetMinutes: number;
307
+ }
308
+ /**
309
+ * A timestamp value with decomposed parts.
310
+ *
311
+ * The timezone can be a SyntaxErrorNode if missing.
312
+ *
313
+ * @example
314
+ * // Fully decomposed timestamp:
315
+ * {
316
+ * type: "timestamp",
317
+ * value: "2026-01-05T18:00Z",
318
+ * date: { type: "date_part", year: 2026, month: 1, day: 5, value: "2026-01-05", ... },
319
+ * time: { type: "time_part", hour: 18, minute: 0, value: "18:00", ... },
320
+ * timezone: { type: "timezone_part", value: "Z", offsetMinutes: 0, ... }
321
+ * }
322
+ *
323
+ * @example
324
+ * // Timestamp with missing timezone (syntax error):
325
+ * {
326
+ * type: "timestamp",
327
+ * value: "2026-01-05T18:00",
328
+ * date: { ... },
329
+ * time: { ... },
330
+ * timezone: { type: "syntax_error", code: "missing_timezone", message: "...", text: "..." }
331
+ * }
332
+ */
333
+ interface Timestamp extends AstNode {
334
+ type: "timestamp";
335
+ /** The full timestamp string */
336
+ value: string;
337
+ /** Decomposed date part */
338
+ date: DatePart;
339
+ /** Decomposed time part */
340
+ time: TimePart;
341
+ /** Decomposed timezone part, or SyntaxErrorNode if missing */
342
+ timezone: Result<TimezonePart, "missing_timezone">;
343
+ }
344
+ interface Title extends AstNode {
345
+ type: "title";
346
+ /** The title text without surrounding quotes */
347
+ value: string;
348
+ }
349
+ interface Link extends AstNode {
350
+ type: "link";
351
+ /** The link ID without the ^ prefix */
352
+ id: string;
353
+ }
354
+ interface Tag extends AstNode {
355
+ type: "tag";
356
+ /** The tag name without the # prefix */
357
+ name: string;
358
+ }
359
+ interface Identifier extends AstNode {
360
+ type: "identifier";
361
+ value: string;
362
+ }
363
+ interface Key extends AstNode {
364
+ type: "key";
365
+ value: string;
366
+ }
367
+ interface Value extends AstNode {
368
+ type: "value";
369
+ /** The raw value text */
370
+ raw: string;
371
+ /** The typed value content */
372
+ content: ValueContent;
373
+ }
374
+ /**
375
+ * Typed value content from the grammar.
376
+ * All values must be explicitly typed (no plain/unquoted values).
377
+ */
378
+ type ValueContent = QuotedValue | LinkValue | DatetimeValue | DaterangeValue | NumberValue | QueryValue | ValueArray;
379
+ interface QuotedValue extends AstNode {
380
+ type: "quoted_value";
381
+ /** The quoted text without surrounding quotes */
382
+ value: string;
383
+ }
384
+ interface LinkValue extends AstNode {
385
+ type: "link_value";
386
+ /** The parsed link */
387
+ link: Link;
388
+ }
389
+ interface DatetimeValue extends AstNode {
390
+ type: "datetime_value";
391
+ /** The full datetime value string */
392
+ value: string;
393
+ /** The date part (YYYY-MM-DD) */
394
+ date: string;
395
+ /** The time part if present (HH:MM) */
396
+ time: string | null;
397
+ /** The timezone if present (Z or +/-HH:MM) */
398
+ tz: string | null;
399
+ }
400
+ interface DaterangeValue extends AstNode {
401
+ type: "daterange";
402
+ /** The raw date range text */
403
+ raw: string;
404
+ }
405
+ interface NumberValue extends AstNode {
406
+ type: "number_value";
407
+ /** The raw number string */
408
+ raw: string;
409
+ /** The parsed numeric value */
410
+ value: number;
411
+ }
412
+ interface QueryValue extends AstNode {
413
+ type: "query_value";
414
+ /** The parsed query */
415
+ query: Query;
416
+ }
417
+ interface ValueArray extends AstNode {
418
+ type: "value_array";
419
+ /** Elements of the array (links, quoted values, datetimes, dateranges, numbers, or queries) */
420
+ elements: (Link | QuotedValue | DatetimeValue | DaterangeValue | NumberValue | Query)[];
421
+ }
422
+ interface Query extends AstNode {
423
+ type: "query";
424
+ /** The entity type to query */
425
+ entity: string;
426
+ /** The conditions (ANDed together) */
427
+ conditions: QueryCondition[];
428
+ }
429
+ type QueryCondition = FieldCondition | TagCondition | LinkCondition;
430
+ interface FieldCondition extends AstNode {
431
+ type: "field_condition";
432
+ /** The field name */
433
+ field: string;
434
+ /** The field value */
435
+ value: string;
436
+ }
437
+ interface TagCondition extends AstNode {
438
+ type: "tag_condition";
439
+ /** The tag (without #) */
440
+ tag: string;
441
+ }
442
+ interface LinkCondition extends AstNode {
443
+ type: "link_condition";
444
+ /** The link (without ^) */
445
+ linkId: string;
446
+ }
447
+ interface FieldName extends AstNode {
448
+ type: "field_name";
449
+ value: string;
450
+ }
451
+ interface SectionName extends AstNode {
452
+ type: "section_name";
453
+ value: string;
454
+ }
455
+ interface Description extends AstNode {
456
+ type: "description";
457
+ /** The description text without surrounding quotes */
458
+ value: string;
459
+ }
460
+ interface DefaultValue extends AstNode {
461
+ type: "default_value";
462
+ /** The raw default value text */
463
+ raw: string;
464
+ /** The typed value content (quoted_value, link, datetime, or number) */
465
+ content: QuotedValue | Link | DatetimeValue | NumberValue;
466
+ }
467
+ //#endregion
468
+ export { ActualizeEntry, Entry, FieldName, Identifier, InstanceEntry, Key, Link, Location, Query, QueryCondition, SchemaEntry, SectionName, SourceFile, SyntaxNode, SynthesisEntry, Tag, Timestamp, TypeExpression, ValueContent, isSyntaxError };
469
+ //# sourceMappingURL=ast-types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ast-types.d.ts","names":[],"sources":["../../src/ast/ast-types.ts"],"sourcesContent":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ //#region src/ast/ast-types.ts
2
+ /**
3
+ * Type guard to check if a Result is a SyntaxErrorNode
4
+ */
5
+ function isSyntaxError(result) {
6
+ return result.type === "syntax_error";
7
+ }
8
+
9
+ //#endregion
10
+ export { isSyntaxError };
11
+ //# sourceMappingURL=ast-types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ast-types.js","names":[],"sources":["../../src/ast/ast-types.ts"],"sourcesContent":["/**\n * AST (Abstract Syntax Tree) type definitions for the Thalo language.\n *\n * ## CST vs AST\n *\n * This module defines the **AST** - a cleaned-up, typed representation of Thalo source code.\n * It is built from the **CST** (Concrete Syntax Tree) produced by tree-sitter.\n *\n * **CST (from tree-sitter grammar):**\n * - Raw parse tree with all syntactic details\n * - Node types like `primitive_type`, `unknown_type`, `timestamp`, etc.\n * - May contain ERROR nodes for invalid syntax\n * - Accessed via `SyntaxNode` interface\n *\n * **AST (this module):**\n * - Typed, validated representation for semantic analysis\n * - Converts CST nodes to typed interfaces (e.g., `PrimitiveType`, `Timestamp`)\n * - Handles syntax errors gracefully via `SyntaxErrorNode` (e.g., unknown types become errors)\n * - Uses `Result<T, E>` pattern for fields that may contain recoverable errors\n *\n * **Example:** The CST node `unknown_type` (for typos like \"date-time\") is converted to a\n * `SyntaxErrorNode<\"unknown_type\">` in the AST, allowing the rest of the document to parse\n * while still reporting the error precisely.\n *\n * The conversion happens in `extract.ts` (CST → AST) and `builder.ts` (timestamp decomposition).\n *\n * @module\n */\n\n/**\n * Tree-sitter Point interface (row and column).\n *\n * Compatible with both tree-sitter (native) and web-tree-sitter (web).\n */\nexport interface Point {\n row: number;\n column: number;\n}\n\n/**\n * Minimal SyntaxNode interface compatible with both tree-sitter and web-tree-sitter.\n *\n * This interface represents the common subset of properties and methods available\n * in both tree-sitter's `SyntaxNode` and web-tree-sitter's `Node`.\n *\n * We define our own interface rather than importing from tree-sitter because:\n * 1. tree-sitter is a peer dependency, not a regular dependency\n * 2. The native and web versions have slightly different interfaces\n * 3. We only need a minimal subset of the full tree-sitter API\n *\n * Note: In web-tree-sitter, namedChildren, children, and childrenForFieldName can\n * contain null values. Native tree-sitter doesn't include nulls, but the type\n * `(SyntaxNode | null)[]` is compatible with `SyntaxNode[]` (contravariance).\n * Code should filter out nulls when needed using `.filter((c): c is SyntaxNode => c !== null)`.\n */\nexport interface SyntaxNode {\n readonly id: number;\n readonly type: string;\n readonly text: string;\n readonly startIndex: number;\n readonly endIndex: number;\n readonly startPosition: Point;\n readonly endPosition: Point;\n readonly namedChildren: readonly (SyntaxNode | null)[];\n readonly children: readonly (SyntaxNode | null)[];\n readonly parent: SyntaxNode | null;\n childForFieldName(fieldName: string): SyntaxNode | null;\n childrenForFieldName(fieldName: string): (SyntaxNode | null)[];\n descendantForPosition(start: Point, end?: Point): SyntaxNode | null;\n descendantsOfType(\n type: string | string[],\n startPosition?: Point,\n endPosition?: Point,\n ): (SyntaxNode | null)[];\n readonly hasError: boolean;\n}\n\n/**\n * Location information for an AST node\n */\nexport interface Location {\n startIndex: number;\n endIndex: number;\n startPosition: Point;\n endPosition: Point;\n}\n\n/**\n * Base interface for all AST nodes\n */\nexport interface AstNode {\n type: string;\n location: Location;\n /** The underlying tree-sitter node */\n syntaxNode: SyntaxNode;\n}\n\n// ===================\n// Syntax Errors\n// ===================\n\n/**\n * Known syntax error codes that can be emitted by the AST builder.\n * These represent recoverable syntax errors where we can still produce a partial AST.\n */\nexport type SyntaxErrorCode =\n | \"missing_timezone\"\n | \"missing_entity\"\n | \"missing_title\"\n | \"missing_link_id\"\n | \"invalid_directive\"\n | \"invalid_timestamp\"\n | \"malformed_metadata\"\n | \"unknown_type\"\n | \"parse_error\";\n\n/**\n * A syntax error node that can appear inline in the AST.\n * Represents recoverable syntax errors that don't prevent further parsing.\n *\n * @example\n * // A timestamp without timezone would have:\n * timestamp: {\n * type: \"timestamp\",\n * value: \"2026-01-05T18:00\",\n * date: { ... },\n * time: { ... },\n * timezone: {\n * type: \"syntax_error\",\n * code: \"missing_timezone\",\n * message: \"Timestamp requires timezone\",\n * text: \"2026-01-05T18:00\"\n * }\n * }\n */\nexport interface SyntaxErrorNode<Code extends SyntaxErrorCode = SyntaxErrorCode> extends AstNode {\n type: \"syntax_error\";\n /** The specific error code */\n code: Code;\n /** Human-readable error message */\n message: string;\n /** The malformed source text that caused the error */\n text: string;\n}\n\n/**\n * Result type for AST nodes that may contain syntax errors.\n * Used to represent optional or validated fields that can fail gracefully.\n *\n * @example\n * // In Timestamp type:\n * timezone: Result<TimezonePart, \"missing_timezone\">\n * // Can be either a valid TimezonePart or a SyntaxErrorNode with code \"missing_timezone\"\n */\nexport type Result<T, E extends SyntaxErrorCode> = T | SyntaxErrorNode<E>;\n\n/**\n * Type guard to check if a Result is a SyntaxErrorNode\n */\nexport function isSyntaxError<T, E extends SyntaxErrorCode>(\n result: Result<T, E>,\n): result is SyntaxErrorNode<E> {\n return (result as SyntaxErrorNode).type === \"syntax_error\";\n}\n\n/**\n * Type guard to check if a Result is a valid value (not a SyntaxErrorNode)\n */\nexport function isValidResult<T, E extends SyntaxErrorCode>(result: Result<T, E>): result is T {\n return (result as SyntaxErrorNode).type !== \"syntax_error\";\n}\n\n// ===================\n// Source File\n// ===================\n\nexport interface SourceFile extends AstNode {\n type: \"source_file\";\n entries: Entry[];\n /** Root-level syntax errors (malformed entries that couldn't be parsed) */\n syntaxErrors: SyntaxErrorNode[];\n}\n\n// ===================\n// Entries\n// ===================\n\nexport type Entry = InstanceEntry | SchemaEntry | SynthesisEntry | ActualizeEntry;\n\n// ===================\n// Instance Entries (create/update)\n// ===================\n\nexport interface InstanceEntry extends AstNode {\n type: \"instance_entry\";\n header: InstanceHeader;\n metadata: Metadata[];\n content: Content | null;\n}\n\nexport interface InstanceHeader extends AstNode {\n type: \"instance_header\";\n timestamp: Timestamp;\n directive: InstanceDirective;\n entity: Entity;\n title: Title;\n link: Link | null;\n tags: Tag[];\n}\n\nexport type InstanceDirective = \"create\" | \"update\";\n\nexport type Entity = \"lore\" | \"opinion\" | \"reference\" | \"journal\";\n\n// ===================\n// Schema Entries (define-entity/alter-entity)\n// ===================\n\nexport interface SchemaEntry extends AstNode {\n type: \"schema_entry\";\n header: SchemaHeader;\n metadataBlock: MetadataBlock | null;\n sectionsBlock: SectionsBlock | null;\n removeMetadataBlock: RemoveMetadataBlock | null;\n removeSectionsBlock: RemoveSectionsBlock | null;\n}\n\nexport interface SchemaHeader extends AstNode {\n type: \"schema_header\";\n timestamp: Timestamp;\n directive: SchemaDirective;\n entityName: Identifier;\n title: Title;\n link: Link | null;\n tags: Tag[];\n}\n\nexport type SchemaDirective = \"define-entity\" | \"alter-entity\";\n\n// ===================\n// Synthesis Entries (define-synthesis)\n// ===================\n\nexport interface SynthesisEntry extends AstNode {\n type: \"synthesis_entry\";\n header: SynthesisHeader;\n metadata: Metadata[];\n content: Content | null;\n}\n\nexport interface SynthesisHeader extends AstNode {\n type: \"synthesis_header\";\n timestamp: Timestamp;\n title: Title;\n linkId: Link;\n tags: Tag[];\n}\n\n// ===================\n// Actualize Entries (actualize-synthesis)\n// ===================\n\nexport interface ActualizeEntry extends AstNode {\n type: \"actualize_entry\";\n header: ActualizeHeader;\n metadata: Metadata[];\n}\n\nexport interface ActualizeHeader extends AstNode {\n type: \"actualize_header\";\n timestamp: Timestamp;\n target: Link;\n}\n\n// ===================\n// Schema Blocks\n// ===================\n\nexport interface MetadataBlock extends AstNode {\n type: \"metadata_block\";\n fields: FieldDefinition[];\n}\n\nexport interface SectionsBlock extends AstNode {\n type: \"sections_block\";\n sections: SectionDefinition[];\n}\n\nexport interface RemoveMetadataBlock extends AstNode {\n type: \"remove_metadata_block\";\n fields: FieldRemoval[];\n}\n\nexport interface RemoveSectionsBlock extends AstNode {\n type: \"remove_sections_block\";\n sections: SectionRemoval[];\n}\n\n// ===================\n// Field Definitions\n// ===================\n\nexport interface FieldDefinition extends AstNode {\n type: \"field_definition\";\n name: FieldName;\n optional: boolean;\n /** The type expression, or SyntaxErrorNode if an unknown type was used */\n typeExpr: Result<TypeExpression, \"unknown_type\">;\n defaultValue: DefaultValue | null;\n description: Description | null;\n}\n\nexport interface FieldRemoval extends AstNode {\n type: \"field_removal\";\n name: FieldName;\n reason: Description | null;\n}\n\n// ===================\n// Section Definitions\n// ===================\n\nexport interface SectionDefinition extends AstNode {\n type: \"section_definition\";\n name: SectionName;\n optional: boolean;\n description: Description | null;\n}\n\nexport interface SectionRemoval extends AstNode {\n type: \"section_removal\";\n name: SectionName;\n reason: Description | null;\n}\n\n// ===================\n// Type Expressions\n// ===================\n\nexport type TypeExpression = PrimitiveType | LiteralType | ArrayType | UnionType;\n\nexport interface PrimitiveType extends AstNode {\n type: \"primitive_type\";\n name: \"string\" | \"datetime\" | \"daterange\" | \"link\" | \"number\";\n}\n\nexport interface LiteralType extends AstNode {\n type: \"literal_type\";\n value: string;\n}\n\nexport interface ArrayType extends AstNode {\n type: \"array_type\";\n elementType: PrimitiveType | LiteralType | UnionType;\n}\n\nexport interface UnionType extends AstNode {\n type: \"union_type\";\n members: (PrimitiveType | LiteralType | ArrayType)[];\n}\n\n// ===================\n// Metadata (instance entries)\n// ===================\n\nexport interface Metadata extends AstNode {\n type: \"metadata\";\n key: Key;\n value: Value;\n}\n\n// ===================\n// Content (instance entries)\n// ===================\n\nexport interface Content extends AstNode {\n type: \"content\";\n children: (MarkdownHeader | ContentLine)[];\n}\n\nexport interface MarkdownHeader extends AstNode {\n type: \"markdown_header\";\n text: string;\n}\n\nexport interface ContentLine extends AstNode {\n type: \"content_line\";\n text: string;\n}\n\n// ===================\n// Terminal Nodes\n// ===================\n\n// ===================\n// Timestamp Parts (decomposed)\n// ===================\n\n/**\n * The date portion of a timestamp (YYYY-MM-DD)\n */\nexport interface DatePart extends AstNode {\n type: \"date_part\";\n year: number;\n month: number;\n day: number;\n /** The formatted date string (YYYY-MM-DD) */\n value: string;\n}\n\n/**\n * The time portion of a timestamp (HH:MM)\n */\nexport interface TimePart extends AstNode {\n type: \"time_part\";\n hour: number;\n minute: number;\n /** The formatted time string (HH:MM) */\n value: string;\n}\n\n/**\n * The timezone portion of a timestamp (e.g., \"Z\", \"+05:30\", \"-08:00\")\n */\nexport interface TimezonePart extends AstNode {\n type: \"timezone_part\";\n /** The timezone string (e.g., \"Z\", \"+05:30\", \"-08:00\") */\n value: string;\n /** Offset from UTC in minutes (0 for Z, positive for east, negative for west) */\n offsetMinutes: number;\n}\n\n/**\n * A timestamp value with decomposed parts.\n *\n * The timezone can be a SyntaxErrorNode if missing.\n *\n * @example\n * // Fully decomposed timestamp:\n * {\n * type: \"timestamp\",\n * value: \"2026-01-05T18:00Z\",\n * date: { type: \"date_part\", year: 2026, month: 1, day: 5, value: \"2026-01-05\", ... },\n * time: { type: \"time_part\", hour: 18, minute: 0, value: \"18:00\", ... },\n * timezone: { type: \"timezone_part\", value: \"Z\", offsetMinutes: 0, ... }\n * }\n *\n * @example\n * // Timestamp with missing timezone (syntax error):\n * {\n * type: \"timestamp\",\n * value: \"2026-01-05T18:00\",\n * date: { ... },\n * time: { ... },\n * timezone: { type: \"syntax_error\", code: \"missing_timezone\", message: \"...\", text: \"...\" }\n * }\n */\nexport interface Timestamp extends AstNode {\n type: \"timestamp\";\n /** The full timestamp string */\n value: string;\n /** Decomposed date part */\n date: DatePart;\n /** Decomposed time part */\n time: TimePart;\n /** Decomposed timezone part, or SyntaxErrorNode if missing */\n timezone: Result<TimezonePart, \"missing_timezone\">;\n}\n\nexport interface Title extends AstNode {\n type: \"title\";\n /** The title text without surrounding quotes */\n value: string;\n}\n\nexport interface Link extends AstNode {\n type: \"link\";\n /** The link ID without the ^ prefix */\n id: string;\n}\n\nexport interface Tag extends AstNode {\n type: \"tag\";\n /** The tag name without the # prefix */\n name: string;\n}\n\nexport interface Identifier extends AstNode {\n type: \"identifier\";\n value: string;\n}\n\nexport interface Key extends AstNode {\n type: \"key\";\n value: string;\n}\n\nexport interface Value extends AstNode {\n type: \"value\";\n /** The raw value text */\n raw: string;\n /** The typed value content */\n content: ValueContent;\n}\n\n/**\n * Typed value content from the grammar.\n * All values must be explicitly typed (no plain/unquoted values).\n */\nexport type ValueContent =\n | QuotedValue\n | LinkValue\n | DatetimeValue\n | DaterangeValue\n | NumberValue\n | QueryValue\n | ValueArray;\n\nexport interface QuotedValue extends AstNode {\n type: \"quoted_value\";\n /** The quoted text without surrounding quotes */\n value: string;\n}\n\nexport interface LinkValue extends AstNode {\n type: \"link_value\";\n /** The parsed link */\n link: Link;\n}\n\nexport interface DatetimeValue extends AstNode {\n type: \"datetime_value\";\n /** The full datetime value string */\n value: string;\n /** The date part (YYYY-MM-DD) */\n date: string;\n /** The time part if present (HH:MM) */\n time: string | null;\n /** The timezone if present (Z or +/-HH:MM) */\n tz: string | null;\n}\n\nexport interface DaterangeValue extends AstNode {\n type: \"daterange\";\n /** The raw date range text */\n raw: string;\n}\n\nexport interface NumberValue extends AstNode {\n type: \"number_value\";\n /** The raw number string */\n raw: string;\n /** The parsed numeric value */\n value: number;\n}\n\nexport interface QueryValue extends AstNode {\n type: \"query_value\";\n /** The parsed query */\n query: Query;\n}\n\nexport interface ValueArray extends AstNode {\n type: \"value_array\";\n /** Elements of the array (links, quoted values, datetimes, dateranges, numbers, or queries) */\n elements: (Link | QuotedValue | DatetimeValue | DaterangeValue | NumberValue | Query)[];\n}\n\nexport interface Query extends AstNode {\n type: \"query\";\n /** The entity type to query */\n entity: string;\n /** The conditions (ANDed together) */\n conditions: QueryCondition[];\n}\n\nexport type QueryCondition = FieldCondition | TagCondition | LinkCondition;\n\nexport interface FieldCondition extends AstNode {\n type: \"field_condition\";\n /** The field name */\n field: string;\n /** The field value */\n value: string;\n}\n\nexport interface TagCondition extends AstNode {\n type: \"tag_condition\";\n /** The tag (without #) */\n tag: string;\n}\n\nexport interface LinkCondition extends AstNode {\n type: \"link_condition\";\n /** The link (without ^) */\n linkId: string;\n}\n\nexport interface FieldName extends AstNode {\n type: \"field_name\";\n value: string;\n}\n\nexport interface SectionName extends AstNode {\n type: \"section_name\";\n value: string;\n}\n\nexport interface Description extends AstNode {\n type: \"description\";\n /** The description text without surrounding quotes */\n value: string;\n}\n\nexport interface DefaultValue extends AstNode {\n type: \"default_value\";\n /** The raw default value text */\n raw: string;\n /** The typed value content (quoted_value, link, datetime, or number) */\n content: QuotedValue | Link | DatetimeValue | NumberValue;\n}\n"],"mappings":";;;;AA+JA,SAAgB,cACd,QAC8B;AAC9B,QAAQ,OAA2B,SAAS"}
@@ -0,0 +1,158 @@
1
+ import { formatTimestamp } from "../formatters.js";
2
+
3
+ //#region src/ast/builder.ts
4
+ /**
5
+ * Extract location information from a tree-sitter node
6
+ */
7
+ function extractLocation(node) {
8
+ return {
9
+ startIndex: node.startIndex,
10
+ endIndex: node.endIndex,
11
+ startPosition: node.startPosition,
12
+ endPosition: node.endPosition
13
+ };
14
+ }
15
+ /**
16
+ * Create a synthetic location from two points
17
+ */
18
+ function syntheticLocation(start, end) {
19
+ return {
20
+ startIndex: start.index,
21
+ endIndex: end.index,
22
+ startPosition: start.position,
23
+ endPosition: end.position
24
+ };
25
+ }
26
+ /**
27
+ * Create a syntax error node for recoverable parse errors
28
+ */
29
+ function createSyntaxError(code, message, text, node) {
30
+ return {
31
+ type: "syntax_error",
32
+ code,
33
+ message,
34
+ text,
35
+ location: extractLocation(node),
36
+ syntaxNode: node
37
+ };
38
+ }
39
+ /**
40
+ * Create a syntax error node with a synthetic location
41
+ */
42
+ function createSyntaxErrorAt(code, message, text, location, syntaxNode) {
43
+ return {
44
+ type: "syntax_error",
45
+ code,
46
+ message,
47
+ text,
48
+ location,
49
+ syntaxNode
50
+ };
51
+ }
52
+ /**
53
+ * Parse a timezone string and return the offset in minutes
54
+ *
55
+ * @param tz - Timezone string like "Z", "+05:30", "-08:00"
56
+ * @returns Offset from UTC in minutes (0 for Z, positive for east, negative for west)
57
+ */
58
+ function parseTimezoneOffset(tz) {
59
+ if (tz === "Z") return 0;
60
+ const match = tz.match(/^([+-])(\d{2}):(\d{2})$/);
61
+ if (!match) throw new Error(`Invalid timezone format: "${tz}"`);
62
+ const sign = match[1] === "+" ? 1 : -1;
63
+ const hours = parseInt(match[2], 10);
64
+ const minutes = parseInt(match[3], 10);
65
+ return sign * (hours * 60 + minutes);
66
+ }
67
+ /**
68
+ * Build a DatePart from a date string (YYYY-MM-DD)
69
+ */
70
+ function buildDatePart(dateStr, location, syntaxNode) {
71
+ const match = dateStr.match(/^(\d{4})-(\d{2})-(\d{2})$/);
72
+ if (!match) throw new Error(`Invalid date format: "${dateStr}"`);
73
+ return {
74
+ type: "date_part",
75
+ year: parseInt(match[1], 10),
76
+ month: parseInt(match[2], 10),
77
+ day: parseInt(match[3], 10),
78
+ value: dateStr,
79
+ location,
80
+ syntaxNode
81
+ };
82
+ }
83
+ /**
84
+ * Build a TimePart from a time string (HH:MM)
85
+ */
86
+ function buildTimePart(timeStr, location, syntaxNode) {
87
+ const match = timeStr.match(/^(\d{2}):(\d{2})$/);
88
+ if (!match) throw new Error(`Invalid time format: "${timeStr}"`);
89
+ return {
90
+ type: "time_part",
91
+ hour: parseInt(match[1], 10),
92
+ minute: parseInt(match[2], 10),
93
+ value: timeStr,
94
+ location,
95
+ syntaxNode
96
+ };
97
+ }
98
+ /**
99
+ * Build a TimezonePart from a timezone string
100
+ */
101
+ function buildTimezonePart(tzStr, location, syntaxNode) {
102
+ return {
103
+ type: "timezone_part",
104
+ value: tzStr,
105
+ offsetMinutes: parseTimezoneOffset(tzStr),
106
+ location,
107
+ syntaxNode
108
+ };
109
+ }
110
+ /**
111
+ * Build a Timestamp with decomposed parts from tree-sitter child nodes.
112
+ *
113
+ * The grammar decomposes timestamp into:
114
+ * - timestamp_date: "YYYY-MM-DD" (date)
115
+ * - timestamp_t: "T" (separator, not a field)
116
+ * - timestamp_time: "HH:MM" (time)
117
+ * - timestamp_tz: "Z" or "±HH:MM" (optional timezone)
118
+ *
119
+ * If the timezone is missing, a SyntaxErrorNode is created for the timezone field.
120
+ *
121
+ * @param node - The tree-sitter timestamp node with date, time, and optional tz children
122
+ * @returns Timestamp with decomposed date, time, and timezone parts
123
+ */
124
+ function buildTimestamp(node) {
125
+ const text = node.text;
126
+ const dateNode = node.childForFieldName("date");
127
+ const timeNode = node.childForFieldName("time");
128
+ const tzNode = node.childForFieldName("tz");
129
+ if (!dateNode || !timeNode) throw new Error(`Invalid timestamp structure: missing date or time node in "${text}"`);
130
+ const dateLocation = extractLocation(dateNode);
131
+ const datePart = buildDatePart(dateNode.text, dateLocation, dateNode);
132
+ const timeLocation = extractLocation(timeNode);
133
+ const timePart = buildTimePart(timeNode.text, timeLocation, timeNode);
134
+ let timezone;
135
+ if (tzNode) {
136
+ const tzLocation = extractLocation(tzNode);
137
+ timezone = buildTimezonePart(tzNode.text, tzLocation, tzNode);
138
+ } else timezone = createSyntaxErrorAt("missing_timezone", "Timestamp requires timezone (e.g., Z or +05:30)", text, syntheticLocation({
139
+ index: timeNode.endIndex,
140
+ position: timeNode.endPosition
141
+ }, {
142
+ index: timeNode.endIndex,
143
+ position: timeNode.endPosition
144
+ }), node);
145
+ return {
146
+ type: "timestamp",
147
+ value: text,
148
+ date: datePart,
149
+ time: timePart,
150
+ timezone,
151
+ location: extractLocation(node),
152
+ syntaxNode: node
153
+ };
154
+ }
155
+
156
+ //#endregion
157
+ export { buildTimestamp, createSyntaxError };
158
+ //# sourceMappingURL=builder.js.map