@mrtdown/core 2.0.0-alpha.2 → 2.0.0-alpha.4

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 (112) hide show
  1. package/dist/cli/commands/create.d.ts +30 -0
  2. package/dist/cli/commands/create.js +189 -0
  3. package/dist/cli/commands/create.js.map +1 -0
  4. package/dist/cli/commands/list.d.ts +6 -0
  5. package/dist/cli/commands/list.js +106 -0
  6. package/dist/cli/commands/list.js.map +1 -0
  7. package/dist/cli/commands/show.d.ts +6 -0
  8. package/dist/cli/commands/show.js +156 -0
  9. package/dist/cli/commands/show.js.map +1 -0
  10. package/dist/cli/commands/validate.d.ts +6 -0
  11. package/dist/cli/commands/validate.js +19 -0
  12. package/dist/cli/commands/validate.js.map +1 -0
  13. package/dist/cli/index.d.ts +2 -0
  14. package/dist/cli/index.js +162 -0
  15. package/dist/cli/index.js.map +1 -0
  16. package/dist/index.d.ts +20 -11
  17. package/dist/index.js +20 -11
  18. package/dist/index.js.map +1 -1
  19. package/dist/llm/client.d.ts +2 -0
  20. package/dist/llm/client.js +5 -0
  21. package/dist/llm/client.js.map +1 -0
  22. package/dist/llm/common/MemoryStore.d.ts +21 -0
  23. package/dist/llm/common/MemoryStore.js +100 -0
  24. package/dist/llm/common/MemoryStore.js.map +1 -0
  25. package/dist/llm/common/MemoryStore.test.d.ts +1 -0
  26. package/dist/llm/common/MemoryStore.test.js +225 -0
  27. package/dist/llm/common/MemoryStore.test.js.map +1 -0
  28. package/dist/llm/common/formatCurrentState.d.ts +10 -0
  29. package/dist/llm/common/formatCurrentState.js +342 -0
  30. package/dist/llm/common/formatCurrentState.js.map +1 -0
  31. package/dist/llm/common/tool.d.ts +32 -0
  32. package/dist/llm/common/tool.js +6 -0
  33. package/dist/llm/common/tool.js.map +1 -0
  34. package/dist/llm/functions/extractClaimsFromNewEvidence/eval.test.d.ts +1 -0
  35. package/dist/llm/functions/extractClaimsFromNewEvidence/eval.test.js +433 -0
  36. package/dist/llm/functions/extractClaimsFromNewEvidence/eval.test.js.map +1 -0
  37. package/dist/llm/functions/extractClaimsFromNewEvidence/index.d.ts +18 -0
  38. package/dist/llm/functions/extractClaimsFromNewEvidence/index.js +153 -0
  39. package/dist/llm/functions/extractClaimsFromNewEvidence/index.js.map +1 -0
  40. package/dist/llm/functions/extractClaimsFromNewEvidence/prompt.d.ts +1 -0
  41. package/dist/llm/functions/extractClaimsFromNewEvidence/prompt.js +168 -0
  42. package/dist/llm/functions/extractClaimsFromNewEvidence/prompt.js.map +1 -0
  43. package/dist/llm/functions/extractClaimsFromNewEvidence/tools/FindLinesTool.d.ts +19 -0
  44. package/dist/llm/functions/extractClaimsFromNewEvidence/tools/FindLinesTool.js +65 -0
  45. package/dist/llm/functions/extractClaimsFromNewEvidence/tools/FindLinesTool.js.map +1 -0
  46. package/dist/llm/functions/extractClaimsFromNewEvidence/tools/FindServicesTool.d.ts +21 -0
  47. package/dist/llm/functions/extractClaimsFromNewEvidence/tools/FindServicesTool.js +115 -0
  48. package/dist/llm/functions/extractClaimsFromNewEvidence/tools/FindServicesTool.js.map +1 -0
  49. package/dist/llm/functions/extractClaimsFromNewEvidence/tools/FindStationsTool.d.ts +24 -0
  50. package/dist/llm/functions/extractClaimsFromNewEvidence/tools/FindStationsTool.js +110 -0
  51. package/dist/llm/functions/extractClaimsFromNewEvidence/tools/FindStationsTool.js.map +1 -0
  52. package/dist/llm/functions/generateIssueTitleAndSlug/index.d.ts +14 -0
  53. package/dist/llm/functions/generateIssueTitleAndSlug/index.js +38 -0
  54. package/dist/llm/functions/generateIssueTitleAndSlug/index.js.map +1 -0
  55. package/dist/llm/functions/generateIssueTitleAndSlug/prompt.d.ts +1 -0
  56. package/dist/llm/functions/generateIssueTitleAndSlug/prompt.js +23 -0
  57. package/dist/llm/functions/generateIssueTitleAndSlug/prompt.js.map +1 -0
  58. package/dist/llm/functions/translate/index.d.ts +1 -0
  59. package/dist/llm/functions/translate/index.js +59 -0
  60. package/dist/llm/functions/translate/index.js.map +1 -0
  61. package/dist/llm/functions/triageNewEvidence/eval.test.d.ts +1 -0
  62. package/dist/llm/functions/triageNewEvidence/eval.test.js +139 -0
  63. package/dist/llm/functions/triageNewEvidence/eval.test.js.map +1 -0
  64. package/dist/llm/functions/triageNewEvidence/index.d.ts +37 -0
  65. package/dist/llm/functions/triageNewEvidence/index.js +121 -0
  66. package/dist/llm/functions/triageNewEvidence/index.js.map +1 -0
  67. package/dist/llm/functions/triageNewEvidence/prompt.d.ts +1 -0
  68. package/dist/llm/functions/triageNewEvidence/prompt.js +60 -0
  69. package/dist/llm/functions/triageNewEvidence/prompt.js.map +1 -0
  70. package/dist/llm/functions/triageNewEvidence/tools/FindIssuesTool.d.ts +19 -0
  71. package/dist/llm/functions/triageNewEvidence/tools/FindIssuesTool.js +65 -0
  72. package/dist/llm/functions/triageNewEvidence/tools/FindIssuesTool.js.map +1 -0
  73. package/dist/llm/functions/triageNewEvidence/tools/GetIssueTool.d.ts +19 -0
  74. package/dist/llm/functions/triageNewEvidence/tools/GetIssueTool.js +37 -0
  75. package/dist/llm/functions/triageNewEvidence/tools/GetIssueTool.js.map +1 -0
  76. package/dist/scripts/ingestViaWebhook.d.ts +1 -0
  77. package/dist/scripts/ingestViaWebhook.js +9 -0
  78. package/dist/scripts/ingestViaWebhook.js.map +1 -0
  79. package/dist/validators/buildContext.d.ts +7 -0
  80. package/dist/validators/buildContext.js +164 -0
  81. package/dist/validators/buildContext.js.map +1 -0
  82. package/dist/validators/index.d.ts +17 -0
  83. package/dist/validators/index.js +58 -0
  84. package/dist/validators/index.js.map +1 -0
  85. package/dist/validators/issue.d.ts +13 -0
  86. package/dist/validators/issue.js +220 -0
  87. package/dist/validators/issue.js.map +1 -0
  88. package/dist/validators/landmark.d.ts +7 -0
  89. package/dist/validators/landmark.js +43 -0
  90. package/dist/validators/landmark.js.map +1 -0
  91. package/dist/validators/line.d.ts +8 -0
  92. package/dist/validators/line.js +87 -0
  93. package/dist/validators/line.js.map +1 -0
  94. package/dist/validators/operator.d.ts +7 -0
  95. package/dist/validators/operator.js +43 -0
  96. package/dist/validators/operator.js.map +1 -0
  97. package/dist/validators/service.d.ts +8 -0
  98. package/dist/validators/service.js +87 -0
  99. package/dist/validators/service.js.map +1 -0
  100. package/dist/validators/station.d.ts +8 -0
  101. package/dist/validators/station.js +93 -0
  102. package/dist/validators/station.js.map +1 -0
  103. package/dist/validators/town.d.ts +7 -0
  104. package/dist/validators/town.js +43 -0
  105. package/dist/validators/town.js.map +1 -0
  106. package/dist/validators/types.d.ts +19 -0
  107. package/dist/validators/types.js +2 -0
  108. package/dist/validators/types.js.map +1 -0
  109. package/dist/validators/utils.d.ts +2 -0
  110. package/dist/validators/utils.js +9 -0
  111. package/dist/validators/utils.js.map +1 -0
  112. package/package.json +11 -7
