@ncukondo/search-hub 0.13.0 → 0.15.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.
- package/README.md +39 -9
- package/dist/cli/commands/check.d.ts +34 -0
- package/dist/cli/commands/check.d.ts.map +1 -0
- package/dist/cli/commands/check.js +126 -0
- package/dist/cli/commands/check.js.map +1 -0
- package/dist/cli/commands/export.d.ts +5 -3
- package/dist/cli/commands/export.d.ts.map +1 -1
- package/dist/cli/commands/export.js +0 -4
- package/dist/cli/commands/export.js.map +1 -1
- package/dist/cli/commands/query/init.d.ts.map +1 -1
- package/dist/cli/commands/query/init.js +17 -7
- package/dist/cli/commands/query/init.js.map +1 -1
- package/dist/cli/commands/query/inspect.d.ts +36 -0
- package/dist/cli/commands/query/inspect.d.ts.map +1 -0
- package/dist/cli/commands/query/inspect.js +155 -0
- package/dist/cli/commands/query/inspect.js.map +1 -0
- package/dist/cli/commands/query/translate.d.ts.map +1 -1
- package/dist/cli/commands/query/translate.js +3 -1
- package/dist/cli/commands/query/translate.js.map +1 -1
- package/dist/cli/commands/query-filter.d.ts +13 -0
- package/dist/cli/commands/query-filter.d.ts.map +1 -0
- package/dist/cli/commands/query-filter.js +149 -0
- package/dist/cli/commands/query-filter.js.map +1 -0
- package/dist/cli/commands/results.d.ts +3 -3
- package/dist/cli/commands/results.d.ts.map +1 -1
- package/dist/cli/commands/results.js +12 -3
- package/dist/cli/commands/results.js.map +1 -1
- package/dist/cli/commands/search-executor.d.ts.map +1 -1
- package/dist/cli/commands/search-executor.js +12 -7
- package/dist/cli/commands/search-executor.js.map +1 -1
- package/dist/cli/e2e-helpers.d.ts +5 -2
- package/dist/cli/e2e-helpers.d.ts.map +1 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +228 -45
- package/dist/cli/index.js.map +1 -1
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/dist/providers/arxiv/provider.d.ts +3 -3
- package/dist/providers/arxiv/provider.d.ts.map +1 -1
- package/dist/providers/arxiv/provider.js +3 -3
- package/dist/providers/arxiv/provider.js.map +1 -1
- package/dist/providers/arxiv/translator.d.ts +3 -3
- package/dist/providers/arxiv/translator.d.ts.map +1 -1
- package/dist/providers/arxiv/translator.js +6 -8
- package/dist/providers/arxiv/translator.js.map +1 -1
- package/dist/providers/base/index.d.ts +1 -1
- package/dist/providers/base/index.d.ts.map +1 -1
- package/dist/providers/base/mock-provider.d.ts +2 -2
- package/dist/providers/base/mock-provider.d.ts.map +1 -1
- package/dist/providers/base/mock-provider.js +2 -9
- package/dist/providers/base/mock-provider.js.map +1 -1
- package/dist/providers/base/provider.d.ts +3 -3
- package/dist/providers/base/provider.d.ts.map +1 -1
- package/dist/providers/base/provider.js.map +1 -1
- package/dist/providers/base/types.d.ts +4 -6
- package/dist/providers/base/types.d.ts.map +1 -1
- package/dist/providers/base/types.js.map +1 -1
- package/dist/providers/eric/provider.d.ts +3 -3
- package/dist/providers/eric/provider.d.ts.map +1 -1
- package/dist/providers/eric/provider.js +3 -3
- package/dist/providers/eric/provider.js.map +1 -1
- package/dist/providers/eric/translator.d.ts +5 -5
- package/dist/providers/eric/translator.d.ts.map +1 -1
- package/dist/providers/eric/translator.js +6 -7
- package/dist/providers/eric/translator.js.map +1 -1
- package/dist/providers/pubmed/provider.d.ts +3 -3
- package/dist/providers/pubmed/provider.d.ts.map +1 -1
- package/dist/providers/pubmed/provider.js +3 -3
- package/dist/providers/pubmed/provider.js.map +1 -1
- package/dist/providers/pubmed/translator.d.ts +3 -3
- package/dist/providers/pubmed/translator.d.ts.map +1 -1
- package/dist/providers/pubmed/translator.js +4 -23
- package/dist/providers/pubmed/translator.js.map +1 -1
- package/dist/providers/scopus/provider.d.ts +3 -3
- package/dist/providers/scopus/provider.d.ts.map +1 -1
- package/dist/providers/scopus/provider.js +3 -3
- package/dist/providers/scopus/provider.js.map +1 -1
- package/dist/providers/scopus/translator.d.ts +3 -3
- package/dist/providers/scopus/translator.d.ts.map +1 -1
- package/dist/providers/scopus/translator.js +7 -9
- package/dist/providers/scopus/translator.js.map +1 -1
- package/dist/query/index.d.ts +3 -2
- package/dist/query/index.d.ts.map +1 -1
- package/dist/query/json-schema.d.ts.map +1 -1
- package/dist/query/json-schema.js +20 -11
- package/dist/query/json-schema.js.map +1 -1
- package/dist/query/mesh-lookup.d.ts.map +1 -1
- package/dist/query/mesh-lookup.js +66 -3
- package/dist/query/mesh-lookup.js.map +1 -1
- package/dist/query/resolver.d.ts +14 -0
- package/dist/query/resolver.d.ts.map +1 -0
- package/dist/query/resolver.js +61 -0
- package/dist/query/resolver.js.map +1 -0
- package/dist/query/types.d.ts +31 -11
- package/dist/query/types.d.ts.map +1 -1
- package/dist/query/validator.d.ts +659 -348
- package/dist/query/validator.d.ts.map +1 -1
- package/dist/query/validator.js +70 -30
- package/dist/query/validator.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../../src/query/validator.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C;;GAEG;AACH,eAAO,MAAM,eAAe;;;;;;;EAO1B,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,eAAe;;;;;;iBAS3B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,cAAc;;;EAAwB,CAAC;AAEpD;;GAEG;AACH,eAAO,MAAM,gBAAgB
|
|
1
|
+
{"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../../src/query/validator.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C;;GAEG;AACH,eAAO,MAAM,eAAe;;;;;;;EAO1B,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,eAAe;;;;;;iBAS3B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,cAAc;;;EAAwB,CAAC;AAEpD;;GAEG;AACH,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;iBAK3B,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,2BAA2B;;;iBAGtC,CAAC;AAEH;;;GAGG;AACH,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkBrB,CAAC;AAEN;;GAEG;AACH,eAAO,MAAM,kBAAkB;;;;;;;EAO7B,CAAC;AAgCH;;GAEG;AACH,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAKhC,CAAC;AAiBH;;;GAGG;AACH,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BvB,CAAC;AAEN;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,OAAO,GAAG,QAAQ,CASzD;AAED;;GAEG;AACH,qBAAa,eAAgB,SAAQ,KAAK;aAEtB,IAAI,EAAE,MAAM;gBAAZ,IAAI,EAAE,MAAM,EAC5B,OAAO,EAAE,MAAM;CAKlB;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,OAAO,GAAG,eAAe,EAAE,CAsBvE"}
|
package/dist/query/validator.js
CHANGED
|
@@ -19,6 +19,7 @@ const termBlockSchema = z.object({
|
|
|
19
19
|
);
|
|
20
20
|
const operatorSchema = z.enum(["AND", "OR"]);
|
|
21
21
|
const queryBlockSchema = z.object({
|
|
22
|
+
id: z.string().min(1),
|
|
22
23
|
field: fieldTypeSchema,
|
|
23
24
|
terms: termBlockSchema,
|
|
24
25
|
operator: operatorSchema
|
|
@@ -31,29 +32,14 @@ const filtersSchema = z.object({
|
|
|
31
32
|
year_from: z.number().int().optional(),
|
|
32
33
|
year_to: z.number().int().optional(),
|
|
33
34
|
language: z.array(z.string()).optional(),
|
|
34
|
-
publication_types: publicationTypeFilterSchema.optional()
|
|
35
|
+
publication_types: publicationTypeFilterSchema.optional(),
|
|
36
|
+
categories: z.array(z.string()).optional(),
|
|
37
|
+
source_types: z.array(z.string()).optional()
|
|
35
38
|
}).optional().default({}).transform((data) => ({
|
|
36
39
|
yearFrom: data.year_from,
|
|
37
40
|
yearTo: data.year_to,
|
|
38
41
|
languages: data.language,
|
|
39
|
-
publicationTypes: data.publication_types
|
|
40
|
-
}));
|
|
41
|
-
const overrideBlockSchema = z.object({
|
|
42
|
-
filters: z.object({
|
|
43
|
-
year_from: z.number().int().optional(),
|
|
44
|
-
year_to: z.number().int().optional(),
|
|
45
|
-
language: z.array(z.string()).optional(),
|
|
46
|
-
publication_types: publicationTypeFilterSchema.optional()
|
|
47
|
-
}).optional(),
|
|
48
|
-
categories: z.array(z.string()).optional(),
|
|
49
|
-
source_types: z.array(z.string()).optional()
|
|
50
|
-
}).transform((data) => ({
|
|
51
|
-
filters: data.filters ? {
|
|
52
|
-
yearFrom: data.filters.year_from,
|
|
53
|
-
yearTo: data.filters.year_to,
|
|
54
|
-
languages: data.filters.language,
|
|
55
|
-
publicationTypes: data.filters.publication_types
|
|
56
|
-
} : void 0,
|
|
42
|
+
publicationTypes: data.publication_types,
|
|
57
43
|
categories: data.categories,
|
|
58
44
|
sourceTypes: data.source_types
|
|
59
45
|
}));
|
|
@@ -65,28 +51,74 @@ z.enum([
|
|
|
65
51
|
"wos",
|
|
66
52
|
"embase"
|
|
67
53
|
]);
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
54
|
+
const blockReplacementSchema = z.object({
|
|
55
|
+
field: fieldTypeSchema,
|
|
56
|
+
terms: termBlockSchema,
|
|
57
|
+
operator: operatorSchema
|
|
58
|
+
});
|
|
59
|
+
const addsFiltersSchema = z.object({
|
|
60
|
+
year_from: z.number().int().optional(),
|
|
61
|
+
year_to: z.number().int().optional(),
|
|
62
|
+
language: z.array(z.string()).optional(),
|
|
63
|
+
publication_types: publicationTypeFilterSchema.optional(),
|
|
64
|
+
categories: z.array(z.string()).optional(),
|
|
65
|
+
source_types: z.array(z.string()).optional()
|
|
66
|
+
}).transform((data) => ({
|
|
67
|
+
yearFrom: data.year_from,
|
|
68
|
+
yearTo: data.year_to,
|
|
69
|
+
languages: data.language,
|
|
70
|
+
publicationTypes: data.publication_types,
|
|
71
|
+
categories: data.categories,
|
|
72
|
+
sourceTypes: data.source_types
|
|
73
|
+
}));
|
|
74
|
+
const providerSectionSchema = z.object({
|
|
75
|
+
replaces: z.record(z.string(), blockReplacementSchema).optional(),
|
|
76
|
+
adds: z.object({
|
|
77
|
+
filters: addsFiltersSchema.optional()
|
|
78
|
+
}).optional()
|
|
79
|
+
});
|
|
80
|
+
const providersSchema = z.object({
|
|
81
|
+
pubmed: providerSectionSchema.optional(),
|
|
82
|
+
scopus: providerSectionSchema.optional(),
|
|
83
|
+
eric: providerSectionSchema.optional(),
|
|
84
|
+
arxiv: providerSectionSchema.optional(),
|
|
85
|
+
wos: providerSectionSchema.optional(),
|
|
86
|
+
embase: providerSectionSchema.optional()
|
|
75
87
|
}).optional().default({});
|
|
76
88
|
const queryFileSchema = z.object({
|
|
77
89
|
name: z.string().min(1),
|
|
78
90
|
description: z.string().optional(),
|
|
79
91
|
query: z.array(queryBlockSchema).min(1),
|
|
80
92
|
filters: filtersSchema,
|
|
81
|
-
|
|
82
|
-
}).
|
|
93
|
+
providers: providersSchema
|
|
94
|
+
}).refine(
|
|
95
|
+
(data) => {
|
|
96
|
+
const blockIds = new Set(data.query.map((b) => b.id));
|
|
97
|
+
for (const [, section] of Object.entries(data.providers ?? {})) {
|
|
98
|
+
if (section?.replaces) {
|
|
99
|
+
for (const key of Object.keys(section.replaces)) {
|
|
100
|
+
if (!blockIds.has(key)) {
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return true;
|
|
107
|
+
},
|
|
108
|
+
{ message: "replaces keys must reference existing block ids" }
|
|
109
|
+
).transform((data) => ({
|
|
83
110
|
name: data.name,
|
|
84
111
|
description: data.description,
|
|
85
112
|
blocks: data.query,
|
|
86
113
|
filters: data.filters,
|
|
87
|
-
|
|
114
|
+
providers: data.providers
|
|
88
115
|
}));
|
|
89
116
|
function validateQueryFile(data) {
|
|
117
|
+
if (typeof data === "object" && data !== null && "overrides" in data) {
|
|
118
|
+
throw new Error(
|
|
119
|
+
'The "overrides" key is no longer supported. Migrate to the new "providers" format. See spec/models/query-dsl.md for details.'
|
|
120
|
+
);
|
|
121
|
+
}
|
|
90
122
|
return queryFileSchema.parse(data);
|
|
91
123
|
}
|
|
92
124
|
class ValidationError extends Error {
|
|
@@ -97,6 +129,14 @@ class ValidationError extends Error {
|
|
|
97
129
|
}
|
|
98
130
|
}
|
|
99
131
|
function formatValidationErrors(data) {
|
|
132
|
+
if (typeof data === "object" && data !== null && "overrides" in data) {
|
|
133
|
+
return [
|
|
134
|
+
new ValidationError(
|
|
135
|
+
"overrides",
|
|
136
|
+
'The "overrides" key is no longer supported. Migrate to the new "providers" format. See spec/models/query-dsl.md for details.'
|
|
137
|
+
)
|
|
138
|
+
];
|
|
139
|
+
}
|
|
100
140
|
const result = queryFileSchema.safeParse(data);
|
|
101
141
|
if (result.success) {
|
|
102
142
|
return [];
|
|
@@ -112,7 +152,7 @@ export {
|
|
|
112
152
|
filtersSchema,
|
|
113
153
|
formatValidationErrors,
|
|
114
154
|
operatorSchema,
|
|
115
|
-
|
|
155
|
+
providerSectionSchema,
|
|
116
156
|
publicationTypeFilterSchema,
|
|
117
157
|
queryBlockSchema,
|
|
118
158
|
queryFileSchema,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validator.js","sources":["../../src/query/validator.ts"],"sourcesContent":["/**\n * Query Schema Validation using Zod\n *\n * Validates query YAML structure against the query DSL schema.\n * See spec/models/query-dsl.md for the full specification.\n */\n\nimport { z } from 'zod';\nimport type { QueryAST } from './types.js';\n\n/**\n * Schema for field types.\n */\nexport const fieldTypeSchema = z.enum([\n 'title',\n 'abstract',\n 'title_abstract',\n 'author',\n 'keyword',\n 'all',\n]);\n\n/**\n * Schema for term block containing search terms.\n */\nexport const termBlockSchema = z.object({\n keywords: z.array(z.string()).min(1).optional(),\n mesh: z.array(z.string()).optional(),\n emtree: z.array(z.string()).optional(),\n eric: z.array(z.string()).optional(),\n exclude: z.array(z.string()).optional(),\n}).refine(\n (data) => data.keywords?.length || data.mesh?.length || data.emtree?.length || data.eric?.length,\n { message: 'At least one of keywords, mesh, emtree, or eric is required' }\n);\n\n/**\n * Schema for operator.\n */\nexport const operatorSchema = z.enum(['AND', 'OR']);\n\n/**\n * Schema for query block.\n */\nexport const queryBlockSchema = z.object({\n field: fieldTypeSchema,\n terms: termBlockSchema,\n operator: operatorSchema,\n});\n\n/**\n * Schema for publication type filter.\n */\nexport const publicationTypeFilterSchema = z.object({\n include: z.array(z.string()).optional(),\n exclude: z.array(z.string()).optional(),\n});\n\n/**\n * Schema for filters (YAML input format with snake_case).\n * Transforms to camelCase for internal use.\n */\nexport const filtersSchema = z\n .object({\n year_from: z.number().int().optional(),\n year_to: z.number().int().optional(),\n language: z.array(z.string()).optional(),\n publication_types: publicationTypeFilterSchema.optional(),\n })\n .optional()\n .default({})\n .transform((data) => ({\n yearFrom: data.year_from,\n yearTo: data.year_to,\n languages: data.language,\n publicationTypes: data.publication_types,\n }));\n\n/**\n * Schema for override block (YAML input format).\n */\nexport const overrideBlockSchema = z\n .object({\n filters: z\n .object({\n year_from: z.number().int().optional(),\n year_to: z.number().int().optional(),\n language: z.array(z.string()).optional(),\n publication_types: publicationTypeFilterSchema.optional(),\n })\n .optional(),\n categories: z.array(z.string()).optional(),\n source_types: z.array(z.string()).optional(),\n })\n .transform((data) => ({\n filters: data.filters\n ? {\n yearFrom: data.filters.year_from,\n yearTo: data.filters.year_to,\n languages: data.filters.language,\n publicationTypes: data.filters.publication_types,\n }\n : undefined,\n categories: data.categories,\n sourceTypes: data.source_types,\n }));\n\n/**\n * Provider names schema.\n */\nexport const providerNameSchema = z.enum([\n 'pubmed',\n 'scopus',\n 'eric',\n 'arxiv',\n 'wos',\n 'embase',\n]);\n\n/**\n * Schema for overrides object (partial record of provider -> override).\n */\nconst overridesSchema = z\n .object({\n pubmed: overrideBlockSchema.optional(),\n scopus: overrideBlockSchema.optional(),\n eric: overrideBlockSchema.optional(),\n arxiv: overrideBlockSchema.optional(),\n wos: overrideBlockSchema.optional(),\n embase: overrideBlockSchema.optional(),\n })\n .optional()\n .default({});\n\n/**\n * Schema for the complete query file (YAML input format).\n * Transforms to QueryAST for internal use.\n */\nexport const queryFileSchema = z\n .object({\n name: z.string().min(1),\n description: z.string().optional(),\n query: z.array(queryBlockSchema).min(1),\n filters: filtersSchema,\n overrides: overridesSchema,\n })\n .transform((data) => ({\n name: data.name,\n description: data.description,\n blocks: data.query,\n filters: data.filters,\n overrides: data.overrides,\n }));\n\n/**\n * Validate a parsed YAML object against the query schema.\n * Returns a validated QueryAST.\n */\nexport function validateQueryFile(data: unknown): QueryAST {\n return queryFileSchema.parse(data);\n}\n\n/**\n * Validation error with path information.\n */\nexport class ValidationError extends Error {\n constructor(\n public readonly path: string,\n message: string\n ) {\n super(message);\n this.name = 'ValidationError';\n }\n}\n\n/**\n * Format Zod validation errors into an array of ValidationError objects.\n *\n * @param data - The data to validate\n * @returns Array of ValidationError objects (empty if valid)\n */\nexport function formatValidationErrors(data: unknown): ValidationError[] {\n const result = queryFileSchema.safeParse(data);\n\n if (result.success) {\n return [];\n }\n\n return result.error.issues.map((issue) => {\n const path = issue.path.join('.');\n return new ValidationError(path, issue.message);\n });\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"validator.js","sources":["../../src/query/validator.ts"],"sourcesContent":["/**\n * Query Schema Validation using Zod\n *\n * Validates query YAML structure against the query DSL schema.\n * See spec/models/query-dsl.md for the full specification.\n */\n\nimport { z } from 'zod';\nimport type { QueryAST } from './types.js';\n\n/**\n * Schema for field types.\n */\nexport const fieldTypeSchema = z.enum([\n 'title',\n 'abstract',\n 'title_abstract',\n 'author',\n 'keyword',\n 'all',\n]);\n\n/**\n * Schema for term block containing search terms.\n */\nexport const termBlockSchema = z.object({\n keywords: z.array(z.string()).min(1).optional(),\n mesh: z.array(z.string()).optional(),\n emtree: z.array(z.string()).optional(),\n eric: z.array(z.string()).optional(),\n exclude: z.array(z.string()).optional(),\n}).refine(\n (data) => data.keywords?.length || data.mesh?.length || data.emtree?.length || data.eric?.length,\n { message: 'At least one of keywords, mesh, emtree, or eric is required' }\n);\n\n/**\n * Schema for operator.\n */\nexport const operatorSchema = z.enum(['AND', 'OR']);\n\n/**\n * Schema for query block (with required id).\n */\nexport const queryBlockSchema = z.object({\n id: z.string().min(1),\n field: fieldTypeSchema,\n terms: termBlockSchema,\n operator: operatorSchema,\n});\n\n/**\n * Schema for publication type filter.\n */\nexport const publicationTypeFilterSchema = z.object({\n include: z.array(z.string()).optional(),\n exclude: z.array(z.string()).optional(),\n});\n\n/**\n * Schema for filters (YAML input format with snake_case).\n * Transforms to camelCase for internal use.\n */\nexport const filtersSchema = z\n .object({\n year_from: z.number().int().optional(),\n year_to: z.number().int().optional(),\n language: z.array(z.string()).optional(),\n publication_types: publicationTypeFilterSchema.optional(),\n categories: z.array(z.string()).optional(),\n source_types: z.array(z.string()).optional(),\n })\n .optional()\n .default({})\n .transform((data) => ({\n yearFrom: data.year_from,\n yearTo: data.year_to,\n languages: data.language,\n publicationTypes: data.publication_types,\n categories: data.categories,\n sourceTypes: data.source_types,\n }));\n\n/**\n * Provider names schema.\n */\nexport const providerNameSchema = z.enum([\n 'pubmed',\n 'scopus',\n 'eric',\n 'arxiv',\n 'wos',\n 'embase',\n]);\n\n/**\n * Schema for a block replacement (QueryBlock without id).\n */\nconst blockReplacementSchema = z.object({\n field: fieldTypeSchema,\n terms: termBlockSchema,\n operator: operatorSchema,\n});\n\n/**\n * Schema for partial filters in adds section (YAML snake_case → camelCase).\n */\nconst addsFiltersSchema = z\n .object({\n year_from: z.number().int().optional(),\n year_to: z.number().int().optional(),\n language: z.array(z.string()).optional(),\n publication_types: publicationTypeFilterSchema.optional(),\n categories: z.array(z.string()).optional(),\n source_types: z.array(z.string()).optional(),\n })\n .transform((data) => ({\n yearFrom: data.year_from,\n yearTo: data.year_to,\n languages: data.language,\n publicationTypes: data.publication_types,\n categories: data.categories,\n sourceTypes: data.source_types,\n }));\n\n/**\n * Schema for provider section with replaces and adds.\n */\nexport const providerSectionSchema = z.object({\n replaces: z.record(z.string(), blockReplacementSchema).optional(),\n adds: z.object({\n filters: addsFiltersSchema.optional(),\n }).optional(),\n});\n\n/**\n * Schema for providers object (partial record of provider -> section).\n */\nconst providersSchema = z\n .object({\n pubmed: providerSectionSchema.optional(),\n scopus: providerSectionSchema.optional(),\n eric: providerSectionSchema.optional(),\n arxiv: providerSectionSchema.optional(),\n wos: providerSectionSchema.optional(),\n embase: providerSectionSchema.optional(),\n })\n .optional()\n .default({});\n\n/**\n * Schema for the complete query file (YAML input format).\n * Transforms to QueryAST for internal use.\n */\nexport const queryFileSchema = z\n .object({\n name: z.string().min(1),\n description: z.string().optional(),\n query: z.array(queryBlockSchema).min(1),\n filters: filtersSchema,\n providers: providersSchema,\n })\n .refine(\n (data) => {\n // Cross-validation: replaces keys must reference existing block ids\n const blockIds = new Set(data.query.map((b) => b.id));\n for (const [, section] of Object.entries(data.providers ?? {})) {\n if (section?.replaces) {\n for (const key of Object.keys(section.replaces)) {\n if (!blockIds.has(key)) {\n return false;\n }\n }\n }\n }\n return true;\n },\n { message: 'replaces keys must reference existing block ids' }\n )\n .transform((data) => ({\n name: data.name,\n description: data.description,\n blocks: data.query,\n filters: data.filters,\n providers: data.providers,\n }));\n\n/**\n * Validate a parsed YAML object against the query schema.\n * Returns a validated QueryAST.\n *\n * @throws Error if the input contains the old `overrides` key (migration message provided)\n */\nexport function validateQueryFile(data: unknown): QueryAST {\n // Check for legacy `overrides` key before Zod parsing (which silently strips unknown keys)\n if (typeof data === 'object' && data !== null && 'overrides' in data) {\n throw new Error(\n 'The \"overrides\" key is no longer supported. ' +\n 'Migrate to the new \"providers\" format. See spec/models/query-dsl.md for details.'\n );\n }\n return queryFileSchema.parse(data);\n}\n\n/**\n * Validation error with path information.\n */\nexport class ValidationError extends Error {\n constructor(\n public readonly path: string,\n message: string\n ) {\n super(message);\n this.name = 'ValidationError';\n }\n}\n\n/**\n * Format Zod validation errors into an array of ValidationError objects.\n *\n * @param data - The data to validate\n * @returns Array of ValidationError objects (empty if valid)\n */\nexport function formatValidationErrors(data: unknown): ValidationError[] {\n // Check for legacy `overrides` key\n if (typeof data === 'object' && data !== null && 'overrides' in data) {\n return [\n new ValidationError(\n 'overrides',\n 'The \"overrides\" key is no longer supported. ' +\n 'Migrate to the new \"providers\" format. See spec/models/query-dsl.md for details.'\n ),\n ];\n }\n\n const result = queryFileSchema.safeParse(data);\n\n if (result.success) {\n return [];\n }\n\n return result.error.issues.map((issue) => {\n const path = issue.path.join('.');\n return new ValidationError(path, issue.message);\n });\n}\n"],"names":[],"mappings":"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"}
|