@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 @@
1
+ {"version":3,"file":"query.js","names":["info: QueryEntryInfo","sinceMarker: ChangeMarker | null","parseQueryStringService","results: InstanceEntry[]","entries: QueryEntryInfo[]"],"sources":["../../src/commands/query.ts"],"sourcesContent":["/**\n * Query command - executes a query on a workspace and returns structured results.\n */\n\nimport type { Workspace } from \"../model/workspace.js\";\nimport type { Query, QueryCondition } from \"../services/query.js\";\nimport type { InstanceEntry, Timestamp } from \"../ast/ast-types.js\";\nimport {\n parseQueryString as parseQueryStringService,\n validateQueryEntities,\n executeQueries,\n formatQuery,\n} from \"../services/query.js\";\nimport { findEntryFile, getEntrySourceText } from \"../services/synthesis.js\";\nimport { formatTimestamp } from \"../formatters.js\";\nimport {\n parseCheckpoint,\n type ChangeMarker,\n type ChangeTracker,\n} from \"../services/change-tracker/change-tracker.js\";\n\n/**\n * Convert a timestamp to epoch milliseconds for correct comparison across timezones\n */\nfunction timestampToEpoch(ts: Timestamp): number {\n const isoStr = formatTimestamp(ts);\n return Date.parse(isoStr);\n}\n\n/**\n * Parse an ISO timestamp string to epoch milliseconds\n */\nfunction parseTimestampToEpoch(isoStr: string): number {\n return Date.parse(isoStr);\n}\n\n// Re-export parseQueryString from service for backward compatibility\nexport { parseQueryString } from \"../services/query.js\";\n\n// ===================\n// Types\n// ===================\n\n/**\n * Information about a condition in a query.\n */\nexport interface QueryConditionInfo {\n kind: QueryCondition[\"kind\"];\n /** For field conditions */\n field?: string;\n value?: string;\n /** For tag conditions */\n tag?: string;\n /** For link conditions */\n link?: string;\n}\n\n/**\n * Information about an entry that matched a query.\n */\nexport interface QueryEntryInfo {\n /** File path containing the entry */\n file: string;\n /** Formatted timestamp string */\n timestamp: string;\n /** Entity type (e.g., \"lore\", \"opinion\") */\n entity: string;\n /** Entry title */\n title: string;\n /** Link ID if present */\n linkId: string | null;\n /** Tags on the entry */\n tags: string[];\n /** 1-based start line */\n startLine: number;\n /** 1-based end line */\n endLine: number;\n /** Raw source text of the entry (optional, for \"raw\" format) */\n rawText?: string;\n}\n\n/**\n * Result of running the query command (single query).\n */\nexport interface QueryResult {\n /** The parsed query */\n query: Query;\n /** Formatted query string for display */\n queryString: string;\n /** Matching entries */\n entries: QueryEntryInfo[];\n /** Total count (may be more than entries.length if limited) */\n totalCount: number;\n}\n\n/**\n * Result of running queries (multiple queries).\n */\nexport interface QueriesResult {\n /** The parsed queries */\n queries: Query[];\n /** Formatted query string for display */\n queryString: string;\n /** Matching entries (deduplicated across all queries) */\n entries: QueryEntryInfo[];\n /** Total count (may be more than entries.length if limited) */\n totalCount: number;\n}\n\n/**\n * Error result when queries reference unknown entities.\n */\nexport interface QueryValidationError {\n kind: \"unknown-entities\";\n /** The unknown entity names */\n entities: string[];\n /** Human-readable error message */\n message: string;\n}\n\n/**\n * Options for running the query command.\n */\nexport interface RunQueryOptions {\n /** Maximum number of results to return */\n limit?: number;\n /** Include raw source text in results */\n includeRawText?: boolean;\n /** Whether to validate that queried entities exist (default: true) */\n validateEntities?: boolean;\n /**\n * Only return entries since this checkpoint.\n * Format: \"ts:2026-01-10T15:00Z\" for timestamp-based filtering.\n * Format: \"git:abc123\" for git-based filtering (requires tracker option).\n */\n since?: string;\n /**\n * Change tracker for git-based filtering.\n * Required when using git checkpoints (git:...).\n */\n tracker?: ChangeTracker;\n}\n\n/**\n * Error result when a checkpoint is invalid or missing required options.\n */\nexport interface CheckpointError {\n kind: \"invalid-checkpoint\";\n /** Human-readable error message */\n message: string;\n}\n\n/**\n * Convert an InstanceEntry to QueryEntryInfo.\n */\nfunction toQueryEntryInfo(\n entry: InstanceEntry,\n file: string,\n workspace: Workspace,\n includeRawText: boolean,\n): QueryEntryInfo {\n const info: QueryEntryInfo = {\n file,\n timestamp: formatTimestamp(entry.header.timestamp),\n entity: entry.header.entity,\n title: entry.header.title.value,\n linkId: entry.header.link?.id ?? null,\n tags: entry.header.tags.map((t) => t.name),\n startLine: entry.location.startPosition.row + 1,\n endLine: entry.location.endPosition.row + 1,\n };\n\n if (includeRawText) {\n const model = workspace.getModel(file);\n if (model) {\n info.rawText = getEntrySourceText(entry, model.source);\n }\n }\n\n return info;\n}\n\n/**\n * Run multiple queries on a workspace.\n * Supports comma-separated query syntax like \"lore, journal where #career\".\n *\n * @param workspace - The workspace to query\n * @param queryString - The query string to parse and execute (may contain multiple queries)\n * @param options - Query options\n * @returns Structured query results, validation error, checkpoint error, or null if query syntax is invalid\n */\nexport async function runQueries(\n workspace: Workspace,\n queryString: string,\n options: RunQueryOptions = {},\n): Promise<QueriesResult | QueryValidationError | CheckpointError | null> {\n const { limit, includeRawText = false, validateEntities = true, since, tracker } = options;\n\n // Parse and validate the since checkpoint if provided\n let sinceMarker: ChangeMarker | null = null;\n\n if (since) {\n sinceMarker = parseCheckpoint(since);\n if (!sinceMarker) {\n return {\n kind: \"invalid-checkpoint\",\n message: `Invalid checkpoint format: '${since}'. Use 'ts:2026-01-10T15:00Z' for timestamps or 'git:abc123' for git commits.`,\n };\n }\n\n // Git checkpoints require a tracker\n if (sinceMarker.type === \"git\" && !tracker) {\n return {\n kind: \"invalid-checkpoint\",\n message: `Git checkpoints require a change tracker. Provide a tracker option or use timestamp checkpoints (ts:...).`,\n };\n }\n }\n\n // Parse the queries\n const queries = parseQueryStringService(queryString);\n if (!queries) {\n return null;\n }\n\n // Validate entity names if requested\n if (validateEntities) {\n const unknownEntities = validateQueryEntities(workspace, queries);\n if (unknownEntities.length > 0) {\n return {\n kind: \"unknown-entities\",\n entities: unknownEntities,\n message: `Unknown entity type${unknownEntities.length > 1 ? \"s\" : \"\"}: ${unknownEntities.map((e) => `'${e}'`).join(\", \")}. Define ${unknownEntities.length > 1 ? \"them\" : \"it\"} using 'define-entity'.`,\n };\n }\n }\n\n let results: InstanceEntry[];\n\n if (sinceMarker?.type === \"git\" && tracker) {\n // Use change tracker for git-based filtering\n const changedResult = await tracker.getChangedEntries(workspace, queries, sinceMarker);\n results = changedResult.entries;\n } else {\n // Execute all queries\n results = executeQueries(workspace, queries);\n\n // Filter by since timestamp if provided\n if (sinceMarker?.type === \"ts\") {\n const sinceEpoch = parseTimestampToEpoch(sinceMarker.value);\n results = results.filter((entry) => {\n const entryEpoch = timestampToEpoch(entry.header.timestamp);\n return entryEpoch > sinceEpoch;\n });\n }\n }\n\n // Convert to QueryEntryInfo\n const entries: QueryEntryInfo[] = [];\n const limitedResults = limit && limit > 0 ? results.slice(0, limit) : results;\n\n for (const entry of limitedResults) {\n const file = findEntryFile(workspace, entry);\n if (file) {\n entries.push(toQueryEntryInfo(entry, file, workspace, includeRawText));\n }\n }\n\n return {\n queries,\n queryString: queries.map(formatQuery).join(\", \"),\n entries,\n totalCount: results.length,\n };\n}\n\n/**\n * Run the query command on a workspace.\n * For backward compatibility, this only supports a single query.\n * Use `runQueries` for multiple queries or comma-separated syntax.\n *\n * @param workspace - The workspace to query\n * @param queryString - The query string to parse and execute\n * @param options - Query options\n * @returns Structured query results, validation error, checkpoint error, or null if query is invalid\n */\nexport async function runQuery(\n workspace: Workspace,\n queryString: string,\n options: RunQueryOptions = {},\n): Promise<QueryResult | QueryValidationError | CheckpointError | null> {\n const result = await runQueries(workspace, queryString, options);\n\n if (!result) {\n return null;\n }\n\n // Return errors as-is\n if (\"kind\" in result) {\n return result;\n }\n\n // For backward compatibility, return single query format\n // If multiple queries were parsed, use the first one\n return {\n query: result.queries[0],\n queryString: result.queryString,\n entries: result.entries,\n totalCount: result.totalCount,\n };\n}\n\n/**\n * Type guard to check if a query result is a validation error.\n */\nexport function isQueryValidationError(\n result: QueryResult | QueriesResult | QueryValidationError | CheckpointError | null,\n): result is QueryValidationError {\n return result !== null && \"kind\" in result && result.kind === \"unknown-entities\";\n}\n\n/**\n * Type guard to check if a query result is a checkpoint error.\n */\nexport function isCheckpointError(\n result: QueryResult | QueriesResult | QueryValidationError | CheckpointError | null,\n): result is CheckpointError {\n return result !== null && \"kind\" in result && result.kind === \"invalid-checkpoint\";\n}\n\n/**\n * Type guard to check if a query result is any error type.\n */\nexport function isQueryError(\n result: QueryResult | QueriesResult | QueryValidationError | CheckpointError | null,\n): result is QueryValidationError | CheckpointError {\n return result !== null && \"kind\" in result;\n}\n\n/**\n * Type guard to check if a query result is a successful result (not an error).\n */\nexport function isQuerySuccess(\n result: QueryResult | QueryValidationError | CheckpointError | null,\n): result is QueryResult {\n return result !== null && !(\"kind\" in result);\n}\n\n/**\n * Type guard to check if a queries result is a successful result (not an error).\n */\nexport function isQueriesSuccess(\n result: QueriesResult | QueryValidationError | CheckpointError | null,\n): result is QueriesResult {\n return result !== null && !(\"kind\" in result);\n}\n"],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ //#region src/constants.d.ts
2
+ /**
3
+ * Language constants for Thalo syntax.
4
+ * Shared across packages (thalo, thalo-lsp, thalo-cli, etc.)
5
+ */
6
+ /** Directives for instance entries (create/update lore, opinion, etc.) */
7
+ declare const INSTANCE_DIRECTIVES: readonly ["create", "update"];
8
+ /** Directives for schema entries (define-entity/alter-entity) */
9
+ declare const SCHEMA_DIRECTIVES: readonly ["define-entity", "alter-entity"];
10
+ /** Directives for synthesis entries (define-synthesis/actualize-synthesis) */
11
+ declare const SYNTHESIS_DIRECTIVES: readonly ["define-synthesis", "actualize-synthesis"];
12
+ /** All directives */
13
+ declare const ALL_DIRECTIVES: readonly ["create", "update", "define-entity", "alter-entity", "define-synthesis", "actualize-synthesis"];
14
+ /** Primitive types for field definitions */
15
+ declare const PRIMITIVE_TYPES: readonly ["string", "datetime", "daterange", "link", "number"];
16
+ /** Block headers used in define-entity/alter-entity */
17
+ declare const SCHEMA_BLOCK_HEADERS: readonly ["# Metadata", "# Sections", "# Remove Metadata", "# Remove Sections"];
18
+ type InstanceDirective = (typeof INSTANCE_DIRECTIVES)[number];
19
+ type SchemaDirective = (typeof SCHEMA_DIRECTIVES)[number];
20
+ type SynthesisDirective = (typeof SYNTHESIS_DIRECTIVES)[number];
21
+ type Directive = (typeof ALL_DIRECTIVES)[number];
22
+ type PrimitiveType = (typeof PRIMITIVE_TYPES)[number];
23
+ type SchemaBlockHeader = (typeof SCHEMA_BLOCK_HEADERS)[number];
24
+ declare function isInstanceDirective(value: string): value is InstanceDirective;
25
+ declare function isSchemaDirective(value: string): value is SchemaDirective;
26
+ declare function isSynthesisDirective(value: string): value is SynthesisDirective;
27
+ declare function isDirective(value: string): value is Directive;
28
+ declare function isPrimitiveType(value: string): value is PrimitiveType;
29
+ //#endregion
30
+ export { ALL_DIRECTIVES, Directive, INSTANCE_DIRECTIVES, InstanceDirective, PRIMITIVE_TYPES, PrimitiveType, SCHEMA_BLOCK_HEADERS, SCHEMA_DIRECTIVES, SYNTHESIS_DIRECTIVES, SchemaBlockHeader, SchemaDirective, SynthesisDirective, isDirective, isInstanceDirective, isPrimitiveType, isSchemaDirective, isSynthesisDirective };
31
+ //# sourceMappingURL=constants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.d.ts","names":[],"sources":["../src/constants.ts"],"sourcesContent":[],"mappings":";;AAUA;AAGA;AAGA;AAGA;AAWa,cApBA,mBAoBgF,EAAA,SAAA,CAAA,QAAA,EAAA,QAAA,CAAA;AAO7F;AAWY,cAnCC,iBAmC2B,EAAA,SAAA,CAAA,eAAmB,EAAA,cAAA,CAAA;AAC3D;AACY,cAlCC,oBAkC4B,EAAA,SAAA,CAAA,kBAAoB,EAAA,qBAAA,CAAA;AAC7D;AACY,cAjCC,cAiCuB,EAAA,SAAA,CAAA,QAAe,EAAA,QAAA,EAAA,eAAA,EAAA,cAAA,EAAA,kBAAA,EAAA,qBAAA,CAAA;AACnD;AAMgB,cA7BH,eA6BsB,EAAA,SAA0B,CAAA,QAAA,EAAiB,UAAA,EAAA,WAAA,EAAA,MAAA,EAAA,QAAA,CAAA;AAI9E;AAIgB,cA9BH,oBA8BiD,EAAA,SAAA,CAAA,YAAkB,EAAA,YAAA,EAAA,mBAAA,EAAA,mBAAA,CAAA;AAIhE,KAvBJ,iBAAA,GAuByC,CAAA,OAvBb,mBAuBsB,CAAA,CAAA,MAAA,CAAA;AAI9C,KA1BJ,eAAA,GA0BmB,CAAA,OA1BO,iBA0BgC,CAAA,CAAA,MAAA,CAAA;KAzB1D,kBAAA,WAA6B;KAC7B,SAAA,WAAoB;KACpB,aAAA,WAAwB;KACxB,iBAAA,WAA4B;iBAMxB,mBAAA,0BAA6C;iBAI7C,iBAAA,0BAA2C;iBAI3C,oBAAA,0BAA8C;iBAI9C,WAAA,0BAAqC;iBAIrC,eAAA,0BAAyC"}
@@ -0,0 +1,51 @@
1
+ //#region src/constants.ts
2
+ /**
3
+ * Language constants for Thalo syntax.
4
+ * Shared across packages (thalo, thalo-lsp, thalo-cli, etc.)
5
+ */
6
+ /** Directives for instance entries (create/update lore, opinion, etc.) */
7
+ const INSTANCE_DIRECTIVES = ["create", "update"];
8
+ /** Directives for schema entries (define-entity/alter-entity) */
9
+ const SCHEMA_DIRECTIVES = ["define-entity", "alter-entity"];
10
+ /** Directives for synthesis entries (define-synthesis/actualize-synthesis) */
11
+ const SYNTHESIS_DIRECTIVES = ["define-synthesis", "actualize-synthesis"];
12
+ /** All directives */
13
+ const ALL_DIRECTIVES = [
14
+ ...INSTANCE_DIRECTIVES,
15
+ ...SCHEMA_DIRECTIVES,
16
+ ...SYNTHESIS_DIRECTIVES
17
+ ];
18
+ /** Primitive types for field definitions */
19
+ const PRIMITIVE_TYPES = [
20
+ "string",
21
+ "datetime",
22
+ "daterange",
23
+ "link",
24
+ "number"
25
+ ];
26
+ /** Block headers used in define-entity/alter-entity */
27
+ const SCHEMA_BLOCK_HEADERS = [
28
+ "# Metadata",
29
+ "# Sections",
30
+ "# Remove Metadata",
31
+ "# Remove Sections"
32
+ ];
33
+ function isInstanceDirective(value) {
34
+ return INSTANCE_DIRECTIVES.includes(value);
35
+ }
36
+ function isSchemaDirective(value) {
37
+ return SCHEMA_DIRECTIVES.includes(value);
38
+ }
39
+ function isSynthesisDirective(value) {
40
+ return SYNTHESIS_DIRECTIVES.includes(value);
41
+ }
42
+ function isDirective(value) {
43
+ return ALL_DIRECTIVES.includes(value);
44
+ }
45
+ function isPrimitiveType(value) {
46
+ return PRIMITIVE_TYPES.includes(value);
47
+ }
48
+
49
+ //#endregion
50
+ export { ALL_DIRECTIVES, INSTANCE_DIRECTIVES, PRIMITIVE_TYPES, SCHEMA_BLOCK_HEADERS, SCHEMA_DIRECTIVES, SYNTHESIS_DIRECTIVES, isDirective, isInstanceDirective, isPrimitiveType, isSchemaDirective, isSynthesisDirective };
51
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","names":[],"sources":["../src/constants.ts"],"sourcesContent":["/**\n * Language constants for Thalo syntax.\n * Shared across packages (thalo, thalo-lsp, thalo-cli, etc.)\n */\n\n// ===================\n// Directives\n// ===================\n\n/** Directives for instance entries (create/update lore, opinion, etc.) */\nexport const INSTANCE_DIRECTIVES = [\"create\", \"update\"] as const;\n\n/** Directives for schema entries (define-entity/alter-entity) */\nexport const SCHEMA_DIRECTIVES = [\"define-entity\", \"alter-entity\"] as const;\n\n/** Directives for synthesis entries (define-synthesis/actualize-synthesis) */\nexport const SYNTHESIS_DIRECTIVES = [\"define-synthesis\", \"actualize-synthesis\"] as const;\n\n/** All directives */\nexport const ALL_DIRECTIVES = [\n ...INSTANCE_DIRECTIVES,\n ...SCHEMA_DIRECTIVES,\n ...SYNTHESIS_DIRECTIVES,\n] as const;\n\n// ===================\n// Primitive Types (for schema definitions)\n// ===================\n\n/** Primitive types for field definitions */\nexport const PRIMITIVE_TYPES = [\"string\", \"datetime\", \"daterange\", \"link\", \"number\"] as const;\n\n// ===================\n// Schema Block Headers\n// ===================\n\n/** Block headers used in define-entity/alter-entity */\nexport const SCHEMA_BLOCK_HEADERS = [\n \"# Metadata\",\n \"# Sections\",\n \"# Remove Metadata\",\n \"# Remove Sections\",\n] as const;\n\n// ===================\n// Type Utilities\n// ===================\n\nexport type InstanceDirective = (typeof INSTANCE_DIRECTIVES)[number];\nexport type SchemaDirective = (typeof SCHEMA_DIRECTIVES)[number];\nexport type SynthesisDirective = (typeof SYNTHESIS_DIRECTIVES)[number];\nexport type Directive = (typeof ALL_DIRECTIVES)[number];\nexport type PrimitiveType = (typeof PRIMITIVE_TYPES)[number];\nexport type SchemaBlockHeader = (typeof SCHEMA_BLOCK_HEADERS)[number];\n\n// ===================\n// Type Guards\n// ===================\n\nexport function isInstanceDirective(value: string): value is InstanceDirective {\n return (INSTANCE_DIRECTIVES as readonly string[]).includes(value);\n}\n\nexport function isSchemaDirective(value: string): value is SchemaDirective {\n return (SCHEMA_DIRECTIVES as readonly string[]).includes(value);\n}\n\nexport function isSynthesisDirective(value: string): value is SynthesisDirective {\n return (SYNTHESIS_DIRECTIVES as readonly string[]).includes(value);\n}\n\nexport function isDirective(value: string): value is Directive {\n return (ALL_DIRECTIVES as readonly string[]).includes(value);\n}\n\nexport function isPrimitiveType(value: string): value is PrimitiveType {\n return (PRIMITIVE_TYPES as readonly string[]).includes(value);\n}\n"],"mappings":";;;;;;AAUA,MAAa,sBAAsB,CAAC,UAAU,SAAS;;AAGvD,MAAa,oBAAoB,CAAC,iBAAiB,eAAe;;AAGlE,MAAa,uBAAuB,CAAC,oBAAoB,sBAAsB;;AAG/E,MAAa,iBAAiB;CAC5B,GAAG;CACH,GAAG;CACH,GAAG;CACJ;;AAOD,MAAa,kBAAkB;CAAC;CAAU;CAAY;CAAa;CAAQ;CAAS;;AAOpF,MAAa,uBAAuB;CAClC;CACA;CACA;CACA;CACD;AAiBD,SAAgB,oBAAoB,OAA2C;AAC7E,QAAQ,oBAA0C,SAAS,MAAM;;AAGnE,SAAgB,kBAAkB,OAAyC;AACzE,QAAQ,kBAAwC,SAAS,MAAM;;AAGjE,SAAgB,qBAAqB,OAA4C;AAC/E,QAAQ,qBAA2C,SAAS,MAAM;;AAGpE,SAAgB,YAAY,OAAmC;AAC7D,QAAQ,eAAqC,SAAS,MAAM;;AAG9D,SAAgB,gBAAgB,OAAuC;AACrE,QAAQ,gBAAsC,SAAS,MAAM"}
@@ -0,0 +1,58 @@
1
+ import { Workspace } from "./model/workspace.js";
2
+ import "./parser.native.js";
3
+
4
+ //#region src/files.d.ts
5
+
6
+ /**
7
+ * Default file extensions for thalo files.
8
+ */
9
+ declare const DEFAULT_EXTENSIONS: string[];
10
+ /**
11
+ * Collect all thalo files from a directory recursively.
12
+ *
13
+ * Skips hidden directories (starting with .) and node_modules.
14
+ *
15
+ * @param dir - Directory to search
16
+ * @param extensions - File extensions to include (default: .thalo, .md)
17
+ * @returns Array of absolute file paths
18
+ */
19
+ declare function collectThaloFiles(dir: string, extensions?: string[]): Promise<string[]>;
20
+ /**
21
+ * Load a workspace from a directory.
22
+ *
23
+ * Discovers all .thalo and .md files in the directory and loads them
24
+ * into a new Workspace instance.
25
+ *
26
+ * @param cwd - Working directory to load files from
27
+ * @param extensions - File extensions to include (default: .thalo, .md)
28
+ * @returns The loaded workspace
29
+ * @throws Error if directory doesn't exist or no files found
30
+ *
31
+ * @example
32
+ * ```typescript
33
+ * import { loadWorkspaceFromDirectory } from "@rejot-dev/thalo/files";
34
+ *
35
+ * const workspace = await loadWorkspaceFromDirectory("./my-thalo-project");
36
+ * ```
37
+ */
38
+ declare function loadWorkspaceFromDirectory(cwd: string, extensions?: string[]): Promise<Workspace>;
39
+ /**
40
+ * Load a workspace from specific files.
41
+ *
42
+ * @param files - Array of file paths to load
43
+ * @returns The loaded workspace
44
+ *
45
+ * @example
46
+ * ```typescript
47
+ * import { loadWorkspaceFromFiles } from "@rejot-dev/thalo/files";
48
+ *
49
+ * const workspace = await loadWorkspaceFromFiles([
50
+ * "./entries.thalo",
51
+ * "./syntheses.thalo",
52
+ * ]);
53
+ * ```
54
+ */
55
+ declare function loadWorkspaceFromFiles(files: string[]): Promise<Workspace>;
56
+ //#endregion
57
+ export { DEFAULT_EXTENSIONS, collectThaloFiles, loadWorkspaceFromDirectory, loadWorkspaceFromFiles };
58
+ //# sourceMappingURL=files.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"files.d.ts","names":[],"sources":["../src/files.ts"],"sourcesContent":[],"mappings":";;;;;;;;cAgBa;;;;;;;;;;iBAWS,iBAAA,sCAGnB;;;;;;;;;;;;;;;;;;;iBAiDmB,0BAAA,sCAGnB,QAAQ;;;;;;;;;;;;;;;;;iBAkDW,sBAAA,mBAAyC,QAAQ"}
package/dist/files.js ADDED
@@ -0,0 +1,103 @@
1
+ import { createWorkspace } from "./parser.native.js";
2
+ import { readFile, readdir, stat } from "node:fs/promises";
3
+ import { join, resolve } from "node:path";
4
+
5
+ //#region src/files.ts
6
+ /**
7
+ * Default file extensions for thalo files.
8
+ */
9
+ const DEFAULT_EXTENSIONS = [".thalo", ".md"];
10
+ /**
11
+ * Collect all thalo files from a directory recursively.
12
+ *
13
+ * Skips hidden directories (starting with .) and node_modules.
14
+ *
15
+ * @param dir - Directory to search
16
+ * @param extensions - File extensions to include (default: .thalo, .md)
17
+ * @returns Array of absolute file paths
18
+ */
19
+ async function collectThaloFiles(dir, extensions = DEFAULT_EXTENSIONS) {
20
+ const files = [];
21
+ async function walk(currentDir) {
22
+ let entries;
23
+ try {
24
+ entries = await readdir(currentDir, { withFileTypes: true });
25
+ } catch {
26
+ return;
27
+ }
28
+ for (const entry of entries) {
29
+ const fullPath = join(currentDir, entry.name);
30
+ if (entry.isDirectory()) {
31
+ if (!entry.name.startsWith(".") && entry.name !== "node_modules") await walk(fullPath);
32
+ } else if (entry.isFile()) {
33
+ if (extensions.some((ext) => entry.name.endsWith(ext))) files.push(fullPath);
34
+ }
35
+ }
36
+ }
37
+ await walk(dir);
38
+ return files;
39
+ }
40
+ /**
41
+ * Load a workspace from a directory.
42
+ *
43
+ * Discovers all .thalo and .md files in the directory and loads them
44
+ * into a new Workspace instance.
45
+ *
46
+ * @param cwd - Working directory to load files from
47
+ * @param extensions - File extensions to include (default: .thalo, .md)
48
+ * @returns The loaded workspace
49
+ * @throws Error if directory doesn't exist or no files found
50
+ *
51
+ * @example
52
+ * ```typescript
53
+ * import { loadWorkspaceFromDirectory } from "@rejot-dev/thalo/files";
54
+ *
55
+ * const workspace = await loadWorkspaceFromDirectory("./my-thalo-project");
56
+ * ```
57
+ */
58
+ async function loadWorkspaceFromDirectory(cwd, extensions = DEFAULT_EXTENSIONS) {
59
+ const resolvedCwd = resolve(cwd);
60
+ try {
61
+ if (!(await stat(resolvedCwd)).isDirectory()) throw new Error(`Path is not a directory: ${cwd}`);
62
+ } catch (err) {
63
+ if (err instanceof Error && "code" in err && err.code === "ENOENT") throw new Error(`Directory not found: ${cwd}`);
64
+ throw err;
65
+ }
66
+ const files = await collectThaloFiles(resolvedCwd, extensions);
67
+ if (files.length === 0) throw new Error(`No ${extensions.join(" or ")} files found in ${cwd}`);
68
+ const workspace = createWorkspace();
69
+ for (const file of files) {
70
+ const source = await readFile(file, "utf-8");
71
+ workspace.addDocument(source, { filename: file });
72
+ }
73
+ return workspace;
74
+ }
75
+ /**
76
+ * Load a workspace from specific files.
77
+ *
78
+ * @param files - Array of file paths to load
79
+ * @returns The loaded workspace
80
+ *
81
+ * @example
82
+ * ```typescript
83
+ * import { loadWorkspaceFromFiles } from "@rejot-dev/thalo/files";
84
+ *
85
+ * const workspace = await loadWorkspaceFromFiles([
86
+ * "./entries.thalo",
87
+ * "./syntheses.thalo",
88
+ * ]);
89
+ * ```
90
+ */
91
+ async function loadWorkspaceFromFiles(files) {
92
+ const workspace = createWorkspace();
93
+ for (const file of files) {
94
+ const resolvedPath = resolve(file);
95
+ const source = await readFile(resolvedPath, "utf-8");
96
+ workspace.addDocument(source, { filename: resolvedPath });
97
+ }
98
+ return workspace;
99
+ }
100
+
101
+ //#endregion
102
+ export { DEFAULT_EXTENSIONS, collectThaloFiles, loadWorkspaceFromDirectory, loadWorkspaceFromFiles };
103
+ //# sourceMappingURL=files.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"files.js","names":["files: string[]"],"sources":["../src/files.ts"],"sourcesContent":["/**\n * Node.js-only file utilities for loading Thalo workspaces.\n *\n * This module provides helpers for discovering and loading .thalo and .md files.\n * It should only be used in Node.js environments (CLI, scripts, GitHub Actions).\n *\n * @module @rejot-dev/thalo/files\n */\n\nimport { readdir, readFile, stat } from \"node:fs/promises\";\nimport { join, resolve } from \"node:path\";\nimport { createWorkspace, type Workspace } from \"./parser.native.js\";\n\n/**\n * Default file extensions for thalo files.\n */\nexport const DEFAULT_EXTENSIONS = [\".thalo\", \".md\"];\n\n/**\n * Collect all thalo files from a directory recursively.\n *\n * Skips hidden directories (starting with .) and node_modules.\n *\n * @param dir - Directory to search\n * @param extensions - File extensions to include (default: .thalo, .md)\n * @returns Array of absolute file paths\n */\nexport async function collectThaloFiles(\n dir: string,\n extensions: string[] = DEFAULT_EXTENSIONS,\n): Promise<string[]> {\n const files: string[] = [];\n\n async function walk(currentDir: string): Promise<void> {\n let entries;\n try {\n entries = await readdir(currentDir, { withFileTypes: true });\n } catch {\n return;\n }\n\n for (const entry of entries) {\n const fullPath = join(currentDir, entry.name);\n\n if (entry.isDirectory()) {\n // Skip hidden directories and node_modules\n if (!entry.name.startsWith(\".\") && entry.name !== \"node_modules\") {\n await walk(fullPath);\n }\n } else if (entry.isFile()) {\n if (extensions.some((ext) => entry.name.endsWith(ext))) {\n files.push(fullPath);\n }\n }\n }\n }\n\n await walk(dir);\n return files;\n}\n\n/**\n * Load a workspace from a directory.\n *\n * Discovers all .thalo and .md files in the directory and loads them\n * into a new Workspace instance.\n *\n * @param cwd - Working directory to load files from\n * @param extensions - File extensions to include (default: .thalo, .md)\n * @returns The loaded workspace\n * @throws Error if directory doesn't exist or no files found\n *\n * @example\n * ```typescript\n * import { loadWorkspaceFromDirectory } from \"@rejot-dev/thalo/files\";\n *\n * const workspace = await loadWorkspaceFromDirectory(\"./my-thalo-project\");\n * ```\n */\nexport async function loadWorkspaceFromDirectory(\n cwd: string,\n extensions: string[] = DEFAULT_EXTENSIONS,\n): Promise<Workspace> {\n const resolvedCwd = resolve(cwd);\n\n // Check if directory exists\n try {\n const dirStat = await stat(resolvedCwd);\n if (!dirStat.isDirectory()) {\n throw new Error(`Path is not a directory: ${cwd}`);\n }\n } catch (err) {\n if (err instanceof Error && \"code\" in err && err.code === \"ENOENT\") {\n throw new Error(`Directory not found: ${cwd}`);\n }\n throw err;\n }\n\n // Collect all thalo files\n const files = await collectThaloFiles(resolvedCwd, extensions);\n\n if (files.length === 0) {\n throw new Error(`No ${extensions.join(\" or \")} files found in ${cwd}`);\n }\n\n // Create workspace and add documents\n const workspace = createWorkspace();\n\n for (const file of files) {\n const source = await readFile(file, \"utf-8\");\n workspace.addDocument(source, { filename: file });\n }\n\n return workspace;\n}\n\n/**\n * Load a workspace from specific files.\n *\n * @param files - Array of file paths to load\n * @returns The loaded workspace\n *\n * @example\n * ```typescript\n * import { loadWorkspaceFromFiles } from \"@rejot-dev/thalo/files\";\n *\n * const workspace = await loadWorkspaceFromFiles([\n * \"./entries.thalo\",\n * \"./syntheses.thalo\",\n * ]);\n * ```\n */\nexport async function loadWorkspaceFromFiles(files: string[]): Promise<Workspace> {\n const workspace = createWorkspace();\n\n for (const file of files) {\n const resolvedPath = resolve(file);\n const source = await readFile(resolvedPath, \"utf-8\");\n workspace.addDocument(source, { filename: resolvedPath });\n }\n\n return workspace;\n}\n"],"mappings":";;;;;;;;AAgBA,MAAa,qBAAqB,CAAC,UAAU,MAAM;;;;;;;;;;AAWnD,eAAsB,kBACpB,KACA,aAAuB,oBACJ;CACnB,MAAMA,QAAkB,EAAE;CAE1B,eAAe,KAAK,YAAmC;EACrD,IAAI;AACJ,MAAI;AACF,aAAU,MAAM,QAAQ,YAAY,EAAE,eAAe,MAAM,CAAC;UACtD;AACN;;AAGF,OAAK,MAAM,SAAS,SAAS;GAC3B,MAAM,WAAW,KAAK,YAAY,MAAM,KAAK;AAE7C,OAAI,MAAM,aAAa,EAErB;QAAI,CAAC,MAAM,KAAK,WAAW,IAAI,IAAI,MAAM,SAAS,eAChD,OAAM,KAAK,SAAS;cAEb,MAAM,QAAQ,EACvB;QAAI,WAAW,MAAM,QAAQ,MAAM,KAAK,SAAS,IAAI,CAAC,CACpD,OAAM,KAAK,SAAS;;;;AAM5B,OAAM,KAAK,IAAI;AACf,QAAO;;;;;;;;;;;;;;;;;;;;AAqBT,eAAsB,2BACpB,KACA,aAAuB,oBACH;CACpB,MAAM,cAAc,QAAQ,IAAI;AAGhC,KAAI;AAEF,MAAI,EADY,MAAM,KAAK,YAAY,EAC1B,aAAa,CACxB,OAAM,IAAI,MAAM,4BAA4B,MAAM;UAE7C,KAAK;AACZ,MAAI,eAAe,SAAS,UAAU,OAAO,IAAI,SAAS,SACxD,OAAM,IAAI,MAAM,wBAAwB,MAAM;AAEhD,QAAM;;CAIR,MAAM,QAAQ,MAAM,kBAAkB,aAAa,WAAW;AAE9D,KAAI,MAAM,WAAW,EACnB,OAAM,IAAI,MAAM,MAAM,WAAW,KAAK,OAAO,CAAC,kBAAkB,MAAM;CAIxE,MAAM,YAAY,iBAAiB;AAEnC,MAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,SAAS,MAAM,SAAS,MAAM,QAAQ;AAC5C,YAAU,YAAY,QAAQ,EAAE,UAAU,MAAM,CAAC;;AAGnD,QAAO;;;;;;;;;;;;;;;;;;AAmBT,eAAsB,uBAAuB,OAAqC;CAChF,MAAM,YAAY,iBAAiB;AAEnC,MAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,eAAe,QAAQ,KAAK;EAClC,MAAM,SAAS,MAAM,SAAS,cAAc,QAAQ;AACpD,YAAU,YAAY,QAAQ,EAAE,UAAU,cAAc,CAAC;;AAG3D,QAAO"}
@@ -0,0 +1,39 @@
1
+ import { Timestamp } from "./ast/ast-types.js";
2
+ import { ActualizeResult } from "./commands/actualize.js";
3
+ import { CheckResult, DiagnosticInfo } from "./commands/check.js";
4
+ import { QueryResult } from "./commands/query.js";
5
+
6
+ //#region src/formatters.d.ts
7
+
8
+ /**
9
+ * Output format style for diagnostics.
10
+ */
11
+ type DiagnosticFormat = "default" | "compact" | "github";
12
+ /**
13
+ * Format a timestamp to ISO-like string for comparisons and display.
14
+ * Example: "2026-01-07T12:00Z" or "2026-01-07T12:00+05:30"
15
+ */
16
+ declare function formatTimestamp(ts: Timestamp): string;
17
+ /**
18
+ * Format a single diagnostic.
19
+ */
20
+ declare function formatDiagnostic(d: DiagnosticInfo, format?: DiagnosticFormat): string;
21
+ /**
22
+ * Format check results as an array of lines.
23
+ */
24
+ declare function formatCheckResult(result: CheckResult, format?: DiagnosticFormat): string[];
25
+ /**
26
+ * Format query results as an array of lines.
27
+ */
28
+ declare function formatQueryResult(result: QueryResult): string[];
29
+ /**
30
+ * Format query results in raw format (just the entry source text).
31
+ */
32
+ declare function formatQueryResultRaw(result: QueryResult): string[];
33
+ /**
34
+ * Format actualize results as an array of lines.
35
+ */
36
+ declare function formatActualizeResult(result: ActualizeResult): string[];
37
+ //#endregion
38
+ export { DiagnosticFormat, formatActualizeResult, formatCheckResult, formatDiagnostic, formatQueryResult, formatQueryResultRaw, formatTimestamp };
39
+ //# sourceMappingURL=formatters.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formatters.d.ts","names":[],"sources":["../src/formatters.ts"],"sourcesContent":[],"mappings":";;;;;;;AA6NA;AA+EA;;KAtRY,gBAAA;;;;;iBAUI,eAAA,KAAoB;;;;iBAiFpB,gBAAA,IAAoB,yBAAwB;;;;iBAc5C,iBAAA,SACN,sBACA;;;;iBAiEM,iBAAA,SAA0B;;;;iBA2B1B,oBAAA,SAA6B;;;;iBA+E7B,qBAAA,SAA8B"}
@@ -0,0 +1,200 @@
1
+ import { formatCheckpoint } from "./services/change-tracker/change-tracker.js";
2
+ import { isSyntaxError } from "./ast/ast-types.js";
3
+
4
+ //#region src/formatters.ts
5
+ /**
6
+ * Format a timestamp to ISO-like string for comparisons and display.
7
+ * Example: "2026-01-07T12:00Z" or "2026-01-07T12:00+05:30"
8
+ */
9
+ function formatTimestamp(ts) {
10
+ return `${`${ts.date.year}-${String(ts.date.month).padStart(2, "0")}-${String(ts.date.day).padStart(2, "0")}`}T${`${String(ts.time.hour).padStart(2, "0")}:${String(ts.time.minute).padStart(2, "0")}`}${isSyntaxError(ts.timezone) ? "" : ts.timezone.value}`;
11
+ }
12
+ /**
13
+ * Format a relative path from CWD (if applicable).
14
+ * This is a no-op since we don't have access to process.cwd() in all environments.
15
+ * CLI tools should handle path relativization themselves.
16
+ */
17
+ function formatPath(path) {
18
+ return path;
19
+ }
20
+ /**
21
+ * Format a single diagnostic in default style.
22
+ */
23
+ function formatDiagnosticDefault(d) {
24
+ return ` ${`${d.line}:${d.column}`.padEnd(8)} ${d.severity.padEnd(7)} ${d.message} ${d.code}`;
25
+ }
26
+ /**
27
+ * Format a single diagnostic in compact style.
28
+ */
29
+ function formatDiagnosticCompact(d) {
30
+ return `${`${formatPath(d.file)}:${d.line}:${d.column}`}: ${d.severity[0].toUpperCase()} [${d.code}] ${d.message}`;
31
+ }
32
+ /**
33
+ * Escape a string for use in GitHub Actions annotation property values.
34
+ * Property values require: % → %25, \n → %0A, \r → %0D, : → %3A, , → %2C
35
+ */
36
+ function escapeGithubProperty(value) {
37
+ return value.replace(/%/g, "%25").replace(/\r/g, "%0D").replace(/\n/g, "%0A").replace(/:/g, "%3A").replace(/,/g, "%2C");
38
+ }
39
+ /**
40
+ * Escape a string for use in GitHub Actions annotation message.
41
+ * Messages require: % → %25, \n → %0A, \r → %0D
42
+ */
43
+ function escapeGithubMessage(value) {
44
+ return value.replace(/%/g, "%25").replace(/\r/g, "%0D").replace(/\n/g, "%0A");
45
+ }
46
+ /**
47
+ * Map internal severity to GitHub Actions annotation level.
48
+ * GitHub Actions supports: error, warning, notice (not "info")
49
+ */
50
+ function toGithubSeverity(severity) {
51
+ return severity === "info" ? "notice" : severity;
52
+ }
53
+ /**
54
+ * Format a single diagnostic in GitHub Actions style.
55
+ */
56
+ function formatDiagnosticGithub(d) {
57
+ const severity = toGithubSeverity(d.severity);
58
+ const file = escapeGithubProperty(d.file);
59
+ const title = escapeGithubProperty(d.code);
60
+ const message = escapeGithubMessage(d.message);
61
+ return `::${severity} file=${file},line=${d.line},col=${d.column},endLine=${d.endLine},endColumn=${d.endColumn},title=${title}::${message}`;
62
+ }
63
+ /**
64
+ * Format a single diagnostic.
65
+ */
66
+ function formatDiagnostic(d, format = "default") {
67
+ switch (format) {
68
+ case "compact": return formatDiagnosticCompact(d);
69
+ case "github": return formatDiagnosticGithub(d);
70
+ default: return formatDiagnosticDefault(d);
71
+ }
72
+ }
73
+ /**
74
+ * Format check results as an array of lines.
75
+ */
76
+ function formatCheckResult(result, format = "default") {
77
+ const lines = [];
78
+ if (format === "default") for (const [file, diagnostics] of result.diagnosticsByFile) {
79
+ lines.push("");
80
+ lines.push(formatPath(file));
81
+ for (const d of diagnostics) lines.push(formatDiagnosticDefault(d));
82
+ }
83
+ else for (const [, diagnostics] of result.diagnosticsByFile) for (const d of diagnostics) lines.push(formatDiagnostic(d, format));
84
+ if (format !== "github") {
85
+ lines.push("");
86
+ const parts = [];
87
+ if (result.errorCount > 0) parts.push(`${result.errorCount} error${result.errorCount !== 1 ? "s" : ""}`);
88
+ if (result.warningCount > 0) parts.push(`${result.warningCount} warning${result.warningCount !== 1 ? "s" : ""}`);
89
+ if (result.infoCount > 0) parts.push(`${result.infoCount} info`);
90
+ const summary = parts.length > 0 ? parts.join(", ") : "no issues";
91
+ lines.push(`${result.filesChecked} files checked, ${summary}`);
92
+ }
93
+ return lines;
94
+ }
95
+ /**
96
+ * Format a query entry in default style.
97
+ */
98
+ function formatQueryEntryDefault(entry) {
99
+ const lines = [];
100
+ const link = entry.linkId ? ` ^${entry.linkId}` : "";
101
+ const tags = entry.tags.length > 0 ? " " + entry.tags.map((t) => `#${t}`).join(" ") : "";
102
+ lines.push(`${entry.timestamp} ${entry.entity} ${entry.title}${link}${tags}`);
103
+ lines.push(` ${formatPath(entry.file)}:${entry.startLine}-${entry.endLine}`);
104
+ return lines;
105
+ }
106
+ /**
107
+ * Format query results as an array of lines.
108
+ */
109
+ function formatQueryResult(result) {
110
+ const lines = [];
111
+ lines.push("");
112
+ lines.push(`Query: ${result.queryString}`);
113
+ lines.push(`Found: ${result.totalCount} entries`);
114
+ if (result.entries.length > 0) {
115
+ lines.push("");
116
+ for (const entry of result.entries) lines.push(...formatQueryEntryDefault(entry));
117
+ }
118
+ if (result.entries.length < result.totalCount) {
119
+ lines.push("");
120
+ lines.push(`(showing ${result.entries.length} of ${result.totalCount} results)`);
121
+ }
122
+ lines.push("");
123
+ return lines;
124
+ }
125
+ /**
126
+ * Format query results in raw format (just the entry source text).
127
+ */
128
+ function formatQueryResultRaw(result) {
129
+ const lines = [];
130
+ for (const entry of result.entries) if (entry.rawText) {
131
+ lines.push(entry.rawText);
132
+ lines.push("");
133
+ }
134
+ return lines;
135
+ }
136
+ /**
137
+ * Format a synthesis entry for actualize output.
138
+ */
139
+ function formatActualizeEntry(entry) {
140
+ return entry.rawText.split("\n");
141
+ }
142
+ /**
143
+ * Format a single synthesis output.
144
+ */
145
+ function formatSynthesisOutput(synthesis) {
146
+ const lines = [];
147
+ if (synthesis.isUpToDate) {
148
+ lines.push(`✓ ${formatPath(synthesis.file)}: ${synthesis.title} - up to date`);
149
+ return lines;
150
+ }
151
+ lines.push("");
152
+ lines.push(`=== Synthesis: ${synthesis.title} (${formatPath(synthesis.file)}) ===`);
153
+ lines.push(`Target: ^${synthesis.linkId}`);
154
+ lines.push(`Sources: ${synthesis.sources.join(", ")}`);
155
+ if (synthesis.lastCheckpoint) lines.push(`Last checkpoint: ${formatCheckpoint(synthesis.lastCheckpoint)}`);
156
+ lines.push("");
157
+ lines.push("--- User Prompt ---");
158
+ if (synthesis.prompt) lines.push(synthesis.prompt);
159
+ else lines.push("(no prompt defined)");
160
+ lines.push("");
161
+ lines.push(`--- Changed Entries (${synthesis.entries.length}) ---`);
162
+ for (const entry of synthesis.entries) {
163
+ lines.push("");
164
+ lines.push(...formatActualizeEntry(entry));
165
+ }
166
+ const checkpointValue = formatCheckpoint(synthesis.currentCheckpoint);
167
+ lines.push("");
168
+ lines.push("--- Instructions ---");
169
+ lines.push(`1. Update the content directly below the \`\`\`thalo block in ${formatPath(synthesis.file)}`);
170
+ lines.push(`2. Place output BEFORE any subsequent \`\`\`thalo blocks`);
171
+ lines.push(`3. Append to the thalo block: actualize-synthesis ^${synthesis.linkId}`);
172
+ lines.push(` with metadata: checkpoint: "${checkpointValue}"`);
173
+ lines.push("");
174
+ lines.push("─".repeat(60));
175
+ return lines;
176
+ }
177
+ /**
178
+ * Format actualize results as an array of lines.
179
+ */
180
+ function formatActualizeResult(result) {
181
+ const lines = [];
182
+ if (result.syntheses.length === 0) {
183
+ lines.push("No synthesis definitions found.");
184
+ return lines;
185
+ }
186
+ let hasOutput = false;
187
+ for (const synthesis of result.syntheses) {
188
+ if (!synthesis.isUpToDate) hasOutput = true;
189
+ lines.push(...formatSynthesisOutput(synthesis));
190
+ }
191
+ if (!hasOutput) {
192
+ lines.push("");
193
+ lines.push("All syntheses are up to date.");
194
+ }
195
+ return lines;
196
+ }
197
+
198
+ //#endregion
199
+ export { formatActualizeResult, formatCheckResult, formatDiagnostic, formatQueryResult, formatQueryResultRaw, formatTimestamp };
200
+ //# sourceMappingURL=formatters.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formatters.js","names":["lines: string[]","parts: string[]"],"sources":["../src/formatters.ts"],"sourcesContent":["/**\n * Plain-text formatters for command results.\n *\n * These formatters produce plain text output without any colors or styling.\n * CLI tools can add colors on top using libraries like picocolors.\n * Browser environments can use the structured results directly.\n */\n\nimport type { CheckResult, DiagnosticInfo } from \"./commands/check.js\";\nimport type { QueryResult, QueryEntryInfo } from \"./commands/query.js\";\nimport type {\n ActualizeResult,\n SynthesisOutputInfo,\n ActualizeEntryInfo,\n} from \"./commands/actualize.js\";\nimport { formatCheckpoint } from \"./services/change-tracker/change-tracker.js\";\nimport type { Timestamp } from \"./ast/ast-types.js\";\nimport { isSyntaxError } from \"./ast/ast-types.js\";\n\n/**\n * Output format style for diagnostics.\n */\nexport type DiagnosticFormat = \"default\" | \"compact\" | \"github\";\n\n// ===================\n// Timestamp Formatting\n// ===================\n\n/**\n * Format a timestamp to ISO-like string for comparisons and display.\n * Example: \"2026-01-07T12:00Z\" or \"2026-01-07T12:00+05:30\"\n */\nexport function formatTimestamp(ts: Timestamp): string {\n const date = `${ts.date.year}-${String(ts.date.month).padStart(2, \"0\")}-${String(ts.date.day).padStart(2, \"0\")}`;\n const time = `${String(ts.time.hour).padStart(2, \"0\")}:${String(ts.time.minute).padStart(2, \"0\")}`;\n const tz = isSyntaxError(ts.timezone) ? \"\" : ts.timezone.value;\n return `${date}T${time}${tz}`;\n}\n\n/**\n * Format a relative path from CWD (if applicable).\n * This is a no-op since we don't have access to process.cwd() in all environments.\n * CLI tools should handle path relativization themselves.\n */\nfunction formatPath(path: string): string {\n return path;\n}\n\n// ===================\n// Check Formatters\n// ===================\n\n/**\n * Format a single diagnostic in default style.\n */\nfunction formatDiagnosticDefault(d: DiagnosticInfo): string {\n const loc = `${d.line}:${d.column}`.padEnd(8);\n const severity = d.severity.padEnd(7);\n return ` ${loc} ${severity} ${d.message} ${d.code}`;\n}\n\n/**\n * Format a single diagnostic in compact style.\n */\nfunction formatDiagnosticCompact(d: DiagnosticInfo): string {\n const loc = `${formatPath(d.file)}:${d.line}:${d.column}`;\n return `${loc}: ${d.severity[0].toUpperCase()} [${d.code}] ${d.message}`;\n}\n\n/**\n * Escape a string for use in GitHub Actions annotation property values.\n * Property values require: % → %25, \\n → %0A, \\r → %0D, : → %3A, , → %2C\n */\nfunction escapeGithubProperty(value: string): string {\n return value\n .replace(/%/g, \"%25\")\n .replace(/\\r/g, \"%0D\")\n .replace(/\\n/g, \"%0A\")\n .replace(/:/g, \"%3A\")\n .replace(/,/g, \"%2C\");\n}\n\n/**\n * Escape a string for use in GitHub Actions annotation message.\n * Messages require: % → %25, \\n → %0A, \\r → %0D\n */\nfunction escapeGithubMessage(value: string): string {\n return value.replace(/%/g, \"%25\").replace(/\\r/g, \"%0D\").replace(/\\n/g, \"%0A\");\n}\n\n/**\n * Map internal severity to GitHub Actions annotation level.\n * GitHub Actions supports: error, warning, notice (not \"info\")\n */\nfunction toGithubSeverity(severity: string): string {\n return severity === \"info\" ? \"notice\" : severity;\n}\n\n/**\n * Format a single diagnostic in GitHub Actions style.\n */\nfunction formatDiagnosticGithub(d: DiagnosticInfo): string {\n const severity = toGithubSeverity(d.severity);\n const file = escapeGithubProperty(d.file);\n const title = escapeGithubProperty(d.code);\n const message = escapeGithubMessage(d.message);\n\n return `::${severity} file=${file},line=${d.line},col=${d.column},endLine=${d.endLine},endColumn=${d.endColumn},title=${title}::${message}`;\n}\n\n/**\n * Format a single diagnostic.\n */\nexport function formatDiagnostic(d: DiagnosticInfo, format: DiagnosticFormat = \"default\"): string {\n switch (format) {\n case \"compact\":\n return formatDiagnosticCompact(d);\n case \"github\":\n return formatDiagnosticGithub(d);\n default:\n return formatDiagnosticDefault(d);\n }\n}\n\n/**\n * Format check results as an array of lines.\n */\nexport function formatCheckResult(\n result: CheckResult,\n format: DiagnosticFormat = \"default\",\n): string[] {\n const lines: string[] = [];\n\n if (format === \"default\") {\n // Group diagnostics by file for cleaner output\n for (const [file, diagnostics] of result.diagnosticsByFile) {\n lines.push(\"\");\n lines.push(formatPath(file));\n for (const d of diagnostics) {\n lines.push(formatDiagnosticDefault(d));\n }\n }\n } else {\n // Flat list for compact/github formats\n for (const [, diagnostics] of result.diagnosticsByFile) {\n for (const d of diagnostics) {\n lines.push(formatDiagnostic(d, format));\n }\n }\n }\n\n // Summary line (skip for github format)\n if (format !== \"github\") {\n lines.push(\"\");\n const parts: string[] = [];\n if (result.errorCount > 0) {\n parts.push(`${result.errorCount} error${result.errorCount !== 1 ? \"s\" : \"\"}`);\n }\n if (result.warningCount > 0) {\n parts.push(`${result.warningCount} warning${result.warningCount !== 1 ? \"s\" : \"\"}`);\n }\n if (result.infoCount > 0) {\n parts.push(`${result.infoCount} info`);\n }\n\n const summary = parts.length > 0 ? parts.join(\", \") : \"no issues\";\n lines.push(`${result.filesChecked} files checked, ${summary}`);\n }\n\n return lines;\n}\n\n// ===================\n// Query Formatters\n// ===================\n\n/**\n * Format a query entry in default style.\n */\nfunction formatQueryEntryDefault(entry: QueryEntryInfo): string[] {\n const lines: string[] = [];\n\n const link = entry.linkId ? ` ^${entry.linkId}` : \"\";\n const tags = entry.tags.length > 0 ? \" \" + entry.tags.map((t) => `#${t}`).join(\" \") : \"\";\n\n lines.push(`${entry.timestamp} ${entry.entity} ${entry.title}${link}${tags}`);\n lines.push(` ${formatPath(entry.file)}:${entry.startLine}-${entry.endLine}`);\n\n return lines;\n}\n\n/**\n * Format query results as an array of lines.\n */\nexport function formatQueryResult(result: QueryResult): string[] {\n const lines: string[] = [];\n\n lines.push(\"\");\n lines.push(`Query: ${result.queryString}`);\n lines.push(`Found: ${result.totalCount} entries`);\n\n if (result.entries.length > 0) {\n lines.push(\"\");\n for (const entry of result.entries) {\n lines.push(...formatQueryEntryDefault(entry));\n }\n }\n\n if (result.entries.length < result.totalCount) {\n lines.push(\"\");\n lines.push(`(showing ${result.entries.length} of ${result.totalCount} results)`);\n }\n\n lines.push(\"\");\n\n return lines;\n}\n\n/**\n * Format query results in raw format (just the entry source text).\n */\nexport function formatQueryResultRaw(result: QueryResult): string[] {\n const lines: string[] = [];\n\n for (const entry of result.entries) {\n if (entry.rawText) {\n lines.push(entry.rawText);\n lines.push(\"\");\n }\n }\n\n return lines;\n}\n\n// ===================\n// Actualize Formatters\n// ===================\n\n/**\n * Format a synthesis entry for actualize output.\n */\nfunction formatActualizeEntry(entry: ActualizeEntryInfo): string[] {\n return entry.rawText.split(\"\\n\");\n}\n\n/**\n * Format a single synthesis output.\n */\nfunction formatSynthesisOutput(synthesis: SynthesisOutputInfo): string[] {\n const lines: string[] = [];\n\n if (synthesis.isUpToDate) {\n lines.push(`✓ ${formatPath(synthesis.file)}: ${synthesis.title} - up to date`);\n return lines;\n }\n\n lines.push(\"\");\n lines.push(`=== Synthesis: ${synthesis.title} (${formatPath(synthesis.file)}) ===`);\n lines.push(`Target: ^${synthesis.linkId}`);\n lines.push(`Sources: ${synthesis.sources.join(\", \")}`);\n if (synthesis.lastCheckpoint) {\n lines.push(`Last checkpoint: ${formatCheckpoint(synthesis.lastCheckpoint)}`);\n }\n\n // Output prompt\n lines.push(\"\");\n lines.push(\"--- User Prompt ---\");\n if (synthesis.prompt) {\n lines.push(synthesis.prompt);\n } else {\n lines.push(\"(no prompt defined)\");\n }\n\n // Output new entries\n lines.push(\"\");\n lines.push(`--- Changed Entries (${synthesis.entries.length}) ---`);\n for (const entry of synthesis.entries) {\n lines.push(\"\");\n lines.push(...formatActualizeEntry(entry));\n }\n\n // Output instructions\n const checkpointValue = formatCheckpoint(synthesis.currentCheckpoint);\n lines.push(\"\");\n lines.push(\"--- Instructions ---\");\n lines.push(\n `1. Update the content directly below the \\`\\`\\`thalo block in ${formatPath(synthesis.file)}`,\n );\n lines.push(`2. Place output BEFORE any subsequent \\`\\`\\`thalo blocks`);\n lines.push(`3. Append to the thalo block: actualize-synthesis ^${synthesis.linkId}`);\n lines.push(` with metadata: checkpoint: \"${checkpointValue}\"`);\n lines.push(\"\");\n lines.push(\"─\".repeat(60));\n\n return lines;\n}\n\n/**\n * Format actualize results as an array of lines.\n */\nexport function formatActualizeResult(result: ActualizeResult): string[] {\n const lines: string[] = [];\n\n if (result.syntheses.length === 0) {\n lines.push(\"No synthesis definitions found.\");\n return lines;\n }\n\n let hasOutput = false;\n\n for (const synthesis of result.syntheses) {\n if (!synthesis.isUpToDate) {\n hasOutput = true;\n }\n lines.push(...formatSynthesisOutput(synthesis));\n }\n\n if (!hasOutput) {\n lines.push(\"\");\n lines.push(\"All syntheses are up to date.\");\n }\n\n return lines;\n}\n"],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ import { SyntaxNode } from "./ast/ast-types.js";
2
+
3
+ //#region src/fragment.d.ts
4
+
5
+ /**
6
+ * Supported fragment types for parsing individual expressions.
7
+ */
8
+ type FragmentType = "query" | "value" | "type_expression";
9
+ /**
10
+ * Result of parsing a fragment
11
+ */
12
+ interface ParsedFragment {
13
+ /** The parsed syntax node */
14
+ node: SyntaxNode;
15
+ /** Whether the fragment parsed without errors */
16
+ valid: boolean;
17
+ /** Error message if parsing failed */
18
+ error?: string;
19
+ }
20
+ //#endregion
21
+ export { FragmentType, ParsedFragment };
22
+ //# sourceMappingURL=fragment.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fragment.d.ts","names":[],"sources":["../src/fragment.ts"],"sourcesContent":[],"mappings":";;;;;AAMA;AAKA;KALY,YAAA;;;;UAKK,cAAA;;QAET"}