@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,102 @@
1
+ import { unknownEntityRule } from "./unknown-entity.js";
2
+ import { missingRequiredFieldRule } from "./missing-required-field.js";
3
+ import { unknownFieldRule } from "./unknown-field.js";
4
+ import { invalidFieldTypeRule } from "./invalid-field-type.js";
5
+ import { missingRequiredSectionRule } from "./missing-required-section.js";
6
+ import { unknownSectionRule } from "./unknown-section.js";
7
+ import { unresolvedLinkRule } from "./unresolved-link.js";
8
+ import { duplicateLinkIdRule } from "./duplicate-link-id.js";
9
+ import { duplicateEntityDefinitionRule } from "./duplicate-entity-definition.js";
10
+ import { alterUndefinedEntityRule } from "./alter-undefined-entity.js";
11
+ import { alterBeforeDefineRule } from "./alter-before-define.js";
12
+ import { duplicateFieldInSchemaRule } from "./duplicate-field-in-schema.js";
13
+ import { duplicateSectionInSchemaRule } from "./duplicate-section-in-schema.js";
14
+ import { removeUndefinedFieldRule } from "./remove-undefined-field.js";
15
+ import { removeUndefinedSectionRule } from "./remove-undefined-section.js";
16
+ import { invalidDefaultValueRule } from "./invalid-default-value.js";
17
+ import { defineEntityRequiresSectionRule } from "./define-entity-requires-section.js";
18
+ import { duplicateMetadataKeyRule } from "./duplicate-metadata-key.js";
19
+ import { emptyRequiredValueRule } from "./empty-required-value.js";
20
+ import { invalidDateRangeValueRule } from "./invalid-date-range-value.js";
21
+ import { duplicateSectionHeadingRule } from "./duplicate-section-heading.js";
22
+ import { emptySectionRule } from "./empty-section.js";
23
+ import { updateWithoutCreateRule } from "./update-without-create.js";
24
+ import { timestampOutOfOrderRule } from "./timestamp-out-of-order.js";
25
+ import { createRequiresSectionRule } from "./create-requires-section.js";
26
+ import { duplicateTimestampRule } from "./duplicate-timestamp.js";
27
+ import { missingTitleRule } from "./missing-title.js";
28
+ import { synthesisMissingSourcesRule } from "./synthesis-missing-sources.js";
29
+ import { synthesisMissingPromptRule } from "./synthesis-missing-prompt.js";
30
+ import { synthesisEmptyQueryRule } from "./synthesis-empty-query.js";
31
+ import { synthesisUnknownQueryEntityRule } from "./synthesis-unknown-query-entity.js";
32
+ import { actualizeUnresolvedTargetRule } from "./actualize-unresolved-target.js";
33
+ import { actualizeMissingUpdatedRule } from "./actualize-missing-updated.js";
34
+
35
+ //#region src/checker/rules/rules.ts
36
+ /**
37
+ * Display order and labels for rule categories
38
+ */
39
+ const RULE_CATEGORIES = {
40
+ instance: {
41
+ order: 1,
42
+ label: "Instance Entry Rules"
43
+ },
44
+ link: {
45
+ order: 2,
46
+ label: "Link Rules"
47
+ },
48
+ schema: {
49
+ order: 3,
50
+ label: "Schema Definition Rules"
51
+ },
52
+ metadata: {
53
+ order: 4,
54
+ label: "Metadata Value Rules"
55
+ },
56
+ content: {
57
+ order: 5,
58
+ label: "Content Rules"
59
+ }
60
+ };
61
+ /**
62
+ * All available validation rules
63
+ */
64
+ const allRules = [
65
+ unknownEntityRule,
66
+ missingRequiredFieldRule,
67
+ unknownFieldRule,
68
+ invalidFieldTypeRule,
69
+ missingRequiredSectionRule,
70
+ unknownSectionRule,
71
+ unresolvedLinkRule,
72
+ duplicateLinkIdRule,
73
+ duplicateEntityDefinitionRule,
74
+ alterUndefinedEntityRule,
75
+ alterBeforeDefineRule,
76
+ duplicateFieldInSchemaRule,
77
+ duplicateSectionInSchemaRule,
78
+ removeUndefinedFieldRule,
79
+ removeUndefinedSectionRule,
80
+ invalidDefaultValueRule,
81
+ defineEntityRequiresSectionRule,
82
+ duplicateMetadataKeyRule,
83
+ emptyRequiredValueRule,
84
+ invalidDateRangeValueRule,
85
+ duplicateSectionHeadingRule,
86
+ emptySectionRule,
87
+ updateWithoutCreateRule,
88
+ timestampOutOfOrderRule,
89
+ createRequiresSectionRule,
90
+ duplicateTimestampRule,
91
+ missingTitleRule,
92
+ synthesisMissingSourcesRule,
93
+ synthesisMissingPromptRule,
94
+ synthesisEmptyQueryRule,
95
+ synthesisUnknownQueryEntityRule,
96
+ actualizeUnresolvedTargetRule,
97
+ actualizeMissingUpdatedRule
98
+ ];
99
+
100
+ //#endregion
101
+ export { RULE_CATEGORIES, allRules };
102
+ //# sourceMappingURL=rules.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rules.js","names":["RULE_CATEGORIES: Record<RuleCategory, { order: number; label: string }>","allRules: Rule[]"],"sources":["../../../src/checker/rules/rules.ts"],"sourcesContent":["/**\n * Severity levels for diagnostics\n */\nexport type Severity = \"error\" | \"warning\" | \"info\" | \"off\";\n\n/**\n * Rule categories for grouping related rules\n */\nexport type RuleCategory = \"instance\" | \"link\" | \"schema\" | \"metadata\" | \"content\";\n\n/**\n * Display order and labels for rule categories\n */\nexport const RULE_CATEGORIES: Record<RuleCategory, { order: number; label: string }> = {\n instance: { order: 1, label: \"Instance Entry Rules\" },\n link: { order: 2, label: \"Link Rules\" },\n schema: { order: 3, label: \"Schema Definition Rules\" },\n metadata: { order: 4, label: \"Metadata Value Rules\" },\n content: { order: 5, label: \"Content Rules\" },\n};\n\n/**\n * Rule scope - determines when a rule needs to re-run.\n *\n * - \"entry\": Rule only looks at individual entries, can run incrementally on changed entries\n * - \"document\": Rule looks at entries within a single document, runs on full document\n * - \"workspace\": Rule looks across multiple documents, runs on full workspace\n */\nexport type RuleScope = \"entry\" | \"document\" | \"workspace\";\n\n/**\n * Dependency declaration for a rule.\n * Used for incremental checking to determine when a rule needs to re-run.\n */\nexport interface RuleDependencies {\n /** Rule scope - determines when rule needs to re-run */\n scope: RuleScope;\n /** Rule needs schema registry data */\n schemas?: boolean;\n /** Rule needs link index data */\n links?: boolean;\n /** Entity names this rule cares about (for targeted invalidation) */\n entities?: \"all\" | string[];\n}\n\n/**\n * A validation rule\n */\nexport interface Rule {\n /** Unique rule code (e.g., \"unknown-entity\") */\n code: string;\n /** Human-readable rule name */\n name: string;\n /** Short description of what this rule checks */\n description: string;\n /** Category for grouping related rules */\n category: RuleCategory;\n /** Default severity for this rule */\n defaultSeverity: Severity;\n\n /**\n * Dependency declaration for incremental checking.\n */\n dependencies: RuleDependencies;\n\n /**\n * Visitor-based implementation.\n * Allows single-pass checking with other rules.\n */\n visitor: import(\"../visitor.js\").RuleVisitor;\n}\n\n// Existing rules\nimport { unknownEntityRule } from \"./unknown-entity.js\";\nimport { missingRequiredFieldRule } from \"./missing-required-field.js\";\nimport { unknownFieldRule } from \"./unknown-field.js\";\nimport { invalidFieldTypeRule } from \"./invalid-field-type.js\";\nimport { missingRequiredSectionRule } from \"./missing-required-section.js\";\nimport { unknownSectionRule } from \"./unknown-section.js\";\nimport { unresolvedLinkRule } from \"./unresolved-link.js\";\nimport { duplicateLinkIdRule } from \"./duplicate-link-id.js\";\n\n// Schema definition rules\nimport { duplicateEntityDefinitionRule } from \"./duplicate-entity-definition.js\";\nimport { alterUndefinedEntityRule } from \"./alter-undefined-entity.js\";\nimport { alterBeforeDefineRule } from \"./alter-before-define.js\";\nimport { duplicateFieldInSchemaRule } from \"./duplicate-field-in-schema.js\";\nimport { duplicateSectionInSchemaRule } from \"./duplicate-section-in-schema.js\";\nimport { removeUndefinedFieldRule } from \"./remove-undefined-field.js\";\nimport { removeUndefinedSectionRule } from \"./remove-undefined-section.js\";\nimport { invalidDefaultValueRule } from \"./invalid-default-value.js\";\nimport { defineEntityRequiresSectionRule } from \"./define-entity-requires-section.js\";\n\n// Metadata value rules\nimport { duplicateMetadataKeyRule } from \"./duplicate-metadata-key.js\";\nimport { emptyRequiredValueRule } from \"./empty-required-value.js\";\nimport { invalidDateRangeValueRule } from \"./invalid-date-range-value.js\";\n\n// Content/section rules\nimport { duplicateSectionHeadingRule } from \"./duplicate-section-heading.js\";\nimport { emptySectionRule } from \"./empty-section.js\";\n\n// Instance entry rules\nimport { updateWithoutCreateRule } from \"./update-without-create.js\";\nimport { timestampOutOfOrderRule } from \"./timestamp-out-of-order.js\";\nimport { createRequiresSectionRule } from \"./create-requires-section.js\";\nimport { duplicateTimestampRule } from \"./duplicate-timestamp.js\";\n\n// Style rules\nimport { missingTitleRule } from \"./missing-title.js\";\n\n// Synthesis rules\nimport { synthesisMissingSourcesRule } from \"./synthesis-missing-sources.js\";\nimport { synthesisMissingPromptRule } from \"./synthesis-missing-prompt.js\";\nimport { synthesisEmptyQueryRule } from \"./synthesis-empty-query.js\";\nimport { synthesisUnknownQueryEntityRule } from \"./synthesis-unknown-query-entity.js\";\nimport { actualizeUnresolvedTargetRule } from \"./actualize-unresolved-target.js\";\nimport { actualizeMissingUpdatedRule } from \"./actualize-missing-updated.js\";\n\n/**\n * All available validation rules\n */\nexport const allRules: Rule[] = [\n // Existing rules\n unknownEntityRule,\n missingRequiredFieldRule,\n unknownFieldRule,\n invalidFieldTypeRule,\n missingRequiredSectionRule,\n unknownSectionRule,\n unresolvedLinkRule,\n duplicateLinkIdRule,\n\n // Schema definition rules\n duplicateEntityDefinitionRule,\n alterUndefinedEntityRule,\n alterBeforeDefineRule,\n duplicateFieldInSchemaRule,\n duplicateSectionInSchemaRule,\n removeUndefinedFieldRule,\n removeUndefinedSectionRule,\n invalidDefaultValueRule,\n defineEntityRequiresSectionRule,\n\n // Metadata value rules\n duplicateMetadataKeyRule,\n emptyRequiredValueRule,\n invalidDateRangeValueRule,\n\n // Content/section rules\n duplicateSectionHeadingRule,\n emptySectionRule,\n\n // Instance entry rules\n updateWithoutCreateRule,\n timestampOutOfOrderRule,\n createRequiresSectionRule,\n duplicateTimestampRule,\n\n // Style rules\n missingTitleRule,\n\n // Synthesis rules\n synthesisMissingSourcesRule,\n synthesisMissingPromptRule,\n synthesisEmptyQueryRule,\n synthesisUnknownQueryEntityRule,\n actualizeUnresolvedTargetRule,\n actualizeMissingUpdatedRule,\n];\n\n/**\n * Get a rule by code\n */\nexport function getRule(code: string): Rule | undefined {\n return allRules.find((r) => r.code === code);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAaA,MAAaA,kBAA0E;CACrF,UAAU;EAAE,OAAO;EAAG,OAAO;EAAwB;CACrD,MAAM;EAAE,OAAO;EAAG,OAAO;EAAc;CACvC,QAAQ;EAAE,OAAO;EAAG,OAAO;EAA2B;CACtD,UAAU;EAAE,OAAO;EAAG,OAAO;EAAwB;CACrD,SAAS;EAAE,OAAO;EAAG,OAAO;EAAiB;CAC9C;;;;AAuGD,MAAaC,WAAmB;CAE9B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CAGA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CAGA;CACA;CACA;CAGA;CACA;CAGA;CACA;CACA;CACA;CAGA;CAGA;CACA;CACA;CACA;CACA;CACA;CACD"}
@@ -0,0 +1,35 @@
1
+ //#region src/checker/rules/synthesis-empty-query.ts
2
+ const category = "instance";
3
+ const visitor = { visitSynthesisEntry(entry, ctx) {
4
+ const title = entry.header.title.value;
5
+ const sourcesMetadata = entry.metadata.find((m) => m.key.value === "sources");
6
+ if (!sourcesMetadata) return;
7
+ const sourcesValue = sourcesMetadata.value;
8
+ if (sourcesValue.content.type === "quoted_value" && sourcesValue.content.value.trim() === "") ctx.report({
9
+ message: `Synthesis '${title}' has an empty query. Specify an entity type like 'lore', 'journal', 'opinion', or 'reference'.`,
10
+ file: ctx.file,
11
+ location: entry.location,
12
+ sourceMap: ctx.sourceMap,
13
+ data: { title }
14
+ });
15
+ } };
16
+ /**
17
+ * Check that synthesis queries have at least an entity type
18
+ *
19
+ * Note: This rule validates the "sources:" metadata value exists and contains
20
+ * valid query syntax. Query validation is simplified since the full query parsing
21
+ * happens at a different layer.
22
+ */
23
+ const synthesisEmptyQueryRule = {
24
+ code: "synthesis-empty-query",
25
+ name: "Synthesis Empty Query",
26
+ description: "A synthesis source query must specify an entity type",
27
+ category,
28
+ defaultSeverity: "error",
29
+ dependencies: { scope: "entry" },
30
+ visitor
31
+ };
32
+
33
+ //#endregion
34
+ export { synthesisEmptyQueryRule };
35
+ //# sourceMappingURL=synthesis-empty-query.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"synthesis-empty-query.js","names":["category: RuleCategory","visitor: RuleVisitor","synthesisEmptyQueryRule: Rule"],"sources":["../../../src/checker/rules/synthesis-empty-query.ts"],"sourcesContent":["import type { Rule, RuleCategory } from \"../rules/rules.js\";\nimport type { RuleVisitor } from \"../visitor.js\";\n\nconst category: RuleCategory = \"instance\";\n\nconst visitor: RuleVisitor = {\n visitSynthesisEntry(entry, ctx) {\n const title = entry.header.title.value;\n const sourcesMetadata = entry.metadata.find((m) => m.key.value === \"sources\");\n\n if (!sourcesMetadata) {\n // Missing sources is handled by synthesis-missing-sources rule\n return;\n }\n\n // Check if sources value is empty or just whitespace\n const sourcesValue = sourcesMetadata.value;\n if (sourcesValue.content.type === \"quoted_value\" && sourcesValue.content.value.trim() === \"\") {\n ctx.report({\n message: `Synthesis '${title}' has an empty query. Specify an entity type like 'lore', 'journal', 'opinion', or 'reference'.`,\n file: ctx.file,\n location: entry.location,\n sourceMap: ctx.sourceMap,\n data: { title },\n });\n }\n },\n};\n\n/**\n * Check that synthesis queries have at least an entity type\n *\n * Note: This rule validates the \"sources:\" metadata value exists and contains\n * valid query syntax. Query validation is simplified since the full query parsing\n * happens at a different layer.\n */\nexport const synthesisEmptyQueryRule: Rule = {\n code: \"synthesis-empty-query\",\n name: \"Synthesis Empty Query\",\n description: \"A synthesis source query must specify an entity type\",\n category,\n defaultSeverity: \"error\",\n dependencies: { scope: \"entry\" },\n visitor,\n};\n"],"mappings":";AAGA,MAAMA,WAAyB;AAE/B,MAAMC,UAAuB,EAC3B,oBAAoB,OAAO,KAAK;CAC9B,MAAM,QAAQ,MAAM,OAAO,MAAM;CACjC,MAAM,kBAAkB,MAAM,SAAS,MAAM,MAAM,EAAE,IAAI,UAAU,UAAU;AAE7E,KAAI,CAAC,gBAEH;CAIF,MAAM,eAAe,gBAAgB;AACrC,KAAI,aAAa,QAAQ,SAAS,kBAAkB,aAAa,QAAQ,MAAM,MAAM,KAAK,GACxF,KAAI,OAAO;EACT,SAAS,cAAc,MAAM;EAC7B,MAAM,IAAI;EACV,UAAU,MAAM;EAChB,WAAW,IAAI;EACf,MAAM,EAAE,OAAO;EAChB,CAAC;GAGP;;;;;;;;AASD,MAAaC,0BAAgC;CAC3C,MAAM;CACN,MAAM;CACN,aAAa;CACb;CACA,iBAAiB;CACjB,cAAc,EAAE,OAAO,SAAS;CAChC;CACD"}
@@ -0,0 +1,42 @@
1
+ //#region src/checker/rules/synthesis-missing-prompt.ts
2
+ const category = "instance";
3
+ const visitor = { visitSynthesisEntry(entry, ctx) {
4
+ const title = entry.header.title.value;
5
+ const linkId = entry.header.linkId.id;
6
+ const content = entry.content;
7
+ let hasPromptWithContent = false;
8
+ if (content) {
9
+ let foundPromptHeader = false;
10
+ for (const child of content.children) if (child.type === "markdown_header" && child.text.toLowerCase().includes("prompt")) foundPromptHeader = true;
11
+ else if (foundPromptHeader && child.type === "content_line") {
12
+ hasPromptWithContent = true;
13
+ break;
14
+ } else if (foundPromptHeader && child.type === "markdown_header") break;
15
+ }
16
+ if (!hasPromptWithContent) ctx.report({
17
+ message: `Synthesis '${title}' is missing a '# Prompt' section. Add instructions for the LLM.`,
18
+ file: ctx.file,
19
+ location: entry.location,
20
+ sourceMap: ctx.sourceMap,
21
+ data: {
22
+ title,
23
+ linkId
24
+ }
25
+ });
26
+ } };
27
+ /**
28
+ * Check that define-synthesis entries have a Prompt section
29
+ */
30
+ const synthesisMissingPromptRule = {
31
+ code: "synthesis-missing-prompt",
32
+ name: "Synthesis Missing Prompt",
33
+ description: "A define-synthesis entry should have a '# Prompt' section with instructions for the LLM",
34
+ category,
35
+ defaultSeverity: "warning",
36
+ dependencies: { scope: "entry" },
37
+ visitor
38
+ };
39
+
40
+ //#endregion
41
+ export { synthesisMissingPromptRule };
42
+ //# sourceMappingURL=synthesis-missing-prompt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"synthesis-missing-prompt.js","names":["category: RuleCategory","visitor: RuleVisitor","synthesisMissingPromptRule: Rule"],"sources":["../../../src/checker/rules/synthesis-missing-prompt.ts"],"sourcesContent":["import type { Rule, RuleCategory } from \"../rules/rules.js\";\nimport type { RuleVisitor } from \"../visitor.js\";\n\nconst category: RuleCategory = \"instance\";\n\nconst visitor: RuleVisitor = {\n visitSynthesisEntry(entry, ctx) {\n const title = entry.header.title.value;\n const linkId = entry.header.linkId.id;\n const content = entry.content;\n\n // Check if there's a # Prompt section with content\n let hasPromptWithContent = false;\n if (content) {\n let foundPromptHeader = false;\n for (const child of content.children) {\n if (child.type === \"markdown_header\" && child.text.toLowerCase().includes(\"prompt\")) {\n foundPromptHeader = true;\n } else if (foundPromptHeader && child.type === \"content_line\") {\n // Found content after the prompt header\n hasPromptWithContent = true;\n break;\n } else if (foundPromptHeader && child.type === \"markdown_header\") {\n // Hit another header before finding content - prompt section is empty\n break;\n }\n }\n }\n\n if (!hasPromptWithContent) {\n ctx.report({\n message: `Synthesis '${title}' is missing a '# Prompt' section. Add instructions for the LLM.`,\n file: ctx.file,\n location: entry.location,\n sourceMap: ctx.sourceMap,\n data: { title, linkId },\n });\n }\n },\n};\n\n/**\n * Check that define-synthesis entries have a Prompt section\n */\nexport const synthesisMissingPromptRule: Rule = {\n code: \"synthesis-missing-prompt\",\n name: \"Synthesis Missing Prompt\",\n description:\n \"A define-synthesis entry should have a '# Prompt' section with instructions for the LLM\",\n category,\n defaultSeverity: \"warning\",\n dependencies: { scope: \"entry\" },\n visitor,\n};\n"],"mappings":";AAGA,MAAMA,WAAyB;AAE/B,MAAMC,UAAuB,EAC3B,oBAAoB,OAAO,KAAK;CAC9B,MAAM,QAAQ,MAAM,OAAO,MAAM;CACjC,MAAM,SAAS,MAAM,OAAO,OAAO;CACnC,MAAM,UAAU,MAAM;CAGtB,IAAI,uBAAuB;AAC3B,KAAI,SAAS;EACX,IAAI,oBAAoB;AACxB,OAAK,MAAM,SAAS,QAAQ,SAC1B,KAAI,MAAM,SAAS,qBAAqB,MAAM,KAAK,aAAa,CAAC,SAAS,SAAS,CACjF,qBAAoB;WACX,qBAAqB,MAAM,SAAS,gBAAgB;AAE7D,0BAAuB;AACvB;aACS,qBAAqB,MAAM,SAAS,kBAE7C;;AAKN,KAAI,CAAC,qBACH,KAAI,OAAO;EACT,SAAS,cAAc,MAAM;EAC7B,MAAM,IAAI;EACV,UAAU,MAAM;EAChB,WAAW,IAAI;EACf,MAAM;GAAE;GAAO;GAAQ;EACxB,CAAC;GAGP;;;;AAKD,MAAaC,6BAAmC;CAC9C,MAAM;CACN,MAAM;CACN,aACE;CACF;CACA,iBAAiB;CACjB,cAAc,EAAE,OAAO,SAAS;CAChC;CACD"}
@@ -0,0 +1,32 @@
1
+ //#region src/checker/rules/synthesis-missing-sources.ts
2
+ const category = "instance";
3
+ const visitor = { visitSynthesisEntry(entry, ctx) {
4
+ const title = entry.header.title.value;
5
+ const linkId = entry.header.linkId.id;
6
+ if (!entry.metadata.find((m) => m.key.value === "sources")) ctx.report({
7
+ message: `Synthesis '${title}' is missing a 'sources:' field. Add a query like 'sources: lore where subject = ^self'.`,
8
+ file: ctx.file,
9
+ location: entry.location,
10
+ sourceMap: ctx.sourceMap,
11
+ data: {
12
+ title,
13
+ linkId
14
+ }
15
+ });
16
+ } };
17
+ /**
18
+ * Check that define-synthesis entries have a sources field
19
+ */
20
+ const synthesisMissingSourcesRule = {
21
+ code: "synthesis-missing-sources",
22
+ name: "Synthesis Missing Sources",
23
+ description: "A define-synthesis entry must have a 'sources:' field specifying which entries to query",
24
+ category,
25
+ defaultSeverity: "error",
26
+ dependencies: { scope: "entry" },
27
+ visitor
28
+ };
29
+
30
+ //#endregion
31
+ export { synthesisMissingSourcesRule };
32
+ //# sourceMappingURL=synthesis-missing-sources.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"synthesis-missing-sources.js","names":["category: RuleCategory","visitor: RuleVisitor","synthesisMissingSourcesRule: Rule"],"sources":["../../../src/checker/rules/synthesis-missing-sources.ts"],"sourcesContent":["import type { Rule, RuleCategory } from \"../rules/rules.js\";\nimport type { RuleVisitor } from \"../visitor.js\";\n\nconst category: RuleCategory = \"instance\";\n\nconst visitor: RuleVisitor = {\n visitSynthesisEntry(entry, ctx) {\n const title = entry.header.title.value;\n const linkId = entry.header.linkId.id;\n const sourcesMetadata = entry.metadata.find((m) => m.key.value === \"sources\");\n\n if (!sourcesMetadata) {\n ctx.report({\n message: `Synthesis '${title}' is missing a 'sources:' field. Add a query like 'sources: lore where subject = ^self'.`,\n file: ctx.file,\n location: entry.location,\n sourceMap: ctx.sourceMap,\n data: { title, linkId },\n });\n }\n },\n};\n\n/**\n * Check that define-synthesis entries have a sources field\n */\nexport const synthesisMissingSourcesRule: Rule = {\n code: \"synthesis-missing-sources\",\n name: \"Synthesis Missing Sources\",\n description:\n \"A define-synthesis entry must have a 'sources:' field specifying which entries to query\",\n category,\n defaultSeverity: \"error\",\n dependencies: { scope: \"entry\" },\n visitor,\n};\n"],"mappings":";AAGA,MAAMA,WAAyB;AAE/B,MAAMC,UAAuB,EAC3B,oBAAoB,OAAO,KAAK;CAC9B,MAAM,QAAQ,MAAM,OAAO,MAAM;CACjC,MAAM,SAAS,MAAM,OAAO,OAAO;AAGnC,KAAI,CAFoB,MAAM,SAAS,MAAM,MAAM,EAAE,IAAI,UAAU,UAAU,CAG3E,KAAI,OAAO;EACT,SAAS,cAAc,MAAM;EAC7B,MAAM,IAAI;EACV,UAAU,MAAM;EAChB,WAAW,IAAI;EACf,MAAM;GAAE;GAAO;GAAQ;EACxB,CAAC;GAGP;;;;AAKD,MAAaC,8BAAoC;CAC/C,MAAM;CACN,MAAM;CACN,aACE;CACF;CACA,iBAAiB;CACjB,cAAc,EAAE,OAAO,SAAS;CAChC;CACD"}
@@ -0,0 +1,39 @@
1
+ //#region src/checker/rules/synthesis-unknown-query-entity.ts
2
+ const category = "instance";
3
+ const visitor = { visitSynthesisEntry(entry, ctx) {
4
+ const sourcesMeta = entry.metadata.find((m) => m.key.value === "sources");
5
+ if (!sourcesMeta) return;
6
+ const content = sourcesMeta.value.content;
7
+ const queries = [];
8
+ if (content.type === "query_value") queries.push(content.query);
9
+ else if (content.type === "value_array") {
10
+ for (const elem of content.elements) if (elem.type === "query") queries.push(elem);
11
+ }
12
+ const registry = ctx.workspace.schemaRegistry;
13
+ for (const query of queries) if (!registry.has(query.entity)) ctx.report({
14
+ message: `Unknown entity type '${query.entity}' in synthesis query. Define it using 'define-entity ${query.entity}'.`,
15
+ file: ctx.file,
16
+ location: query.location,
17
+ sourceMap: ctx.sourceMap,
18
+ data: { entity: query.entity }
19
+ });
20
+ } };
21
+ /**
22
+ * Check that synthesis source queries reference defined entity types
23
+ */
24
+ const synthesisUnknownQueryEntityRule = {
25
+ code: "synthesis-unknown-query-entity",
26
+ name: "Synthesis Unknown Query Entity",
27
+ description: "A synthesis source query must reference a defined entity type",
28
+ category,
29
+ defaultSeverity: "error",
30
+ dependencies: {
31
+ scope: "entry",
32
+ schemas: true
33
+ },
34
+ visitor
35
+ };
36
+
37
+ //#endregion
38
+ export { synthesisUnknownQueryEntityRule };
39
+ //# sourceMappingURL=synthesis-unknown-query-entity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"synthesis-unknown-query-entity.js","names":["category: RuleCategory","visitor: RuleVisitor","queries: AstQuery[]","synthesisUnknownQueryEntityRule: Rule"],"sources":["../../../src/checker/rules/synthesis-unknown-query-entity.ts"],"sourcesContent":["import type { Rule, RuleCategory } from \"../rules/rules.js\";\nimport type { RuleVisitor } from \"../visitor.js\";\nimport type { Query as AstQuery } from \"../../ast/ast-types.js\";\n\nconst category: RuleCategory = \"instance\";\n\nconst visitor: RuleVisitor = {\n visitSynthesisEntry(entry, ctx) {\n const sourcesMeta = entry.metadata.find((m) => m.key.value === \"sources\");\n if (!sourcesMeta) {\n // Missing sources is handled by synthesis-missing-sources rule\n return;\n }\n\n const content = sourcesMeta.value.content;\n const queries: AstQuery[] = [];\n\n // Extract queries from sources (single query or array)\n if (content.type === \"query_value\") {\n queries.push(content.query);\n } else if (content.type === \"value_array\") {\n for (const elem of content.elements) {\n if (elem.type === \"query\") {\n queries.push(elem);\n }\n }\n }\n\n // Check each query's entity against the schema registry\n const registry = ctx.workspace.schemaRegistry;\n for (const query of queries) {\n if (!registry.has(query.entity)) {\n ctx.report({\n message: `Unknown entity type '${query.entity}' in synthesis query. Define it using 'define-entity ${query.entity}'.`,\n file: ctx.file,\n location: query.location,\n sourceMap: ctx.sourceMap,\n data: { entity: query.entity },\n });\n }\n }\n },\n};\n\n/**\n * Check that synthesis source queries reference defined entity types\n */\nexport const synthesisUnknownQueryEntityRule: Rule = {\n code: \"synthesis-unknown-query-entity\",\n name: \"Synthesis Unknown Query Entity\",\n description: \"A synthesis source query must reference a defined entity type\",\n category,\n defaultSeverity: \"error\",\n dependencies: { scope: \"entry\", schemas: true },\n visitor,\n};\n"],"mappings":";AAIA,MAAMA,WAAyB;AAE/B,MAAMC,UAAuB,EAC3B,oBAAoB,OAAO,KAAK;CAC9B,MAAM,cAAc,MAAM,SAAS,MAAM,MAAM,EAAE,IAAI,UAAU,UAAU;AACzE,KAAI,CAAC,YAEH;CAGF,MAAM,UAAU,YAAY,MAAM;CAClC,MAAMC,UAAsB,EAAE;AAG9B,KAAI,QAAQ,SAAS,cACnB,SAAQ,KAAK,QAAQ,MAAM;UAClB,QAAQ,SAAS,eAC1B;OAAK,MAAM,QAAQ,QAAQ,SACzB,KAAI,KAAK,SAAS,QAChB,SAAQ,KAAK,KAAK;;CAMxB,MAAM,WAAW,IAAI,UAAU;AAC/B,MAAK,MAAM,SAAS,QAClB,KAAI,CAAC,SAAS,IAAI,MAAM,OAAO,CAC7B,KAAI,OAAO;EACT,SAAS,wBAAwB,MAAM,OAAO,uDAAuD,MAAM,OAAO;EAClH,MAAM,IAAI;EACV,UAAU,MAAM;EAChB,WAAW,IAAI;EACf,MAAM,EAAE,QAAQ,MAAM,QAAQ;EAC/B,CAAC;GAIT;;;;AAKD,MAAaC,kCAAwC;CACnD,MAAM;CACN,MAAM;CACN,aAAa;CACb;CACA,iBAAiB;CACjB,cAAc;EAAE,OAAO;EAAS,SAAS;EAAM;CAC/C;CACD"}
@@ -0,0 +1,55 @@
1
+ import { formatTimestamp } from "../../formatters.js";
2
+
3
+ //#region src/checker/rules/timestamp-out-of-order.ts
4
+ const category = "instance";
5
+ /**
6
+ * Compare two timestamps, returning negative if a < b, positive if a > b, 0 if equal
7
+ */
8
+ function compareTimestamps(a, b) {
9
+ const aStr = formatTimestamp(a);
10
+ const bStr = formatTimestamp(b);
11
+ return aStr.localeCompare(bStr);
12
+ }
13
+ const visitor = { afterCheck(ctx) {
14
+ const { workspace } = ctx;
15
+ for (const model of workspace.allModels()) {
16
+ const entries = model.ast.entries;
17
+ if (entries.length < 2) continue;
18
+ let previousTimestamp = null;
19
+ for (const entry of entries) {
20
+ const timestamp = entry.type === "instance_entry" ? entry.header.timestamp : entry.type === "schema_entry" ? entry.header.timestamp : entry.type === "synthesis_entry" ? entry.header.timestamp : entry.type === "actualize_entry" ? entry.header.timestamp : null;
21
+ if (!timestamp) continue;
22
+ if (previousTimestamp !== null && compareTimestamps(timestamp, previousTimestamp) < 0) {
23
+ const currentStr = formatTimestamp(timestamp);
24
+ const previousStr = formatTimestamp(previousTimestamp);
25
+ ctx.report({
26
+ message: `Timestamp '${currentStr}' is earlier than previous entry '${previousStr}'. Entries should be in chronological order.`,
27
+ file: model.file,
28
+ location: entry.location,
29
+ sourceMap: model.sourceMap,
30
+ data: {
31
+ timestamp: currentStr,
32
+ previousTimestamp: previousStr
33
+ }
34
+ });
35
+ }
36
+ previousTimestamp = timestamp;
37
+ }
38
+ }
39
+ } };
40
+ /**
41
+ * Check for timestamps that are out of chronological order within a document
42
+ */
43
+ const timestampOutOfOrderRule = {
44
+ code: "timestamp-out-of-order",
45
+ name: "Timestamp Out of Order",
46
+ description: "Entry timestamp is earlier than the previous entry",
47
+ category,
48
+ defaultSeverity: "warning",
49
+ dependencies: { scope: "document" },
50
+ visitor
51
+ };
52
+
53
+ //#endregion
54
+ export { timestampOutOfOrderRule };
55
+ //# sourceMappingURL=timestamp-out-of-order.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"timestamp-out-of-order.js","names":["category: RuleCategory","visitor: RuleVisitor","previousTimestamp: Timestamp | null","timestampOutOfOrderRule: Rule"],"sources":["../../../src/checker/rules/timestamp-out-of-order.ts"],"sourcesContent":["import type { Rule, RuleCategory } from \"../rules/rules.js\";\nimport type { RuleVisitor, VisitorContext } from \"../visitor.js\";\nimport type { Timestamp } from \"../../ast/ast-types.js\";\nimport { formatTimestamp } from \"../../formatters.js\";\n\nconst category: RuleCategory = \"instance\";\n\n/**\n * Compare two timestamps, returning negative if a < b, positive if a > b, 0 if equal\n */\nfunction compareTimestamps(a: Timestamp, b: Timestamp): number {\n const aStr = formatTimestamp(a);\n const bStr = formatTimestamp(b);\n return aStr.localeCompare(bStr);\n}\n\nconst visitor: RuleVisitor = {\n afterCheck(ctx: VisitorContext) {\n const { workspace } = ctx;\n\n for (const model of workspace.allModels()) {\n const entries = model.ast.entries;\n\n if (entries.length < 2) {\n continue;\n }\n\n let previousTimestamp: Timestamp | null = null;\n\n for (const entry of entries) {\n // Get timestamp from entry header\n const timestamp =\n entry.type === \"instance_entry\"\n ? entry.header.timestamp\n : entry.type === \"schema_entry\"\n ? entry.header.timestamp\n : entry.type === \"synthesis_entry\"\n ? entry.header.timestamp\n : entry.type === \"actualize_entry\"\n ? entry.header.timestamp\n : null;\n\n if (!timestamp) {\n continue;\n }\n\n if (previousTimestamp !== null && compareTimestamps(timestamp, previousTimestamp) < 0) {\n const currentStr = formatTimestamp(timestamp);\n const previousStr = formatTimestamp(previousTimestamp);\n\n ctx.report({\n message: `Timestamp '${currentStr}' is earlier than previous entry '${previousStr}'. Entries should be in chronological order.`,\n file: model.file,\n location: entry.location,\n sourceMap: model.sourceMap,\n data: {\n timestamp: currentStr,\n previousTimestamp: previousStr,\n },\n });\n }\n\n previousTimestamp = timestamp;\n }\n }\n },\n};\n\n/**\n * Check for timestamps that are out of chronological order within a document\n */\nexport const timestampOutOfOrderRule: Rule = {\n code: \"timestamp-out-of-order\",\n name: \"Timestamp Out of Order\",\n description: \"Entry timestamp is earlier than the previous entry\",\n category,\n defaultSeverity: \"warning\",\n dependencies: { scope: \"document\" },\n visitor,\n};\n"],"mappings":";;;AAKA,MAAMA,WAAyB;;;;AAK/B,SAAS,kBAAkB,GAAc,GAAsB;CAC7D,MAAM,OAAO,gBAAgB,EAAE;CAC/B,MAAM,OAAO,gBAAgB,EAAE;AAC/B,QAAO,KAAK,cAAc,KAAK;;AAGjC,MAAMC,UAAuB,EAC3B,WAAW,KAAqB;CAC9B,MAAM,EAAE,cAAc;AAEtB,MAAK,MAAM,SAAS,UAAU,WAAW,EAAE;EACzC,MAAM,UAAU,MAAM,IAAI;AAE1B,MAAI,QAAQ,SAAS,EACnB;EAGF,IAAIC,oBAAsC;AAE1C,OAAK,MAAM,SAAS,SAAS;GAE3B,MAAM,YACJ,MAAM,SAAS,mBACX,MAAM,OAAO,YACb,MAAM,SAAS,iBACb,MAAM,OAAO,YACb,MAAM,SAAS,oBACb,MAAM,OAAO,YACb,MAAM,SAAS,oBACb,MAAM,OAAO,YACb;AAEZ,OAAI,CAAC,UACH;AAGF,OAAI,sBAAsB,QAAQ,kBAAkB,WAAW,kBAAkB,GAAG,GAAG;IACrF,MAAM,aAAa,gBAAgB,UAAU;IAC7C,MAAM,cAAc,gBAAgB,kBAAkB;AAEtD,QAAI,OAAO;KACT,SAAS,cAAc,WAAW,oCAAoC,YAAY;KAClF,MAAM,MAAM;KACZ,UAAU,MAAM;KAChB,WAAW,MAAM;KACjB,MAAM;MACJ,WAAW;MACX,mBAAmB;MACpB;KACF,CAAC;;AAGJ,uBAAoB;;;GAI3B;;;;AAKD,MAAaC,0BAAgC;CAC3C,MAAM;CACN,MAAM;CACN,aAAa;CACb;CACA,iBAAiB;CACjB,cAAc,EAAE,OAAO,YAAY;CACnC;CACD"}
@@ -0,0 +1,32 @@
1
+ //#region src/checker/rules/unknown-entity.ts
2
+ const category = "instance";
3
+ const visitor = { visitInstanceEntry(entry, ctx) {
4
+ const registry = ctx.workspace.schemaRegistry;
5
+ const entity = entry.header.entity;
6
+ if (!registry.has(entity)) ctx.report({
7
+ message: `Unknown entity type '${entity}'. Define it using 'define-entity ${entity}'.`,
8
+ file: ctx.file,
9
+ location: entry.location,
10
+ sourceMap: ctx.sourceMap,
11
+ data: { entity }
12
+ });
13
+ } };
14
+ /**
15
+ * Check for instance entries using undefined entity types
16
+ */
17
+ const unknownEntityRule = {
18
+ code: "unknown-entity",
19
+ name: "Unknown Entity",
20
+ description: "Instance entry uses an undefined entity type",
21
+ category,
22
+ defaultSeverity: "error",
23
+ dependencies: {
24
+ scope: "entry",
25
+ schemas: true
26
+ },
27
+ visitor
28
+ };
29
+
30
+ //#endregion
31
+ export { unknownEntityRule };
32
+ //# sourceMappingURL=unknown-entity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unknown-entity.js","names":["category: RuleCategory","visitor: RuleVisitor","unknownEntityRule: Rule"],"sources":["../../../src/checker/rules/unknown-entity.ts"],"sourcesContent":["import type { Rule, RuleCategory } from \"../rules/rules.js\";\nimport type { RuleVisitor } from \"../visitor.js\";\n\nconst category: RuleCategory = \"instance\";\n\nconst visitor: RuleVisitor = {\n visitInstanceEntry(entry, ctx) {\n const registry = ctx.workspace.schemaRegistry;\n const entity = entry.header.entity;\n\n if (!registry.has(entity)) {\n ctx.report({\n message: `Unknown entity type '${entity}'. Define it using 'define-entity ${entity}'.`,\n file: ctx.file,\n location: entry.location,\n sourceMap: ctx.sourceMap,\n data: { entity },\n });\n }\n },\n};\n\n/**\n * Check for instance entries using undefined entity types\n */\nexport const unknownEntityRule: Rule = {\n code: \"unknown-entity\",\n name: \"Unknown Entity\",\n description: \"Instance entry uses an undefined entity type\",\n category,\n defaultSeverity: \"error\",\n dependencies: { scope: \"entry\", schemas: true },\n visitor,\n};\n"],"mappings":";AAGA,MAAMA,WAAyB;AAE/B,MAAMC,UAAuB,EAC3B,mBAAmB,OAAO,KAAK;CAC7B,MAAM,WAAW,IAAI,UAAU;CAC/B,MAAM,SAAS,MAAM,OAAO;AAE5B,KAAI,CAAC,SAAS,IAAI,OAAO,CACvB,KAAI,OAAO;EACT,SAAS,wBAAwB,OAAO,oCAAoC,OAAO;EACnF,MAAM,IAAI;EACV,UAAU,MAAM;EAChB,WAAW,IAAI;EACf,MAAM,EAAE,QAAQ;EACjB,CAAC;GAGP;;;;AAKD,MAAaC,oBAA0B;CACrC,MAAM;CACN,MAAM;CACN,aAAa;CACb;CACA,iBAAiB;CACjB,cAAc;EAAE,OAAO;EAAS,SAAS;EAAM;CAC/C;CACD"}
@@ -0,0 +1,40 @@
1
+ //#region src/checker/rules/unknown-field.ts
2
+ const category = "instance";
3
+ const visitor = { visitInstanceEntry(entry, ctx) {
4
+ const registry = ctx.workspace.schemaRegistry;
5
+ const entity = entry.header.entity;
6
+ const schema = registry.get(entity);
7
+ if (!schema) return;
8
+ for (const meta of entry.metadata) {
9
+ const fieldName = meta.key.value;
10
+ if (!schema.fields.has(fieldName)) ctx.report({
11
+ message: `Unknown field '${fieldName}' for entity '${entity}'.`,
12
+ file: ctx.file,
13
+ location: meta.key.location,
14
+ sourceMap: ctx.sourceMap,
15
+ data: {
16
+ field: fieldName,
17
+ entity
18
+ }
19
+ });
20
+ }
21
+ } };
22
+ /**
23
+ * Check for metadata fields not defined in the entity schema
24
+ */
25
+ const unknownFieldRule = {
26
+ code: "unknown-field",
27
+ name: "Unknown Field",
28
+ description: "Metadata field not defined in entity schema",
29
+ category,
30
+ defaultSeverity: "warning",
31
+ dependencies: {
32
+ scope: "entry",
33
+ schemas: true
34
+ },
35
+ visitor
36
+ };
37
+
38
+ //#endregion
39
+ export { unknownFieldRule };
40
+ //# sourceMappingURL=unknown-field.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unknown-field.js","names":["category: RuleCategory","visitor: RuleVisitor","unknownFieldRule: Rule"],"sources":["../../../src/checker/rules/unknown-field.ts"],"sourcesContent":["import type { Rule, RuleCategory } from \"../rules/rules.js\";\nimport type { RuleVisitor } from \"../visitor.js\";\n\nconst category: RuleCategory = \"instance\";\n\nconst visitor: RuleVisitor = {\n visitInstanceEntry(entry, ctx) {\n const registry = ctx.workspace.schemaRegistry;\n const entity = entry.header.entity;\n const schema = registry.get(entity);\n\n if (!schema) {\n return; // Will be caught by unknown-entity rule\n }\n\n for (const meta of entry.metadata) {\n const fieldName = meta.key.value;\n if (!schema.fields.has(fieldName)) {\n ctx.report({\n message: `Unknown field '${fieldName}' for entity '${entity}'.`,\n file: ctx.file,\n // Use key.location to point to the field name, not the leading indent\n location: meta.key.location,\n sourceMap: ctx.sourceMap,\n data: { field: fieldName, entity },\n });\n }\n }\n },\n};\n\n/**\n * Check for metadata fields not defined in the entity schema\n */\nexport const unknownFieldRule: Rule = {\n code: \"unknown-field\",\n name: \"Unknown Field\",\n description: \"Metadata field not defined in entity schema\",\n category,\n defaultSeverity: \"warning\",\n dependencies: { scope: \"entry\", schemas: true },\n visitor,\n};\n"],"mappings":";AAGA,MAAMA,WAAyB;AAE/B,MAAMC,UAAuB,EAC3B,mBAAmB,OAAO,KAAK;CAC7B,MAAM,WAAW,IAAI,UAAU;CAC/B,MAAM,SAAS,MAAM,OAAO;CAC5B,MAAM,SAAS,SAAS,IAAI,OAAO;AAEnC,KAAI,CAAC,OACH;AAGF,MAAK,MAAM,QAAQ,MAAM,UAAU;EACjC,MAAM,YAAY,KAAK,IAAI;AAC3B,MAAI,CAAC,OAAO,OAAO,IAAI,UAAU,CAC/B,KAAI,OAAO;GACT,SAAS,kBAAkB,UAAU,gBAAgB,OAAO;GAC5D,MAAM,IAAI;GAEV,UAAU,KAAK,IAAI;GACnB,WAAW,IAAI;GACf,MAAM;IAAE,OAAO;IAAW;IAAQ;GACnC,CAAC;;GAIT;;;;AAKD,MAAaC,mBAAyB;CACpC,MAAM;CACN,MAAM;CACN,aAAa;CACb;CACA,iBAAiB;CACjB,cAAc;EAAE,OAAO;EAAS,SAAS;EAAM;CAC/C;CACD"}
@@ -0,0 +1,47 @@
1
+ //#region src/checker/rules/unknown-section.ts
2
+ const category = "instance";
3
+ /**
4
+ * Extract section names from entry content (markdown headers)
5
+ */
6
+ function getSectionNames(entry) {
7
+ if (!entry.content) return [];
8
+ return entry.content.children.filter((c) => c.type === "markdown_header").map((h) => {
9
+ const match = h.text.match(/^#+\s*(.+)$/);
10
+ return match ? match[1].trim() : h.text;
11
+ });
12
+ }
13
+ const visitor = { visitInstanceEntry(entry, ctx) {
14
+ const registry = ctx.workspace.schemaRegistry;
15
+ const entity = entry.header.entity;
16
+ const schema = registry.get(entity);
17
+ if (!schema) return;
18
+ for (const sectionName of getSectionNames(entry)) if (!schema.sections.has(sectionName)) ctx.report({
19
+ message: `Unknown section '${sectionName}' for entity '${entity}'.`,
20
+ file: ctx.file,
21
+ location: entry.location,
22
+ sourceMap: ctx.sourceMap,
23
+ data: {
24
+ section: sectionName,
25
+ entity
26
+ }
27
+ });
28
+ } };
29
+ /**
30
+ * Check for sections in content not defined in the entity schema
31
+ */
32
+ const unknownSectionRule = {
33
+ code: "unknown-section",
34
+ name: "Unknown Section",
35
+ description: "Section not defined in entity schema",
36
+ category,
37
+ defaultSeverity: "warning",
38
+ dependencies: {
39
+ scope: "entry",
40
+ schemas: true
41
+ },
42
+ visitor
43
+ };
44
+
45
+ //#endregion
46
+ export { unknownSectionRule };
47
+ //# sourceMappingURL=unknown-section.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unknown-section.js","names":["category: RuleCategory","visitor: RuleVisitor","unknownSectionRule: Rule"],"sources":["../../../src/checker/rules/unknown-section.ts"],"sourcesContent":["import type { Rule, RuleCategory } from \"../rules/rules.js\";\nimport type { RuleVisitor } from \"../visitor.js\";\nimport type { InstanceEntry } from \"../../ast/ast-types.js\";\n\nconst category: RuleCategory = \"instance\";\n\n/**\n * Extract section names from entry content (markdown headers)\n */\nfunction getSectionNames(entry: InstanceEntry): string[] {\n if (!entry.content) {\n return [];\n }\n return entry.content.children\n .filter((c) => c.type === \"markdown_header\")\n .map((h) => {\n // Extract section name from \"# SectionName\" format\n const match = h.text.match(/^#+\\s*(.+)$/);\n return match ? match[1].trim() : h.text;\n });\n}\n\nconst visitor: RuleVisitor = {\n visitInstanceEntry(entry, ctx) {\n const registry = ctx.workspace.schemaRegistry;\n const entity = entry.header.entity;\n const schema = registry.get(entity);\n\n if (!schema) {\n return; // Will be caught by unknown-entity rule\n }\n\n for (const sectionName of getSectionNames(entry)) {\n if (!schema.sections.has(sectionName)) {\n ctx.report({\n message: `Unknown section '${sectionName}' for entity '${entity}'.`,\n file: ctx.file,\n location: entry.location, // Ideally we'd have the section's location\n sourceMap: ctx.sourceMap,\n data: { section: sectionName, entity },\n });\n }\n }\n },\n};\n\n/**\n * Check for sections in content not defined in the entity schema\n */\nexport const unknownSectionRule: Rule = {\n code: \"unknown-section\",\n name: \"Unknown Section\",\n description: \"Section not defined in entity schema\",\n category,\n defaultSeverity: \"warning\",\n dependencies: { scope: \"entry\", schemas: true },\n visitor,\n};\n"],"mappings":";AAIA,MAAMA,WAAyB;;;;AAK/B,SAAS,gBAAgB,OAAgC;AACvD,KAAI,CAAC,MAAM,QACT,QAAO,EAAE;AAEX,QAAO,MAAM,QAAQ,SAClB,QAAQ,MAAM,EAAE,SAAS,kBAAkB,CAC3C,KAAK,MAAM;EAEV,MAAM,QAAQ,EAAE,KAAK,MAAM,cAAc;AACzC,SAAO,QAAQ,MAAM,GAAG,MAAM,GAAG,EAAE;GACnC;;AAGN,MAAMC,UAAuB,EAC3B,mBAAmB,OAAO,KAAK;CAC7B,MAAM,WAAW,IAAI,UAAU;CAC/B,MAAM,SAAS,MAAM,OAAO;CAC5B,MAAM,SAAS,SAAS,IAAI,OAAO;AAEnC,KAAI,CAAC,OACH;AAGF,MAAK,MAAM,eAAe,gBAAgB,MAAM,CAC9C,KAAI,CAAC,OAAO,SAAS,IAAI,YAAY,CACnC,KAAI,OAAO;EACT,SAAS,oBAAoB,YAAY,gBAAgB,OAAO;EAChE,MAAM,IAAI;EACV,UAAU,MAAM;EAChB,WAAW,IAAI;EACf,MAAM;GAAE,SAAS;GAAa;GAAQ;EACvC,CAAC;GAIT;;;;AAKD,MAAaC,qBAA2B;CACtC,MAAM;CACN,MAAM;CACN,aAAa;CACb;CACA,iBAAiB;CACjB,cAAc;EAAE,OAAO;EAAS,SAAS;EAAM;CAC/C;CACD"}
@@ -0,0 +1,34 @@
1
+ //#region src/checker/rules/unresolved-link.ts
2
+ const category = "link";
3
+ const visitor = { afterCheck(ctx) {
4
+ const linkIndex = ctx.workspace.linkIndex;
5
+ for (const [linkId, refs] of linkIndex.references) if (!linkIndex.definitions.get(linkId)) for (const ref of refs) {
6
+ const model = ctx.workspace.getModel(ref.file);
7
+ ctx.report({
8
+ message: `Unresolved link '^${linkId}'. No entry defines this link ID.`,
9
+ file: ref.file,
10
+ location: ref.location,
11
+ sourceMap: model?.sourceMap,
12
+ data: { linkId }
13
+ });
14
+ }
15
+ } };
16
+ /**
17
+ * Check for link references that don't resolve to any definition
18
+ */
19
+ const unresolvedLinkRule = {
20
+ code: "unresolved-link",
21
+ name: "Unresolved Link",
22
+ description: "Link reference (^id) has no definition",
23
+ category,
24
+ defaultSeverity: "warning",
25
+ dependencies: {
26
+ scope: "workspace",
27
+ links: true
28
+ },
29
+ visitor
30
+ };
31
+
32
+ //#endregion
33
+ export { unresolvedLinkRule };
34
+ //# sourceMappingURL=unresolved-link.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unresolved-link.js","names":["category: RuleCategory","visitor: RuleVisitor","unresolvedLinkRule: Rule"],"sources":["../../../src/checker/rules/unresolved-link.ts"],"sourcesContent":["import type { Rule, RuleCategory } from \"../rules/rules.js\";\nimport type { RuleVisitor, VisitorContext } from \"../visitor.js\";\n\nconst category: RuleCategory = \"link\";\n\nconst visitor: RuleVisitor = {\n afterCheck(ctx: VisitorContext) {\n const linkIndex = ctx.workspace.linkIndex;\n\n // Check all references to see if they have definitions\n for (const [linkId, refs] of linkIndex.references) {\n const definition = linkIndex.definitions.get(linkId);\n\n if (!definition) {\n // No definition found - report for each reference\n for (const ref of refs) {\n // Get source map from the model\n const model = ctx.workspace.getModel(ref.file);\n\n ctx.report({\n message: `Unresolved link '^${linkId}'. No entry defines this link ID.`,\n file: ref.file,\n location: ref.location,\n sourceMap: model?.sourceMap,\n data: { linkId },\n });\n }\n }\n }\n },\n};\n\n/**\n * Check for link references that don't resolve to any definition\n */\nexport const unresolvedLinkRule: Rule = {\n code: \"unresolved-link\",\n name: \"Unresolved Link\",\n description: \"Link reference (^id) has no definition\",\n category,\n defaultSeverity: \"warning\",\n dependencies: { scope: \"workspace\", links: true },\n visitor,\n};\n"],"mappings":";AAGA,MAAMA,WAAyB;AAE/B,MAAMC,UAAuB,EAC3B,WAAW,KAAqB;CAC9B,MAAM,YAAY,IAAI,UAAU;AAGhC,MAAK,MAAM,CAAC,QAAQ,SAAS,UAAU,WAGrC,KAAI,CAFe,UAAU,YAAY,IAAI,OAAO,CAIlD,MAAK,MAAM,OAAO,MAAM;EAEtB,MAAM,QAAQ,IAAI,UAAU,SAAS,IAAI,KAAK;AAE9C,MAAI,OAAO;GACT,SAAS,qBAAqB,OAAO;GACrC,MAAM,IAAI;GACV,UAAU,IAAI;GACd,WAAW,OAAO;GAClB,MAAM,EAAE,QAAQ;GACjB,CAAC;;GAKX;;;;AAKD,MAAaC,qBAA2B;CACtC,MAAM;CACN,MAAM;CACN,aAAa;CACb;CACA,iBAAiB;CACjB,cAAc;EAAE,OAAO;EAAa,OAAO;EAAM;CACjD;CACD"}
@@ -0,0 +1,65 @@
1
+ //#region src/checker/rules/update-without-create.ts
2
+ const category = "instance";
3
+ /**
4
+ * Get metadata link value for a given key
5
+ */
6
+ function getMetadataLink(entry, key) {
7
+ const meta = entry.metadata.find((m) => m.key.value === key);
8
+ if (!meta) return null;
9
+ const content = meta.value.content;
10
+ if (content.type === "link_value") return {
11
+ id: content.link.id,
12
+ location: content.link.location
13
+ };
14
+ return null;
15
+ }
16
+ const visitor = { visitInstanceEntry(entry, ctx) {
17
+ if (entry.header.directive !== "update") return;
18
+ const supersedes = getMetadataLink(entry, "supersedes");
19
+ if (!supersedes) return;
20
+ const definition = ctx.workspace.getLinkDefinition(supersedes.id);
21
+ if (!definition) return;
22
+ const supersededEntry = definition.entry;
23
+ if (supersededEntry.type === "instance_entry") {
24
+ if (supersededEntry.header.directive !== "create") ctx.report({
25
+ message: `'update' entry supersedes another '${supersededEntry.header.directive}' entry. Consider pointing to the original 'create' entry instead.`,
26
+ file: ctx.file,
27
+ location: supersedes.location,
28
+ sourceMap: ctx.sourceMap,
29
+ data: {
30
+ linkId: supersedes.id,
31
+ supersededDirective: supersededEntry.header.directive
32
+ }
33
+ });
34
+ else if (supersededEntry.header.entity !== entry.header.entity) ctx.report({
35
+ message: `'update ${entry.header.entity}' supersedes a '${supersededEntry.header.entity}' entry. Entity types should match.`,
36
+ file: ctx.file,
37
+ location: supersedes.location,
38
+ sourceMap: ctx.sourceMap,
39
+ data: {
40
+ linkId: supersedes.id,
41
+ expectedEntity: entry.header.entity,
42
+ actualEntity: supersededEntry.header.entity
43
+ }
44
+ });
45
+ }
46
+ } };
47
+ /**
48
+ * Check for 'update' entries that reference (via supersedes) a non-existent create entry
49
+ */
50
+ const updateWithoutCreateRule = {
51
+ code: "update-without-create",
52
+ name: "Update Without Create",
53
+ description: "update entry supersedes wrong directive/entity type",
54
+ category,
55
+ defaultSeverity: "warning",
56
+ dependencies: {
57
+ scope: "entry",
58
+ links: true
59
+ },
60
+ visitor
61
+ };
62
+
63
+ //#endregion
64
+ export { updateWithoutCreateRule };
65
+ //# sourceMappingURL=update-without-create.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update-without-create.js","names":["category: RuleCategory","visitor: RuleVisitor","updateWithoutCreateRule: Rule"],"sources":["../../../src/checker/rules/update-without-create.ts"],"sourcesContent":["import type { Rule, RuleCategory } from \"../rules/rules.js\";\nimport type { RuleVisitor } from \"../visitor.js\";\nimport type { InstanceEntry } from \"../../ast/ast-types.js\";\n\nconst category: RuleCategory = \"instance\";\n\n/**\n * Get metadata link value for a given key\n */\nfunction getMetadataLink(\n entry: InstanceEntry,\n key: string,\n): { id: string; location: import(\"../../ast/ast-types.js\").Location } | null {\n const meta = entry.metadata.find((m) => m.key.value === key);\n if (!meta) {\n return null;\n }\n\n const content = meta.value.content;\n if (content.type === \"link_value\") {\n return { id: content.link.id, location: content.link.location };\n }\n return null;\n}\n\nconst visitor: RuleVisitor = {\n visitInstanceEntry(entry, ctx) {\n if (entry.header.directive !== \"update\") {\n return;\n }\n\n // Check if there's a supersedes field\n const supersedes = getMetadataLink(entry, \"supersedes\");\n if (!supersedes) {\n return;\n }\n\n // Check if the superseded entry exists\n const definition = ctx.workspace.getLinkDefinition(supersedes.id);\n if (!definition) {\n // This will be caught by unresolved-link rule\n return;\n }\n\n // Check if the superseded entry is a create of the same entity type\n const supersededEntry = definition.entry;\n if (supersededEntry.type === \"instance_entry\") {\n if (supersededEntry.header.directive !== \"create\") {\n ctx.report({\n message: `'update' entry supersedes another '${supersededEntry.header.directive}' entry. Consider pointing to the original 'create' entry instead.`,\n file: ctx.file,\n location: supersedes.location,\n sourceMap: ctx.sourceMap,\n data: {\n linkId: supersedes.id,\n supersededDirective: supersededEntry.header.directive,\n },\n });\n } else if (supersededEntry.header.entity !== entry.header.entity) {\n ctx.report({\n message: `'update ${entry.header.entity}' supersedes a '${supersededEntry.header.entity}' entry. Entity types should match.`,\n file: ctx.file,\n location: supersedes.location,\n sourceMap: ctx.sourceMap,\n data: {\n linkId: supersedes.id,\n expectedEntity: entry.header.entity,\n actualEntity: supersededEntry.header.entity,\n },\n });\n }\n }\n },\n};\n\n/**\n * Check for 'update' entries that reference (via supersedes) a non-existent create entry\n */\nexport const updateWithoutCreateRule: Rule = {\n code: \"update-without-create\",\n name: \"Update Without Create\",\n description: \"update entry supersedes wrong directive/entity type\",\n category,\n defaultSeverity: \"warning\",\n dependencies: { scope: \"entry\", links: true },\n visitor,\n};\n"],"mappings":";AAIA,MAAMA,WAAyB;;;;AAK/B,SAAS,gBACP,OACA,KAC4E;CAC5E,MAAM,OAAO,MAAM,SAAS,MAAM,MAAM,EAAE,IAAI,UAAU,IAAI;AAC5D,KAAI,CAAC,KACH,QAAO;CAGT,MAAM,UAAU,KAAK,MAAM;AAC3B,KAAI,QAAQ,SAAS,aACnB,QAAO;EAAE,IAAI,QAAQ,KAAK;EAAI,UAAU,QAAQ,KAAK;EAAU;AAEjE,QAAO;;AAGT,MAAMC,UAAuB,EAC3B,mBAAmB,OAAO,KAAK;AAC7B,KAAI,MAAM,OAAO,cAAc,SAC7B;CAIF,MAAM,aAAa,gBAAgB,OAAO,aAAa;AACvD,KAAI,CAAC,WACH;CAIF,MAAM,aAAa,IAAI,UAAU,kBAAkB,WAAW,GAAG;AACjE,KAAI,CAAC,WAEH;CAIF,MAAM,kBAAkB,WAAW;AACnC,KAAI,gBAAgB,SAAS,kBAC3B;MAAI,gBAAgB,OAAO,cAAc,SACvC,KAAI,OAAO;GACT,SAAS,sCAAsC,gBAAgB,OAAO,UAAU;GAChF,MAAM,IAAI;GACV,UAAU,WAAW;GACrB,WAAW,IAAI;GACf,MAAM;IACJ,QAAQ,WAAW;IACnB,qBAAqB,gBAAgB,OAAO;IAC7C;GACF,CAAC;WACO,gBAAgB,OAAO,WAAW,MAAM,OAAO,OACxD,KAAI,OAAO;GACT,SAAS,WAAW,MAAM,OAAO,OAAO,kBAAkB,gBAAgB,OAAO,OAAO;GACxF,MAAM,IAAI;GACV,UAAU,WAAW;GACrB,WAAW,IAAI;GACf,MAAM;IACJ,QAAQ,WAAW;IACnB,gBAAgB,MAAM,OAAO;IAC7B,cAAc,gBAAgB,OAAO;IACtC;GACF,CAAC;;GAIT;;;;AAKD,MAAaC,0BAAgC;CAC3C,MAAM;CACN,MAAM;CACN,aAAa;CACb;CACA,iBAAiB;CACjB,cAAc;EAAE,OAAO;EAAS,OAAO;EAAM;CAC7C;CACD"}