summaryrefslogtreecommitdiffhomepage
path: root/packages/tool-web-search/src/validate.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/tool-web-search/src/validate.ts')
-rw-r--r--packages/tool-web-search/src/validate.ts304
1 files changed, 152 insertions, 152 deletions
diff --git a/packages/tool-web-search/src/validate.ts b/packages/tool-web-search/src/validate.ts
index 56bd356..019fd5a 100644
--- a/packages/tool-web-search/src/validate.ts
+++ b/packages/tool-web-search/src/validate.ts
@@ -17,32 +17,32 @@ export const CRAWL_DEFAULT_LIMIT = 3;
export const MAX_LIMIT = 10;
interface BaseArgs {
- readonly format: Format;
+ readonly format: Format;
}
export interface SearchArgs extends BaseArgs {
- readonly mode: "search";
- readonly query: string;
- readonly limit: number;
- readonly scrape: boolean;
- readonly lang?: string;
- readonly country?: string;
+ readonly mode: "search";
+ readonly query: string;
+ readonly limit: number;
+ readonly scrape: boolean;
+ readonly lang?: string;
+ readonly country?: string;
}
export interface ScrapeArgs extends BaseArgs {
- readonly mode: "scrape";
- readonly url: string;
+ readonly mode: "scrape";
+ readonly url: string;
}
export interface CrawlArgs extends BaseArgs {
- readonly mode: "crawl";
- readonly url: string;
- readonly limit: number;
+ readonly mode: "crawl";
+ readonly url: string;
+ readonly limit: number;
}
export interface MapArgs extends BaseArgs {
- readonly mode: "map";
- readonly url: string;
+ readonly mode: "map";
+ readonly url: string;
}
export type ValidatedArgs = SearchArgs | ScrapeArgs | CrawlArgs | MapArgs;
@@ -52,60 +52,60 @@ export type ValidationError = { readonly error: string };
type Result<T> = { readonly value: T } | ValidationError;
function resolveFormat(raw: unknown): Result<Format> {
- if (raw === undefined || raw === null) {
- return { value: "markdown" };
- }
- if (typeof raw === "string" && (FORMATS as readonly string[]).includes(raw)) {
- return { value: raw as Format };
- }
- return {
- error: `Error: Invalid format "${String(raw)}" (must be one of: markdown, text, html).`,
- };
+ if (raw === undefined || raw === null) {
+ return { value: "markdown" };
+ }
+ if (typeof raw === "string" && (FORMATS as readonly string[]).includes(raw)) {
+ return { value: raw as Format };
+ }
+ return {
+ error: `Error: Invalid format "${String(raw)}" (must be one of: markdown, text, html).`,
+ };
}
function resolveMode(raw: unknown, query: unknown, url: unknown): Result<Mode> {
- if (raw === undefined || raw === null) {
- const hasQuery = typeof query === "string" && query.trim().length > 0;
- const hasUrl = typeof url === "string" && url.trim().length > 0;
- return { value: hasQuery ? "search" : hasUrl ? "scrape" : "search" };
- }
- if (typeof raw === "string" && (MODES as readonly string[]).includes(raw)) {
- return { value: raw as Mode };
- }
- return {
- error: `Error: Invalid mode "${String(raw)}" (must be one of: search, scrape, crawl, map).`,
- };
+ if (raw === undefined || raw === null) {
+ const hasQuery = typeof query === "string" && query.trim().length > 0;
+ const hasUrl = typeof url === "string" && url.trim().length > 0;
+ return { value: hasQuery ? "search" : hasUrl ? "scrape" : "search" };
+ }
+ if (typeof raw === "string" && (MODES as readonly string[]).includes(raw)) {
+ return { value: raw as Mode };
+ }
+ return {
+ error: `Error: Invalid mode "${String(raw)}" (must be one of: search, scrape, crawl, map).`,
+ };
}
function optionalString(raw: unknown, name: string): Result<string | undefined> {
- if (raw === undefined || raw === null) {
- return { value: undefined };
- }
- if (typeof raw === "string") {
- return { value: raw };
- }
- return { error: `Error: "${name}" must be a string.` };
+ if (raw === undefined || raw === null) {
+ return { value: undefined };
+ }
+ if (typeof raw === "string") {
+ return { value: raw };
+ }
+ return { error: `Error: "${name}" must be a string.` };
}
function resolveLimit(raw: unknown, defaultLimit: number): Result<number> {
- if (raw === undefined || raw === null) {
- return { value: defaultLimit };
- }
- const n = Number(raw);
- if (!Number.isFinite(n) || n < 1) {
- return { error: 'Error: "limit" must be a positive number.' };
- }
- return { value: Math.min(Math.floor(n), MAX_LIMIT) };
+ if (raw === undefined || raw === null) {
+ return { value: defaultLimit };
+ }
+ const n = Number(raw);
+ if (!Number.isFinite(n) || n < 1) {
+ return { error: 'Error: "limit" must be a positive number.' };
+ }
+ return { value: Math.min(Math.floor(n), MAX_LIMIT) };
}
function resolveBoolean(raw: unknown, name: string): Result<boolean> {
- if (raw === undefined || raw === null) {
- return { value: false };
- }
- if (typeof raw === "boolean") {
- return { value: raw };
- }
- return { error: `Error: "${name}" must be a boolean.` };
+ if (raw === undefined || raw === null) {
+ return { value: false };
+ }
+ if (typeof raw === "boolean") {
+ return { value: raw };
+ }
+ return { error: `Error: "${name}" must be a boolean.` };
}
/**
@@ -113,100 +113,100 @@ function resolveBoolean(raw: unknown, name: string): Result<boolean> {
* Returns `{ error }` for invalid input — the tool surfaces it verbatim.
*/
export function validateArgs(args: unknown): ValidatedArgs | ValidationError {
- if (args === null || args === undefined || typeof args !== "object") {
- return { error: "Error: Arguments must be an object." };
- }
- const obj = args as Record<string, unknown>;
-
- const format = resolveFormat(obj.format);
- if ("error" in format) {
- return format;
- }
-
- const mode = resolveMode(obj.mode, obj.query, obj.url);
- if ("error" in mode) {
- return mode;
- }
-
- const query = optionalString(obj.query, "query");
- if ("error" in query) {
- return query;
- }
-
- const url = optionalString(obj.url, "url");
- if ("error" in url) {
- return url;
- }
-
- switch (mode.value) {
- case "search": {
- if (query.value === undefined || query.value.trim().length === 0) {
- return { error: "Error: query is required for search mode." };
- }
- const limit = resolveLimit(obj.limit, SEARCH_DEFAULT_LIMIT);
- if ("error" in limit) {
- return limit;
- }
- const scrape = resolveBoolean(obj.scrape, "scrape");
- if ("error" in scrape) {
- return scrape;
- }
- const lang = optionalString(obj.lang, "lang");
- if ("error" in lang) {
- return lang;
- }
- const country = optionalString(obj.country, "country");
- if ("error" in country) {
- return country;
- }
- const result: SearchArgs = {
- mode: "search",
- query: query.value,
- limit: limit.value,
- scrape: scrape.value,
- format: format.value,
- ...(lang.value !== undefined ? { lang: lang.value } : {}),
- ...(country.value !== undefined ? { country: country.value } : {}),
- };
- return result;
- }
- case "scrape": {
- if (url.value === undefined || url.value.trim().length === 0) {
- return { error: "Error: url is required for scrape mode." };
- }
- const result: ScrapeArgs = {
- mode: "scrape",
- url: url.value,
- format: format.value,
- };
- return result;
- }
- case "crawl": {
- if (url.value === undefined || url.value.trim().length === 0) {
- return { error: "Error: url is required for crawl mode." };
- }
- const limit = resolveLimit(obj.limit, CRAWL_DEFAULT_LIMIT);
- if ("error" in limit) {
- return limit;
- }
- const result: CrawlArgs = {
- mode: "crawl",
- url: url.value,
- limit: limit.value,
- format: format.value,
- };
- return result;
- }
- case "map": {
- if (url.value === undefined || url.value.trim().length === 0) {
- return { error: "Error: url is required for map mode." };
- }
- const result: MapArgs = {
- mode: "map",
- url: url.value,
- format: format.value,
- };
- return result;
- }
- }
+ if (args === null || args === undefined || typeof args !== "object") {
+ return { error: "Error: Arguments must be an object." };
+ }
+ const obj = args as Record<string, unknown>;
+
+ const format = resolveFormat(obj.format);
+ if ("error" in format) {
+ return format;
+ }
+
+ const mode = resolveMode(obj.mode, obj.query, obj.url);
+ if ("error" in mode) {
+ return mode;
+ }
+
+ const query = optionalString(obj.query, "query");
+ if ("error" in query) {
+ return query;
+ }
+
+ const url = optionalString(obj.url, "url");
+ if ("error" in url) {
+ return url;
+ }
+
+ switch (mode.value) {
+ case "search": {
+ if (query.value === undefined || query.value.trim().length === 0) {
+ return { error: "Error: query is required for search mode." };
+ }
+ const limit = resolveLimit(obj.limit, SEARCH_DEFAULT_LIMIT);
+ if ("error" in limit) {
+ return limit;
+ }
+ const scrape = resolveBoolean(obj.scrape, "scrape");
+ if ("error" in scrape) {
+ return scrape;
+ }
+ const lang = optionalString(obj.lang, "lang");
+ if ("error" in lang) {
+ return lang;
+ }
+ const country = optionalString(obj.country, "country");
+ if ("error" in country) {
+ return country;
+ }
+ const result: SearchArgs = {
+ mode: "search",
+ query: query.value,
+ limit: limit.value,
+ scrape: scrape.value,
+ format: format.value,
+ ...(lang.value !== undefined ? { lang: lang.value } : {}),
+ ...(country.value !== undefined ? { country: country.value } : {}),
+ };
+ return result;
+ }
+ case "scrape": {
+ if (url.value === undefined || url.value.trim().length === 0) {
+ return { error: "Error: url is required for scrape mode." };
+ }
+ const result: ScrapeArgs = {
+ mode: "scrape",
+ url: url.value,
+ format: format.value,
+ };
+ return result;
+ }
+ case "crawl": {
+ if (url.value === undefined || url.value.trim().length === 0) {
+ return { error: "Error: url is required for crawl mode." };
+ }
+ const limit = resolveLimit(obj.limit, CRAWL_DEFAULT_LIMIT);
+ if ("error" in limit) {
+ return limit;
+ }
+ const result: CrawlArgs = {
+ mode: "crawl",
+ url: url.value,
+ limit: limit.value,
+ format: format.value,
+ };
+ return result;
+ }
+ case "map": {
+ if (url.value === undefined || url.value.trim().length === 0) {
+ return { error: "Error: url is required for map mode." };
+ }
+ const result: MapArgs = {
+ mode: "map",
+ url: url.value,
+ format: format.value,
+ };
+ return result;
+ }
+ }
}