@@ -0,0 +1,220 @@
1
+ import { join } from 'node:path';
2
+ import { NdJson } from 'json-nd';
3
+ import z from 'zod';
4
+ import { EvidenceSchema } from '#schema/issue/evidence.js';
5
+ import { ImpactEventSchema } from '#schema/issue/impactEvent.js';
6
+ import { IssueSchema } from '#schema/issue/issue.js';
7
+ import { DIR_ISSUE } from '../constants.js';
8
+ import { loadJson } from './utils.js';
9
+ export function validateIssueSchema(data) {
10
+ const result = IssueSchema.safeParse(data);
11
+ if (result.success)
12
+ return [];
13
+ return result.error.issues.map((i) => ({
14
+ file: '',
15
+ message: `${i.path.length > 0 ? i.path.join('.') : 'root'}: ${i.message}`,
16
+ }));
17
+ }
18
+ export function validateEvidenceSchema(data) {
19
+ const result = EvidenceSchema.safeParse(data);
20
+ if (result.success)
21
+ return [];
22
+ return result.error.issues.map((i) => ({
23
+ file: '',
24
+ message: `${i.path.length > 0 ? i.path.join('.') : 'root'}: ${i.message}`,
25
+ }));
26
+ }
27
+ export function validateImpactEventSchema(data) {
28
+ const result = ImpactEventSchema.safeParse(data);
29
+ if (result.success)
30
+ return [];
31
+ return result.error.issues.map((i) => ({
32
+ file: '',
33
+ message: `${i.path.length > 0 ? i.path.join('.') : 'root'}: ${i.message}`,
34
+ }));
35
+ }
36
+ export function validateImpactEventRelationships(event, evidenceIds, file, lineNum, ctx) {
37
+ const errors = [];
38
+ if (!evidenceIds.has(event.basis.evidenceId)) {
39
+ errors.push({
40
+ file,
41
+ line: lineNum,
42
+ message: `basis.evidenceId "${event.basis.evidenceId}" does not exist in evidence`,
43
+ });
44
+ }
45
+ if (!ctx)
46
+ return errors;
47
+ if (event.entity.type === 'service') {
48
+ if (!ctx.serviceIds.has(event.entity.serviceId)) {
49
+ errors.push({
50
+ file,
51
+ line: lineNum,
52
+ message: `entity.serviceId "${event.entity.serviceId}" does not exist`,
53
+ });
54
+ }
55
+ }
56
+ else {
57
+ if (!ctx.stationIds.has(event.entity.stationId)) {
58
+ errors.push({
59
+ file,
60
+ line: lineNum,
61
+ message: `entity.stationId "${event.entity.stationId}" does not exist`,
62
+ });
63
+ }
64
+ }
65
+ if ('serviceScopes' in event && event.serviceScopes) {
66
+ for (const scope of event.serviceScopes) {
67
+ if (scope.type === 'service.segment') {
68
+ if (!ctx.stationIds.has(scope.fromStationId)) {
69
+ errors.push({
70
+ file,
71
+ line: lineNum,
72
+ message: `serviceScopes[].fromStationId "${scope.fromStationId}" does not exist`,
73
+ });
74
+ }
75
+ if (!ctx.stationIds.has(scope.toStationId)) {
76
+ errors.push({
77
+ file,
78
+ line: lineNum,
79
+ message: `serviceScopes[].toStationId "${scope.toStationId}" does not exist`,
80
+ });
81
+ }
82
+ }
83
+ else if (scope.type === 'service.point') {
84
+ if (!ctx.stationIds.has(scope.stationId)) {
85
+ errors.push({
86
+ file,
87
+ line: lineNum,
88
+ message: `serviceScopes[].stationId "${scope.stationId}" does not exist`,
89
+ });
90
+ }
91
+ }
92
+ }
93
+ }
94
+ return errors;
95
+ }
96
+ function validateIssueAtPath(store, relBase, ctx) {
97
+ const errors = [];
98
+ const issueJsonPath = join(relBase, 'issue.json');
99
+ if (!store.exists(issueJsonPath)) {
100
+ errors.push({
101
+ file: issueJsonPath,
102
+ message: 'Issue not found',
103
+ });
104
+ return errors;
105
+ }
106
+ const issueRaw = loadJson(store, issueJsonPath);
107
+ if (issueRaw) {
108
+ const schemaErrs = validateIssueSchema(issueRaw);
109
+ for (const e of schemaErrs) {
110
+ errors.push({ ...e, file: e.file || issueJsonPath });
111
+ }
112
+ }
113
+ else {
114
+ errors.push({
115
+ file: issueJsonPath,
116
+ message: 'Failed to parse JSON',
117
+ });
118
+ }
119
+ const evidenceIdsFromCtx = ctx?.evidenceIdsByIssue.get(relBase);
120
+ const evidenceIds = evidenceIdsFromCtx !== undefined ? evidenceIdsFromCtx : new Set();
121
+ const needToBuildEvidenceIds = evidenceIdsFromCtx === undefined;
122
+ const evidencePath = join(relBase, 'evidence.ndjson');
123
+ try {
124
+ const content = store.readText(evidencePath).trim();
125
+ if (content) {
126
+ const parsed = NdJson.parse(content);
127
+ for (let i = 0; i < parsed.length; i++) {
128
+ const row = parsed[i];
129
+ const schemaErrs = validateEvidenceSchema(row);
130
+ for (const e of schemaErrs) {
131
+ errors.push({
132
+ ...e,
133
+ file: evidencePath,
134
+ line: i + 1,
135
+ });
136
+ }
137
+ if (needToBuildEvidenceIds) {
138
+ const idParsed = z.object({ id: z.string() }).safeParse(row);
139
+ if (idParsed.success)
140
+ evidenceIds.add(idParsed.data.id);
141
+ }
142
+ }
143
+ }
144
+ }
145
+ catch {
146
+ // ignore missing
147
+ }
148
+ const impactPath = join(relBase, 'impact.ndjson');
149
+ try {
150
+ const content = store.readText(impactPath).trim();
151
+ if (content) {
152
+ const parsed = NdJson.parse(content);
153
+ for (let i = 0; i < parsed.length; i++) {
154
+ const row = parsed[i];
155
+ const schemaErrs = validateImpactEventSchema(row);
156
+ for (const e of schemaErrs) {
157
+ errors.push({
158
+ ...e,
159
+ file: impactPath,
160
+ line: i + 1,
161
+ });
162
+ }
163
+ const eventResult = z
164
+ .object({
165
+ entity: z.any(),
166
+ basis: z.any(),
167
+ serviceScopes: z.any().optional(),
168
+ })
169
+ .safeParse(row);
170
+ if (eventResult.success) {
171
+ const relErrs = validateImpactEventRelationships(row, evidenceIds, impactPath, i + 1, ctx);
172
+ errors.push(...relErrs);
173
+ }
174
+ }
175
+ }
176
+ }
177
+ catch {
178
+ // ignore missing
179
+ }
180
+ return errors;
181
+ }
182
+ /**
183
+ * Validates a single issue at the given path (e.g. "issue/2025/03/2025-03-11-x").
184
+ * Pass ctx for relationship validation (serviceIds, stationIds, evidenceIds).
185
+ */
186
+ export function validateIssue(store, relBase, ctx) {
187
+ return validateIssueAtPath(store, relBase, ctx);
188
+ }
189
+ export function validateIssues(store, ctx) {
190
+ const errors = [];
191
+ try {
192
+ const years = store.listDir(DIR_ISSUE);
193
+ for (const year of years) {
194
+ if (!/^\d{4}$/.test(year))
195
+ continue;
196
+ const monthsPath = join(DIR_ISSUE, year);
197
+ const months = store.listDir(monthsPath);
198
+ for (const month of months) {
199
+ if (!/^\d{2}$/.test(month))
200
+ continue;
201
+ const issuesPath = join(monthsPath, month);
202
+ const issues = store.listDir(issuesPath);
203
+ for (const issueId of issues) {
204
+ const relBase = join(DIR_ISSUE, year, month, issueId);
205
+ errors.push(...validateIssueAtPath(store, relBase, ctx));
206
+ }
207
+ }
208
+ }
209
+ }
210
+ catch (err) {
211
+ if (err.code !== 'ENOENT') {
212
+ errors.push({
213
+ file: DIR_ISSUE,
214
+ message: err instanceof Error ? err.message : String(err),
215
+ });
216
+ }
217
+ }
218
+ return errors;
219
+ }
220
+ //# sourceMappingURL=issue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"issue.js","sourceRoot":"/","sources":["validators/issue.ts"],"names":[],"mappings":"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","sourcesContent":["import { join } from 'node:path';\nimport { NdJson } from 'json-nd';\nimport z from 'zod';\nimport { EvidenceSchema } from '#schema/issue/evidence.js';\nimport type { ImpactEvent } from '#schema/issue/impactEvent.js';\nimport { ImpactEventSchema } from '#schema/issue/impactEvent.js';\nimport { IssueSchema } from '#schema/issue/issue.js';\nimport { DIR_ISSUE } from '../constants.js';\nimport type { IStore } from '../repo/common/store.js';\nimport type { ValidationContext, ValidationError } from './types.js';\nimport { loadJson } from './utils.js';\n\nexport function validateIssueSchema(data: unknown): ValidationError[] {\n const result = IssueSchema.safeParse(data);\n if (result.success) return [];\n return result.error.issues.map((i) => ({\n file: '',\n message: `${i.path.length > 0 ? i.path.join('.') : 'root'}: ${i.message}`,\n }));\n}\n\nexport function validateEvidenceSchema(data: unknown): ValidationError[] {\n const result = EvidenceSchema.safeParse(data);\n if (result.success) return [];\n return result.error.issues.map((i) => ({\n file: '',\n message: `${i.path.length > 0 ? i.path.join('.') : 'root'}: ${i.message}`,\n }));\n}\n\nexport function validateImpactEventSchema(data: unknown): ValidationError[] {\n const result = ImpactEventSchema.safeParse(data);\n if (result.success) return [];\n return result.error.issues.map((i) => ({\n file: '',\n message: `${i.path.length > 0 ? i.path.join('.') : 'root'}: ${i.message}`,\n }));\n}\n\nexport function validateImpactEventRelationships(\n event: ImpactEvent,\n evidenceIds: Set<string>,\n file: string,\n lineNum: number,\n ctx?: ValidationContext,\n): ValidationError[] {\n const errors: ValidationError[] = [];\n\n if (!evidenceIds.has(event.basis.evidenceId)) {\n errors.push({\n file,\n line: lineNum,\n message: `basis.evidenceId \"${event.basis.evidenceId}\" does not exist in evidence`,\n });\n }\n\n if (!ctx) return errors;\n\n if (event.entity.type === 'service') {\n if (!ctx.serviceIds.has(event.entity.serviceId)) {\n errors.push({\n file,\n line: lineNum,\n message: `entity.serviceId \"${event.entity.serviceId}\" does not exist`,\n });\n }\n } else {\n if (!ctx.stationIds.has(event.entity.stationId)) {\n errors.push({\n file,\n line: lineNum,\n message: `entity.stationId \"${event.entity.stationId}\" does not exist`,\n });\n }\n }\n\n if ('serviceScopes' in event && event.serviceScopes) {\n for (const scope of event.serviceScopes) {\n if (scope.type === 'service.segment') {\n if (!ctx.stationIds.has(scope.fromStationId)) {\n errors.push({\n file,\n line: lineNum,\n message: `serviceScopes[].fromStationId \"${scope.fromStationId}\" does not exist`,\n });\n }\n if (!ctx.stationIds.has(scope.toStationId)) {\n errors.push({\n file,\n line: lineNum,\n message: `serviceScopes[].toStationId \"${scope.toStationId}\" does not exist`,\n });\n }\n } else if (scope.type === 'service.point') {\n if (!ctx.stationIds.has(scope.stationId)) {\n errors.push({\n file,\n line: lineNum,\n message: `serviceScopes[].stationId \"${scope.stationId}\" does not exist`,\n });\n }\n }\n }\n }\n\n return errors;\n}\n\nfunction validateIssueAtPath(\n store: IStore,\n relBase: string,\n ctx?: ValidationContext,\n): ValidationError[] {\n const errors: ValidationError[] = [];\n const issueJsonPath = join(relBase, 'issue.json');\n\n if (!store.exists(issueJsonPath)) {\n errors.push({\n file: issueJsonPath,\n message: 'Issue not found',\n });\n return errors;\n }\n\n const issueRaw = loadJson<unknown>(store, issueJsonPath);\n if (issueRaw) {\n const schemaErrs = validateIssueSchema(issueRaw);\n for (const e of schemaErrs) {\n errors.push({ ...e, file: e.file || issueJsonPath });\n }\n } else {\n errors.push({\n file: issueJsonPath,\n message: 'Failed to parse JSON',\n });\n }\n\n const evidenceIdsFromCtx = ctx?.evidenceIdsByIssue.get(relBase);\n const evidenceIds =\n evidenceIdsFromCtx !== undefined ? evidenceIdsFromCtx : new Set<string>();\n const needToBuildEvidenceIds = evidenceIdsFromCtx === undefined;\n\n const evidencePath = join(relBase, 'evidence.ndjson');\n try {\n const content = store.readText(evidencePath).trim();\n if (content) {\n const parsed = NdJson.parse(content);\n for (let i = 0; i < parsed.length; i++) {\n const row = parsed[i];\n const schemaErrs = validateEvidenceSchema(row);\n for (const e of schemaErrs) {\n errors.push({\n ...e,\n file: evidencePath,\n line: i + 1,\n });\n }\n if (needToBuildEvidenceIds) {\n const idParsed = z.object({ id: z.string() }).safeParse(row);\n if (idParsed.success) evidenceIds.add(idParsed.data.id);\n }\n }\n }\n } catch {\n // ignore missing\n }\n\n const impactPath = join(relBase, 'impact.ndjson');\n try {\n const content = store.readText(impactPath).trim();\n if (content) {\n const parsed = NdJson.parse(content);\n for (let i = 0; i < parsed.length; i++) {\n const row = parsed[i];\n const schemaErrs = validateImpactEventSchema(row);\n for (const e of schemaErrs) {\n errors.push({\n ...e,\n file: impactPath,\n line: i + 1,\n });\n }\n const eventResult = z\n .object({\n entity: z.any(),\n basis: z.any(),\n serviceScopes: z.any().optional(),\n })\n .safeParse(row);\n if (eventResult.success) {\n const relErrs = validateImpactEventRelationships(\n row as ImpactEvent,\n evidenceIds,\n impactPath,\n i + 1,\n ctx,\n );\n errors.push(...relErrs);\n }\n }\n }\n } catch {\n // ignore missing\n }\n\n return errors;\n}\n\n/**\n * Validates a single issue at the given path (e.g. \"issue/2025/03/2025-03-11-x\").\n * Pass ctx for relationship validation (serviceIds, stationIds, evidenceIds).\n */\nexport function validateIssue(\n store: IStore,\n relBase: string,\n ctx?: ValidationContext,\n): ValidationError[] {\n return validateIssueAtPath(store, relBase, ctx);\n}\n\nexport function validateIssues(\n store: IStore,\n ctx?: ValidationContext,\n): ValidationError[] {\n const errors: ValidationError[] = [];\n try {\n const years = store.listDir(DIR_ISSUE);\n for (const year of years) {\n if (!/^\\d{4}$/.test(year)) continue;\n const monthsPath = join(DIR_ISSUE, year);\n const months = store.listDir(monthsPath);\n for (const month of months) {\n if (!/^\\d{2}$/.test(month)) continue;\n const issuesPath = join(monthsPath, month);\n const issues = store.listDir(issuesPath);\n for (const issueId of issues) {\n const relBase = join(DIR_ISSUE, year, month, issueId);\n errors.push(...validateIssueAtPath(store, relBase, ctx));\n }\n }\n }\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT') {\n errors.push({\n file: DIR_ISSUE,\n message: err instanceof Error ? err.message : String(err),\n });\n }\n }\n return errors;\n}\n"]}
@@ -0,0 +1,7 @@
1
+ import type { IStore } from '../repo/common/store.js';
2
+ import type { ValidationError } from './types.js';
3
+ export declare function validateLandmarkSchema(data: unknown): {
4
+ file: string;
5
+ message: string;
6
+ }[];
7
+ export declare function validateLandmarks(store: IStore): ValidationError[];
@@ -0,0 +1,43 @@
1
+ import { join } from 'node:path';
2
+ import { DIR_LANDMARK } from '../constants.js';
3
+ import { LandmarkSchema } from '../schema/Landmark.js';
4
+ import { loadJson } from './utils.js';
5
+ export function validateLandmarkSchema(data) {
6
+ const result = LandmarkSchema.safeParse(data);
7
+ if (result.success)
8
+ return [];
9
+ return result.error.issues.map((i) => ({
10
+ file: '',
11
+ message: `${i.path.length > 0 ? i.path.join('.') : 'root'}: ${i.message}`,
12
+ }));
13
+ }
14
+ export function validateLandmarks(store) {
15
+ const errors = [];
16
+ try {
17
+ const files = store.listDir(DIR_LANDMARK);
18
+ for (const file of files) {
19
+ if (!file.endsWith('.json'))
20
+ continue;
21
+ const relPath = join(DIR_LANDMARK, file);
22
+ const raw = loadJson(store, relPath);
23
+ if (raw === null) {
24
+ errors.push({ file: relPath, message: 'Failed to parse JSON' });
25
+ continue;
26
+ }
27
+ const schemaErrs = validateLandmarkSchema(raw);
28
+ for (const e of schemaErrs) {
29
+ errors.push({ ...e, file: e.file || relPath });
30
+ }
31
+ }
32
+ }
33
+ catch (err) {
34
+ if (err.code !== 'ENOENT') {
35
+ errors.push({
36
+ file: DIR_LANDMARK,
37
+ message: err instanceof Error ? err.message : String(err),
38
+ });
39
+ }
40
+ }
41
+ return errors;
42
+ }
43
+ //# sourceMappingURL=landmark.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"landmark.js","sourceRoot":"/","sources":["validators/landmark.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAE/C,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAEvD,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtC,MAAM,UAAU,sBAAsB,CACpC,IAAa;IAEb,MAAM,MAAM,GAAG,cAAc,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IAC9C,IAAI,MAAM,CAAC,OAAO;QAAE,OAAO,EAAE,CAAC;IAC9B,OAAO,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACrC,IAAI,EAAE,EAAE;QACR,OAAO,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,OAAO,EAAE;KAC1E,CAAC,CAAC,CAAC;AACN,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,KAAa;IAC7C,MAAM,MAAM,GAAsB,EAAE,CAAC;IACrC,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;QAC1C,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC;gBAAE,SAAS;YACtC,MAAM,OAAO,GAAG,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;YACzC,MAAM,GAAG,GAAG,QAAQ,CAAU,KAAK,EAAE,OAAO,CAAC,CAAC;YAC9C,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;gBACjB,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,sBAAsB,EAAE,CAAC,CAAC;gBAChE,SAAS;YACX,CAAC;YACD,MAAM,UAAU,GAAG,sBAAsB,CAAC,GAAG,CAAC,CAAC;YAC/C,KAAK,MAAM,CAAC,IAAI,UAAU,EAAE,CAAC;gBAC3B,MAAM,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,IAAI,OAAO,EAAE,CAAC,CAAC;YACjD,CAAC;QACH,CAAC;IACH,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAK,GAA6B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACrD,MAAM,CAAC,IAAI,CAAC;gBACV,IAAI,EAAE,YAAY;gBAClB,OAAO,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;aAC1D,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC","sourcesContent":["import { join } from 'node:path';\nimport { DIR_LANDMARK } from '../constants.js';\nimport type { IStore } from '../repo/common/store.js';\nimport { LandmarkSchema } from '../schema/Landmark.js';\nimport type { ValidationError } from './types.js';\nimport { loadJson } from './utils.js';\n\nexport function validateLandmarkSchema(\n data: unknown,\n): { file: string; message: string }[] {\n const result = LandmarkSchema.safeParse(data);\n if (result.success) return [];\n return result.error.issues.map((i) => ({\n file: '',\n message: `${i.path.length > 0 ? i.path.join('.') : 'root'}: ${i.message}`,\n }));\n}\n\nexport function validateLandmarks(store: IStore): ValidationError[] {\n const errors: ValidationError[] = [];\n try {\n const files = store.listDir(DIR_LANDMARK);\n for (const file of files) {\n if (!file.endsWith('.json')) continue;\n const relPath = join(DIR_LANDMARK, file);\n const raw = loadJson<unknown>(store, relPath);\n if (raw === null) {\n errors.push({ file: relPath, message: 'Failed to parse JSON' });\n continue;\n }\n const schemaErrs = validateLandmarkSchema(raw);\n for (const e of schemaErrs) {\n errors.push({ ...e, file: e.file || relPath });\n }\n }\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT') {\n errors.push({\n file: DIR_LANDMARK,\n message: err instanceof Error ? err.message : String(err),\n });\n }\n }\n return errors;\n}\n"]}
@@ -0,0 +1,8 @@
1
+ import type z from 'zod';
2
+ import { LineSchema } from '#schema/Line.js';
3
+ import type { IStore } from '../repo/common/store.js';
4
+ import type { ValidationContext, ValidationError } from './types.js';
5
+ export declare function validateLineSchema(data: unknown): ValidationError[];
6
+ export declare function validateLineRelationships(data: z.infer<typeof LineSchema>, ctx: ValidationContext, file: string): ValidationError[];
7
+ export declare function validateLines(store: IStore): ValidationError[];
8
+ export declare function validateLinesRelationships(store: IStore, ctx?: ValidationContext): ValidationError[];
@@ -0,0 +1,87 @@
1
+ import { join } from 'node:path';
2
+ import { LineSchema } from '#schema/Line.js';
3
+ import { DIR_LINE } from '../constants.js';
4
+ import { loadJson } from './utils.js';
5
+ export function validateLineSchema(data) {
6
+ const result = LineSchema.safeParse(data);
7
+ if (result.success)
8
+ return [];
9
+ return result.error.issues.map((i) => ({
10
+ file: '',
11
+ message: `${i.path.length > 0 ? i.path.join('.') : 'root'}: ${i.message}`,
12
+ }));
13
+ }
14
+ export function validateLineRelationships(data, ctx, file) {
15
+ const errors = [];
16
+ for (const op of data.operators) {
17
+ if (!ctx.operatorIds.has(op.operatorId)) {
18
+ errors.push({
19
+ file,
20
+ message: `operators[].operatorId "${op.operatorId}" does not exist`,
21
+ });
22
+ }
23
+ }
24
+ for (const serviceId of data.serviceIds) {
25
+ if (!ctx.serviceIds.has(serviceId)) {
26
+ errors.push({
27
+ file,
28
+ message: `serviceIds: "${serviceId}" does not exist`,
29
+ });
30
+ }
31
+ }
32
+ return errors;
33
+ }
34
+ export function validateLines(store) {
35
+ const errors = [];
36
+ try {
37
+ const files = store.listDir(DIR_LINE);
38
+ for (const file of files) {
39
+ if (!file.endsWith('.json'))
40
+ continue;
41
+ const relPath = join(DIR_LINE, file);
42
+ const raw = loadJson(store, relPath);
43
+ if (raw === null) {
44
+ errors.push({ file: relPath, message: 'Failed to parse JSON' });
45
+ continue;
46
+ }
47
+ const schemaErrs = validateLineSchema(raw);
48
+ for (const e of schemaErrs) {
49
+ errors.push({ ...e, file: e.file || relPath });
50
+ }
51
+ }
52
+ }
53
+ catch (err) {
54
+ if (err.code !== 'ENOENT') {
55
+ errors.push({
56
+ file: DIR_LINE,
57
+ message: err instanceof Error ? err.message : String(err),
58
+ });
59
+ }
60
+ }
61
+ return errors;
62
+ }
63
+ export function validateLinesRelationships(store, ctx) {
64
+ if (!ctx)
65
+ return [];
66
+ const errors = [];
67
+ try {
68
+ const files = store.listDir(DIR_LINE);
69
+ for (const file of files) {
70
+ if (!file.endsWith('.json'))
71
+ continue;
72
+ const relPath = join(DIR_LINE, file);
73
+ const raw = loadJson(store, relPath);
74
+ if (raw === null)
75
+ continue;
76
+ const parsed = LineSchema.safeParse(raw);
77
+ if (parsed.success) {
78
+ errors.push(...validateLineRelationships(parsed.data, ctx, relPath));
79
+ }
80
+ }
81
+ }
82
+ catch {
83
+ // ignore
84
+ }
85
+ return errors;
86
+ }
87
+ //# sourceMappingURL=line.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"line.js","sourceRoot":"/","sources":["validators/line.ts"],"names":[],"mappings":"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","sourcesContent":["import { join } from 'node:path';\nimport type z from 'zod';\nimport { LineSchema } from '#schema/Line.js';\nimport { DIR_LINE } from '../constants.js';\nimport type { IStore } from '../repo/common/store.js';\nimport type { ValidationContext, ValidationError } from './types.js';\nimport { loadJson } from './utils.js';\n\nexport function validateLineSchema(data: unknown): ValidationError[] {\n const result = LineSchema.safeParse(data);\n if (result.success) return [];\n return result.error.issues.map((i) => ({\n file: '',\n message: `${i.path.length > 0 ? i.path.join('.') : 'root'}: ${i.message}`,\n }));\n}\n\nexport function validateLineRelationships(\n data: z.infer<typeof LineSchema>,\n ctx: ValidationContext,\n file: string,\n): ValidationError[] {\n const errors: ValidationError[] = [];\n\n for (const op of data.operators) {\n if (!ctx.operatorIds.has(op.operatorId)) {\n errors.push({\n file,\n message: `operators[].operatorId \"${op.operatorId}\" does not exist`,\n });\n }\n }\n\n for (const serviceId of data.serviceIds) {\n if (!ctx.serviceIds.has(serviceId)) {\n errors.push({\n file,\n message: `serviceIds: \"${serviceId}\" does not exist`,\n });\n }\n }\n\n return errors;\n}\n\nexport function validateLines(store: IStore): ValidationError[] {\n const errors: ValidationError[] = [];\n try {\n const files = store.listDir(DIR_LINE);\n for (const file of files) {\n if (!file.endsWith('.json')) continue;\n const relPath = join(DIR_LINE, file);\n const raw = loadJson<unknown>(store, relPath);\n if (raw === null) {\n errors.push({ file: relPath, message: 'Failed to parse JSON' });\n continue;\n }\n const schemaErrs = validateLineSchema(raw);\n for (const e of schemaErrs) {\n errors.push({ ...e, file: e.file || relPath });\n }\n }\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT') {\n errors.push({\n file: DIR_LINE,\n message: err instanceof Error ? err.message : String(err),\n });\n }\n }\n return errors;\n}\n\nexport function validateLinesRelationships(\n store: IStore,\n ctx?: ValidationContext,\n): ValidationError[] {\n if (!ctx) return [];\n const errors: ValidationError[] = [];\n try {\n const files = store.listDir(DIR_LINE);\n for (const file of files) {\n if (!file.endsWith('.json')) continue;\n const relPath = join(DIR_LINE, file);\n const raw = loadJson<unknown>(store, relPath);\n if (raw === null) continue;\n const parsed = LineSchema.safeParse(raw);\n if (parsed.success) {\n errors.push(...validateLineRelationships(parsed.data, ctx, relPath));\n }\n }\n } catch {\n // ignore\n }\n return errors;\n}\n"]}
@@ -0,0 +1,7 @@
1
+ import type { IStore } from '../repo/common/store.js';
2
+ import type { ValidationError } from './types.js';
3
+ export declare function validateOperatorSchema(data: unknown): {
4
+ file: string;
5
+ message: string;
6
+ }[];
7
+ export declare function validateOperators(store: IStore): ValidationError[];
@@ -0,0 +1,43 @@
1
+ import { join } from 'node:path';
2
+ import { OperatorSchema } from '#schema/Operator.js';
3
+ import { DIR_OPERATOR } from '../constants.js';
4
+ import { loadJson } from './utils.js';
5
+ export function validateOperatorSchema(data) {
6
+ const result = OperatorSchema.safeParse(data);
7
+ if (result.success)
8
+ return [];
9
+ return result.error.issues.map((i) => ({
10
+ file: '',
11
+ message: `${i.path.length > 0 ? i.path.join('.') : 'root'}: ${i.message}`,
12
+ }));
13
+ }
14
+ export function validateOperators(store) {
15
+ const errors = [];
16
+ try {
17
+ const files = store.listDir(DIR_OPERATOR);
18
+ for (const file of files) {
19
+ if (!file.endsWith('.json'))
20
+ continue;
21
+ const relPath = join(DIR_OPERATOR, file);
22
+ const raw = loadJson(store, relPath);
23
+ if (raw === null) {
24
+ errors.push({ file: relPath, message: 'Failed to parse JSON' });
25
+ continue;
26
+ }
27
+ const schemaErrs = validateOperatorSchema(raw);
28
+ for (const e of schemaErrs) {
29
+ errors.push({ ...e, file: e.file || relPath });
30
+ }
31
+ }
32
+ }
33
+ catch (err) {
34
+ if (err.code !== 'ENOENT') {
35
+ errors.push({
36
+ file: DIR_OPERATOR,
37
+ message: err instanceof Error ? err.message : String(err),
38
+ });
39
+ }
40
+ }
41
+ return errors;
42
+ }
43
+ //# sourceMappingURL=operator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"operator.js","sourceRoot":"/","sources":["validators/operator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAG/C,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtC,MAAM,UAAU,sBAAsB,CACpC,IAAa;IAEb,MAAM,MAAM,GAAG,cAAc,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IAC9C,IAAI,MAAM,CAAC,OAAO;QAAE,OAAO,EAAE,CAAC;IAC9B,OAAO,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACrC,IAAI,EAAE,EAAE;QACR,OAAO,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,OAAO,EAAE;KAC1E,CAAC,CAAC,CAAC;AACN,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,KAAa;IAC7C,MAAM,MAAM,GAAsB,EAAE,CAAC;IACrC,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;QAC1C,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC;gBAAE,SAAS;YACtC,MAAM,OAAO,GAAG,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;YACzC,MAAM,GAAG,GAAG,QAAQ,CAAU,KAAK,EAAE,OAAO,CAAC,CAAC;YAC9C,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;gBACjB,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,sBAAsB,EAAE,CAAC,CAAC;gBAChE,SAAS;YACX,CAAC;YACD,MAAM,UAAU,GAAG,sBAAsB,CAAC,GAAG,CAAC,CAAC;YAC/C,KAAK,MAAM,CAAC,IAAI,UAAU,EAAE,CAAC;gBAC3B,MAAM,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,IAAI,OAAO,EAAE,CAAC,CAAC;YACjD,CAAC;QACH,CAAC;IACH,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAK,GAA6B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACrD,MAAM,CAAC,IAAI,CAAC;gBACV,IAAI,EAAE,YAAY;gBAClB,OAAO,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;aAC1D,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC","sourcesContent":["import { join } from 'node:path';\nimport { OperatorSchema } from '#schema/Operator.js';\nimport { DIR_OPERATOR } from '../constants.js';\nimport type { IStore } from '../repo/common/store.js';\nimport type { ValidationError } from './types.js';\nimport { loadJson } from './utils.js';\n\nexport function validateOperatorSchema(\n data: unknown,\n): { file: string; message: string }[] {\n const result = OperatorSchema.safeParse(data);\n if (result.success) return [];\n return result.error.issues.map((i) => ({\n file: '',\n message: `${i.path.length > 0 ? i.path.join('.') : 'root'}: ${i.message}`,\n }));\n}\n\nexport function validateOperators(store: IStore): ValidationError[] {\n const errors: ValidationError[] = [];\n try {\n const files = store.listDir(DIR_OPERATOR);\n for (const file of files) {\n if (!file.endsWith('.json')) continue;\n const relPath = join(DIR_OPERATOR, file);\n const raw = loadJson<unknown>(store, relPath);\n if (raw === null) {\n errors.push({ file: relPath, message: 'Failed to parse JSON' });\n continue;\n }\n const schemaErrs = validateOperatorSchema(raw);\n for (const e of schemaErrs) {\n errors.push({ ...e, file: e.file || relPath });\n }\n }\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT') {\n errors.push({\n file: DIR_OPERATOR,\n message: err instanceof Error ? err.message : String(err),\n });\n }\n }\n return errors;\n}\n"]}
@@ -0,0 +1,8 @@
1
+ import type z from 'zod';
2
+ import type { IStore } from '../repo/common/store.js';
3
+ import { ServiceSchema } from '../schema/Service.js';
4
+ import type { ValidationContext, ValidationError } from './types.js';
5
+ export declare function validateServiceSchema(data: unknown): ValidationError[];
6
+ export declare function validateServiceRelationships(data: z.infer<typeof ServiceSchema>, ctx: ValidationContext, file: string): ValidationError[];
7
+ export declare function validateServices(store: IStore): ValidationError[];
8
+ export declare function validateServicesRelationships(store: IStore, ctx?: ValidationContext): ValidationError[];
@@ -0,0 +1,87 @@
1
+ import { join } from 'node:path';
2
+ import { DIR_SERVICE } from '../constants.js';
3
+ import { ServiceSchema } from '../schema/Service.js';
4
+ import { loadJson } from './utils.js';
5
+ export function validateServiceSchema(data) {
6
+ const result = ServiceSchema.safeParse(data);
7
+ if (result.success)
8
+ return [];
9
+ return result.error.issues.map((i) => ({
10
+ file: '',
11
+ message: `${i.path.length > 0 ? i.path.join('.') : 'root'}: ${i.message}`,
12
+ }));
13
+ }
14
+ export function validateServiceRelationships(data, ctx, file) {
15
+ const errors = [];
16
+ if (!ctx.lineIds.has(data.lineId)) {
17
+ errors.push({
18
+ file,
19
+ message: `lineId "${data.lineId}" does not exist`,
20
+ });
21
+ }
22
+ for (const rev of data.revisions) {
23
+ for (const st of rev.path.stations) {
24
+ if (!ctx.stationIds.has(st.stationId)) {
25
+ errors.push({
26
+ file,
27
+ message: `revisions[].path.stations[].stationId "${st.stationId}" does not exist`,
28
+ });
29
+ }
30
+ }
31
+ }
32
+ return errors;
33
+ }
34
+ export function validateServices(store) {
35
+ const errors = [];
36
+ try {
37
+ const files = store.listDir(DIR_SERVICE);
38
+ for (const file of files) {
39
+ if (!file.endsWith('.json'))
40
+ continue;
41
+ const relPath = join(DIR_SERVICE, file);
42
+ const raw = loadJson(store, relPath);
43
+ if (raw === null) {
44
+ errors.push({ file: relPath, message: 'Failed to parse JSON' });
45
+ continue;
46
+ }
47
+ const schemaErrs = validateServiceSchema(raw);
48
+ for (const e of schemaErrs) {
49
+ errors.push({ ...e, file: e.file || relPath });
50
+ }
51
+ }
52
+ }
53
+ catch (err) {
54
+ if (err.code !== 'ENOENT') {
55
+ errors.push({
56
+ file: DIR_SERVICE,
57
+ message: err instanceof Error ? err.message : String(err),
58
+ });
59
+ }
60
+ }
61
+ return errors;
62
+ }
63
+ export function validateServicesRelationships(store, ctx) {
64
+ if (!ctx)
65
+ return [];
66
+ const errors = [];
67
+ try {
68
+ const files = store.listDir(DIR_SERVICE);
69
+ for (const file of files) {
70
+ if (!file.endsWith('.json'))
71
+ continue;
72
+ const relPath = join(DIR_SERVICE, file);
73
+ const raw = loadJson(store, relPath);
74
+ if (raw === null)
75
+ continue;
76
+ const parsed = ServiceSchema.safeParse(raw);
77
+ if (parsed.success) {
78
+ errors.push(...validateServiceRelationships(parsed.data, ctx, relPath));
79
+ }
80
+ }
81
+ }
82
+ catch {
83
+ // ignore
84
+ }
85
+ return errors;
86
+ }
87
+ //# sourceMappingURL=service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service.js","sourceRoot":"/","sources":["validators/service.ts"],"names":[],"mappings":"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","sourcesContent":["import { join } from 'node:path';\nimport type z from 'zod';\nimport { DIR_SERVICE } from '../constants.js';\nimport type { IStore } from '../repo/common/store.js';\nimport { ServiceSchema } from '../schema/Service.js';\nimport type { ValidationContext, ValidationError } from './types.js';\nimport { loadJson } from './utils.js';\n\nexport function validateServiceSchema(data: unknown): ValidationError[] {\n const result = ServiceSchema.safeParse(data);\n if (result.success) return [];\n return result.error.issues.map((i) => ({\n file: '',\n message: `${i.path.length > 0 ? i.path.join('.') : 'root'}: ${i.message}`,\n }));\n}\n\nexport function validateServiceRelationships(\n data: z.infer<typeof ServiceSchema>,\n ctx: ValidationContext,\n file: string,\n): ValidationError[] {\n const errors: ValidationError[] = [];\n\n if (!ctx.lineIds.has(data.lineId)) {\n errors.push({\n file,\n message: `lineId \"${data.lineId}\" does not exist`,\n });\n }\n\n for (const rev of data.revisions) {\n for (const st of rev.path.stations) {\n if (!ctx.stationIds.has(st.stationId)) {\n errors.push({\n file,\n message: `revisions[].path.stations[].stationId \"${st.stationId}\" does not exist`,\n });\n }\n }\n }\n\n return errors;\n}\n\nexport function validateServices(store: IStore): ValidationError[] {\n const errors: ValidationError[] = [];\n try {\n const files = store.listDir(DIR_SERVICE);\n for (const file of files) {\n if (!file.endsWith('.json')) continue;\n const relPath = join(DIR_SERVICE, file);\n const raw = loadJson<unknown>(store, relPath);\n if (raw === null) {\n errors.push({ file: relPath, message: 'Failed to parse JSON' });\n continue;\n }\n const schemaErrs = validateServiceSchema(raw);\n for (const e of schemaErrs) {\n errors.push({ ...e, file: e.file || relPath });\n }\n }\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT') {\n errors.push({\n file: DIR_SERVICE,\n message: err instanceof Error ? err.message : String(err),\n });\n }\n }\n return errors;\n}\n\nexport function validateServicesRelationships(\n store: IStore,\n ctx?: ValidationContext,\n): ValidationError[] {\n if (!ctx) return [];\n const errors: ValidationError[] = [];\n try {\n const files = store.listDir(DIR_SERVICE);\n for (const file of files) {\n if (!file.endsWith('.json')) continue;\n const relPath = join(DIR_SERVICE, file);\n const raw = loadJson<unknown>(store, relPath);\n if (raw === null) continue;\n const parsed = ServiceSchema.safeParse(raw);\n if (parsed.success) {\n errors.push(...validateServiceRelationships(parsed.data, ctx, relPath));\n }\n }\n } catch {\n // ignore\n }\n return errors;\n}\n"]}
@@ -0,0 +1,8 @@
1
+ import type z from 'zod';
2
+ import type { IStore } from '../repo/common/store.js';
3
+ import { StationSchema } from '../schema/Station.js';
4
+ import type { ValidationContext, ValidationError } from './types.js';
5
+ export declare function validateStationSchema(data: unknown): ValidationError[];
6
+ export declare function validateStationRelationships(data: z.infer<typeof StationSchema>, ctx: ValidationContext, file: string): ValidationError[];
7
+ export declare function validateStations(store: IStore): ValidationError[];
8
+ export declare function validateStationsRelationships(store: IStore, ctx?: ValidationContext): ValidationError[];