diff --git a/packages/google-sr/src/constants.ts b/packages/google-sr/src/constants.ts index 824d2ba..f7f3c5c 100644 --- a/packages/google-sr/src/constants.ts +++ b/packages/google-sr/src/constants.ts @@ -77,47 +77,72 @@ export interface SearchOptions< N extends boolean = false, > { /** - * Search query + * The search query string to send to Google. */ query: string; + /** - * Control the type of results returned (can have a significant performance impact) + * Array of result parsers that determine which types of results to extract. + * + * Each parser processes the HTML response and extracts specific result types. + * Using fewer parsers can improve performance. + * + * @default [OrganicResult] - Only organic results are parsed if not specified */ parsers?: R[]; /** - * When true, excludes results that have undefined or empty properties. + * Whether to exclude results with missing or undefined properties. * @default false - Partial results are included. */ noPartialResults?: N; /** - * Custom request configuration to be sent with the request + * Custom HTTP request configuration for the search request. + * + * Accepts all standard Fetch API options (headers, method, signal, etc.) + * plus additional google-sr specific properties. + * + * @example + * ```ts + * requestConfig: { + * signal: abortController.signal, + * queryParams: { tbm: 'nws' }, // this is provided by google-sr + * } + * ``` */ requestConfig?: RequestOptions; } /** - * Search options for multiple pages search + * Configuration options for multi-page search. */ export interface SearchOptionsWithPages< R extends ResultParser = ResultParser, N extends boolean = false, > extends SearchOptions { /** - * Total number of pages to search or an array of specific pages to search + * Specifies which pages to search. * - * google search uses cursor-based pagination. + * - **Number**: Total pages to search starting from page 1 + * - **Array**: Specific page offsets to search (0 = page 1, 10 = page 2, etc.) * - * Specific page numbers are incremented by 10 starting from 0 (page 1) + * Google uses cursor-based pagination with increments of 10. * - * If total number of pages is provided, cursor will be created according to: start = page * 10 + * @example + * ```ts + * pages: 3 // Searches pages 1, 2, 3 (offsets: 0, 10, 20) + * pages: [0, 20] // Searches pages 1 and 3 (offsets: 0, 20) + * ``` */ pages: number | number[]; /** - * Delay between each request in milliseconds. helps to avoid rate limiting issues. + * Delay between requests in milliseconds. + * + * Helps prevent rate limiting by spacing out requests. + * Set to 0 to disable delays (not recommended for production). * - * Default is 1000 ms (1 second). set to 0 to disable delay. + * @default 1000 - 1 second delay between requests */ delay?: number; } diff --git a/packages/google-sr/src/index.ts b/packages/google-sr/src/index.ts index 55f2618..375f24e 100644 --- a/packages/google-sr/src/index.ts +++ b/packages/google-sr/src/index.ts @@ -2,4 +2,9 @@ export * from "./constants.js"; export * from "./results/index.js"; export * from "./search.js"; -export type { SearchResultTypeFromParser } from "./utils.js"; +// export some of the utility functions for ease of use +export type { + ParserResultType, + PartialExceptType, + SearchResultTypeFromParser, +} from "./utils.js"; diff --git a/packages/google-sr/src/results/conversion.ts b/packages/google-sr/src/results/conversion.ts index caaed8f..f84e4fe 100644 --- a/packages/google-sr/src/results/conversion.ts +++ b/packages/google-sr/src/results/conversion.ts @@ -14,7 +14,22 @@ export interface UnitConversionResultNode extends SearchResultNodeLike { /** * Parses unit conversion search results. - * @returns Array of UnitConversionResultNode + * + * @example + * ```ts + * import { UnitConversionResult, search } from 'google-sr'; + * + * const results = await search({ + * query: '100 USD to EUR', + * parsers: [UnitConversionResult], + * }); + * ``` + * + * @param $ - The CheerioAPI instance + * @param noPartialResults - Whether to exclude results with missing properties + * @returns + * - If noPartialResults is true: {@link UnitConversionResultNode} object or null + * - If noPartialResults is false: {@link PartialExceptType}<{@link UnitConversionResultNode}> object or null */ export const UnitConversionResult: ResultParser = ( $, diff --git a/packages/google-sr/src/results/dictionary.ts b/packages/google-sr/src/results/dictionary.ts index 8e066b2..f77506b 100644 --- a/packages/google-sr/src/results/dictionary.ts +++ b/packages/google-sr/src/results/dictionary.ts @@ -56,7 +56,22 @@ const parseDefinitionBlock = ( /** * Parses dictionary search results. - * @returns Array of DictionaryResultNode + * + * @example + * ```ts + * import { DictionaryResult, search } from 'google-sr'; + * + * const results = await search({ + * query: 'define serendipity', + * parsers: [DictionaryResult], + * }); + * ``` + * + * @param $ - The CheerioAPI instance + * @param noPartialResults - Whether to exclude results with missing properties + * @returns + * - If noPartialResults is true: {@link DictionaryResultNode} object or null + * - If noPartialResults is false: {@link PartialExceptType}<{@link DictionaryResultNode}> object or null */ export const DictionaryResult: ResultParser = ( $, diff --git a/packages/google-sr/src/results/knowledge-panel.ts b/packages/google-sr/src/results/knowledge-panel.ts index 88602cb..e25a35b 100644 --- a/packages/google-sr/src/results/knowledge-panel.ts +++ b/packages/google-sr/src/results/knowledge-panel.ts @@ -27,9 +27,23 @@ export interface KnowledgePanelResultNode extends SearchResultNodeLike { /** * Parses knowledge panel search results. - * @param $ - * @param noPartialResults - * @returns KnowledgePanelResultNode + * Knowledge panels appear for well-known entities like people, places, and organizations. + * + * @example + * ```ts + * import { KnowledgePanelResult, search } from 'google-sr'; + * + * const results = await search({ + * query: 'Albert Einstein', + * parsers: [KnowledgePanelResult], + * }); + * ``` + * + * @param $ - The CheerioAPI instance + * @param noPartialResults - Whether to exclude results with missing properties + * @returns + * - If noPartialResults is true: {@link KnowledgePanelResultNode} object or null + * - If noPartialResults is false: {@link PartialExceptType}<{@link KnowledgePanelResultNode}> object or null */ export const KnowledgePanelResult: ResultParser = ( $, diff --git a/packages/google-sr/src/results/news.ts b/packages/google-sr/src/results/news.ts index b182ffa..fb1d9ad 100644 --- a/packages/google-sr/src/results/news.ts +++ b/packages/google-sr/src/results/news.ts @@ -23,7 +23,7 @@ export interface NewsResultNode extends SearchResultNodeLike { /** * Parses results from the dedicated News tab in Google Search. * - * To use this selector, set the `tbm` query parameter to `'nws'` in the request configuration. + * To use this parser, set the `tbm` query parameter to `'nws'` in the request configuration. * * **NOTE: This parser is not compatible with the other parsers and vice versa.** * @@ -42,7 +42,12 @@ export interface NewsResultNode extends SearchResultNodeLike { * }); * ``` * - * @returns Array of {@link NewsResultNode} objects + * @param $ - The CheerioAPI instance + * @param noPartialResults - Whether to exclude results with missing properties + * @returns + * - If noPartialResults is true: Array of {@link NewsResultNode} objects + * - If noPartialResults is false: Array of {@link PartialExceptType}<{@link NewsResultNode}> objects + * - If no results are found: returns an empty array */ export const NewsResult: ResultParser = ( $, diff --git a/packages/google-sr/src/results/organic.ts b/packages/google-sr/src/results/organic.ts index e6de132..1d99820 100644 --- a/packages/google-sr/src/results/organic.ts +++ b/packages/google-sr/src/results/organic.ts @@ -28,15 +28,19 @@ export interface OrganicResultNode extends SearchResultNodeLike { * @example * ```ts * import { OrganicResult, search } from 'google-sr'; + * * const results = await search({ * query: 'google-sr npm package', * parsers: [OrganicResult], * }); * ``` * + * @param $ - The CheerioAPI instance + * @param noPartialResults - Whether to exclude results with missing properties * @returns - * - Array of {@link OrganicResultNode} objects - * - If noPartialResult is true, Array of {@link PartialExceptType}<{@link OrganicResultNode}> objects + * - If noPartialResults is true: Array of {@link OrganicResultNode} objects + * - If noPartialResults is false: Array of {@link PartialExceptType}<{@link OrganicResultNode}> objects + * - If no results are found: returns an empty array */ export const OrganicResult: ResultParser = ( $, diff --git a/packages/google-sr/src/results/related-searches.ts b/packages/google-sr/src/results/related-searches.ts index 5ab888a..6da60d4 100644 --- a/packages/google-sr/src/results/related-searches.ts +++ b/packages/google-sr/src/results/related-searches.ts @@ -18,11 +18,12 @@ export interface RelatedSearchesResultNode extends SearchResultNodeLike { /** * Parses related search queries that appear at the bottom of Google search results. * This parser extracts the "Related searches" or similar related query suggestions - * that Google displays to help users refine their search. + * that Google displays to help users find similar or relevant topics. * * @example * ```ts * import { RelatedSearchesResult, search } from 'google-sr'; + * * const results = await search({ * query: 'nodejs frameworks', * parsers: [RelatedSearchesResult], @@ -30,9 +31,11 @@ export interface RelatedSearchesResultNode extends SearchResultNodeLike { * // results[0].queries might contain: ["express.js", "react.js", ...] * ``` * + * @param $ - The CheerioAPI instance + * @param noPartialResults - Whether to exclude results with missing properties * @returns - * - If noPartialResults is true, {@link RelatedSearchesResultNode} object - * - If noPartialResults is false, {@link PartialExceptType}<{@link RelatedSearchesResultNode}> object + * - If noPartialResults is true: {@link RelatedSearchesResultNode} object or null + * - If noPartialResults is false: {@link PartialExceptType}<{@link RelatedSearchesResultNode}> object or null */ export const RelatedSearchesResult: ResultParser = ( $, diff --git a/packages/google-sr/src/results/time.ts b/packages/google-sr/src/results/time.ts index 4df4f6c..734e90d 100644 --- a/packages/google-sr/src/results/time.ts +++ b/packages/google-sr/src/results/time.ts @@ -16,7 +16,22 @@ export interface TimeResultNode extends SearchResultNodeLike { /** * Parses time search results. - * @returns Array of TimeResultNode + * + * @example + * ```ts + * import { TimeResult, search } from 'google-sr'; + * + * const results = await search({ + * query: 'time in new york', + * parsers: [TimeResult], + * }); + * ``` + * + * @param $ - The CheerioAPI instance + * @param noPartialResults - Whether to exclude results with missing properties + * @returns + * - If noPartialResults is true: {@link TimeResultNode} object or null + * - If noPartialResults is false: {@link PartialExceptType}<{@link TimeResultNode}> object or null */ export const TimeResult: ResultParser = ( $, diff --git a/packages/google-sr/src/results/translate.ts b/packages/google-sr/src/results/translate.ts index 692e864..c3f2698 100644 --- a/packages/google-sr/src/results/translate.ts +++ b/packages/google-sr/src/results/translate.ts @@ -17,7 +17,22 @@ export interface TranslateResultNode extends SearchResultNodeLike { /** * Parses translation search results. - * @returns Array of TranslateSearchResultNodes + * + * @example + * ```ts + * import { TranslateResult, search } from 'google-sr'; + * + * const results = await search({ + * query: 'translate hello to spanish', + * parsers: [TranslateResult], + * }); + * ``` + * + * @param $ - The CheerioAPI instance + * @param noPartialResults - Whether to exclude results with missing properties + * @returns + * - If noPartialResults is true: {@link TranslateResultNode} object or null + * - If noPartialResults is false: {@link PartialExceptType}<{@link TranslateResultNode}> object or null */ export const TranslateResult: ResultParser = ( $, diff --git a/packages/google-sr/src/search.ts b/packages/google-sr/src/search.ts index 9a7de9c..73a8442 100644 --- a/packages/google-sr/src/search.ts +++ b/packages/google-sr/src/search.ts @@ -11,6 +11,28 @@ import { safeGetFetch, } from "./utils.js"; +/** + * Performs a Google search and returns parsed results from a single page. + * + * This is the main search function for single-page searches. It accepts various parsers + * to extract different types of results (organic results, news, translations, etc.). + * + * @example + * ```ts + * import { search, OrganicResult } from 'google-sr'; + * + * const results = await search({ + * query: 'nodejs tutorial', + * // Configure the parsers you want + * parsers: [OrganicResult], + * noPartialResults: true + * }); + * ``` + * + * @param searchOptions - Configuration options for the search + * @returns Promise that resolves to an array of parsed search results + * @throws {TypeError} When searchOptions is not provided or is invalid + */ export async function search( searchOptions: SearchOptions, ): Promise[]> { @@ -41,6 +63,37 @@ export async function search( return searchResults; } +/** + * Performs a Google search across multiple pages and returns parsed results. + * + * This function efficiently searches multiple pages by reusing the same parsers + * and request configuration. Results are returned as a 2D array where each + * sub-array contains results from one page. + * + * @example + * ```ts + * import { searchWithPages, OrganicResult } from 'google-sr'; + * + * // Search first 3 pages + * const results = await searchWithPages({ + * query: 'machine learning', + * parsers: [OrganicResult], + * pages: 3, // Will search pages 0, 10, 20 + * delay: 1000 // 1 second delay between requests + * }); + * + * // Search specific pages + * const specificResults = await searchWithPages({ + * query: 'react hooks', + * parsers: [OrganicResult], + * pages: [0, 20, 40], // Search pages 1, 3, and 5 + * }); + * ``` + * + * @param options - Configuration options for the multi-page search + * @returns Promise that resolves to a 2D array where each sub-array contains results from one page + * @throws {TypeError} When options is not provided or pages parameter is invalid + */ export async function searchWithPages< R extends ResultParser = typeof OrganicResult, N extends boolean = false, diff --git a/packages/google-sr/src/utils.ts b/packages/google-sr/src/utils.ts index 6ce6f18..c518b07 100644 --- a/packages/google-sr/src/utils.ts +++ b/packages/google-sr/src/utils.ts @@ -20,11 +20,13 @@ const baseHeaders = { }; /** - * @private - * Fetches a URL with the provided options, handling errors and returning the response. - * @param url The URL to fetch - * @param options The request options - * @returns The response from the fetch call + * Performs a safe HTTP GET request with error handling. + * + * @internal + * @param options - Request configuration options + * @returns Promise that resolves to the HTTP response + * @throws {TypeError} When URL is missing from options + * @throws {Error} When the HTTP response is not successful (non-2xx status) */ export async function safeGetFetch(options: RequestOptions): Promise { options.method = "GET"; // Ensure the method is GET @@ -46,10 +48,18 @@ export async function safeGetFetch(options: RequestOptions): Promise { } /** - * Extract the actual webpage link from a href tag result - * @param googleLink - * @returns - * @private + * Extracts the actual destination URL from a Google search result link. + * + * @internal + * @param googleLink - The Google redirect URL from a search result + * @returns The actual destination URL, or null if extraction fails + * + * @example + * ```ts + * const googleLink = "/url?q=https%3A//example.com&sa=U&ved=..."; + * const actualUrl = extractUrlFromGoogleLink(googleLink); + * // Returns: "https://example.com" + * ``` */ export function extractUrlFromGoogleLink(googleLink?: string): string | null { if (!googleLink) return null; @@ -121,9 +131,9 @@ export function throwNoCheerioError( /** * Coerces a value into a string or undefined. * If the value is empty or null, returns undefined. - * @private - * @param value - The value to coerce. - * @returns A string if the value is valid, otherwise undefined. + * @internal + * @param value - The value to coerce + * @returns String if value is a non-empty string, undefined otherwise */ export function coerceToStringOrUndefined(value: unknown): string | undefined { if (typeof value !== "string") return undefined; @@ -148,7 +158,7 @@ export type ParserResultType = AsArrayElement< /** * Internal utility type to create a partial type from a result type * It will make all properties optional except the 'type' property - * @private + * @internal */ export type PartialExceptType = Pick & Omit, "type">;