-
Notifications
You must be signed in to change notification settings - Fork 6.1k
Update numpy-documentation-search extension #27290
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
ebed897
b007011
75667f4
4b0e5b3
0825dab
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -1,6 +1,16 @@ | ||||||
| # NumPy Documentation Search Changelog | ||||||
|
|
||||||
| ## [1.2.3] - 2025-10-09 | ||||||
| ## [1.3.0] - {PR_MERGE_DATE} | ||||||
|
|
||||||
| ### Added | ||||||
| - Add guided recovery when live access to `numpy.org` fails, including in-app setup steps for downloaded local docs | ||||||
| - Add configurable documentation source preferences for auto and local directory modes | ||||||
|
|
||||||
| ### Changed | ||||||
| - Fall back to local documentation when remote inventory loading fails | ||||||
| - Load inline documentation previews from a configured local docs directory when network access is unavailable | ||||||
|
|
||||||
| ## [1.2.3] - {PR_MERGE_DATE} | ||||||
|
0xdhrv marked this conversation as resolved.
Outdated
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The
Suggested change
Prompt To Fix With AIThis is a comment left during a code review.
Path: extensions/numpy-documentation-search/CHANGELOG.md
Line: 13
Comment:
**Previously-released entry date overwritten with placeholder**
The `[1.2.3]` entry already had a real merge date (`2025-10-09`) from a prior PR. Changing it to `{PR_MERGE_DATE}` will cause the release tooling to stamp it with this PR's merge date, permanently erasing the historical date.
```suggestion
## [1.2.3] - 2025-10-09
```
How can I resolve this? If you propose a fix, please make it concise. |
||||||
|
|
||||||
| ### Changed | ||||||
| - Refresh README to focus on a concise Raycast user overview with key in-app features | ||||||
|
|
||||||
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,7 +1,7 @@ | ||
| { | ||
| "$schema": "https://www.raycast.com/schemas/extension.json", | ||
| "name": "numpy-documentation-search", | ||
| "title": "NumPy Documentation Search", | ||
| "title": "Numpy Documentation Search", | ||
|
||
| "description": "Quickly search through official NumPy documentation", | ||
| "icon": "extension-icon.png", | ||
| "author": "FariaF22", | ||
|
|
@@ -18,13 +18,38 @@ | |
| "commands": [ | ||
| { | ||
| "name": "numpy-docs", | ||
| "title": "NumPy Docs", | ||
| "title": "Numpy Docs", | ||
| "subtitle": "Search through Numpy documentation", | ||
|
Comment on lines
+21
to
22
|
||
| "description": "Search NumPy's API reference and preview documentation inside Raycast.", | ||
| "mode": "view" | ||
| } | ||
| ], | ||
| "preferences": [ | ||
| { | ||
| "name": "documentationSourceMode", | ||
| "type": "dropdown", | ||
| "required": true, | ||
| "title": "Documentation Source", | ||
| "description": "Choose where the extension should load NumPy documentation from", | ||
| "default": "online", | ||
| "data": [ | ||
| { | ||
| "title": "Online", | ||
| "value": "online" | ||
| }, | ||
| { | ||
| "title": "Local Docs Directory", | ||
| "value": "local" | ||
| } | ||
| ] | ||
| }, | ||
| { | ||
| "name": "localDocsDirectory", | ||
| "type": "directory", | ||
| "required": false, | ||
| "title": "Local Docs Directory", | ||
| "description": "Only used when Documentation Source is Local Docs Directory. Select the downloaded NumPy docs folder and the extension will load files from its stable subfolder" | ||
| }, | ||
| { | ||
| "name": "useShortPrefix", | ||
| "type": "checkbox", | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,110 @@ | ||||||
| import { mkdtempSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs"; | ||||||
| import { tmpdir } from "node:os"; | ||||||
| import path from "node:path"; | ||||||
| import { deflateSync } from "node:zlib"; | ||||||
| import { afterEach, describe, expect, it, vi } from "vitest"; | ||||||
| import { loadDocDetail, loadInventory } from "../lib/docs-source"; | ||||||
| import type { InventoryItem } from "../lib/inventory"; | ||||||
|
|
||||||
| const linspaceItem: InventoryItem = { | ||||||
| id: "numpy.linspace", | ||||||
| name: "numpy.linspace", | ||||||
| shortName: "linspace", | ||||||
| role: "py:function", | ||||||
| url: "https://numpy.org/doc/stable/reference/generated/numpy.linspace.html", | ||||||
| docPath: "reference/generated/numpy.linspace.html#numpy.linspace", | ||||||
| displayName: "numpy.linspace", | ||||||
| }; | ||||||
|
|
||||||
| const tempDirs: string[] = []; | ||||||
|
|
||||||
| afterEach(() => { | ||||||
| for (const dir of tempDirs) { | ||||||
| rmSync(dir, { force: true, recursive: true }); | ||||||
| } | ||||||
| tempDirs.length = 0; | ||||||
| }); | ||||||
|
|
||||||
| describe("loadInventory", () => { | ||||||
| it("falls back to local docs in online mode when remote loading fails", async () => { | ||||||
| const localDocsDirectory = createLocalDocsDirectory(); | ||||||
| const stableDir = path.join(localDocsDirectory, "stable"); | ||||||
| mkdirSync(stableDir, { recursive: true }); | ||||||
| writeFileSync(path.join(stableDir, "objects.inv"), buildInventoryFixture()); | ||||||
|
|
||||||
| const result = await loadInventory( | ||||||
| { | ||||||
| localDocsDirectory, | ||||||
| mode: "online", | ||||||
| }, | ||||||
| { | ||||||
| fetchImpl: vi.fn(async () => { | ||||||
| throw new Error("certificate failure"); | ||||||
| }) as typeof fetch, | ||||||
| readBinaryFileImpl: async (filePath) => readFileSync(filePath), | ||||||
| readTextFileImpl: async (filePath) => readFileSync(filePath, "utf8"), | ||||||
| }, | ||||||
| ); | ||||||
|
|
||||||
| expect(result.source).toBe("local"); | ||||||
| expect(result.remoteError?.message).toBe("certificate failure"); | ||||||
| expect(result.data.some((item) => item.id === "numpy.linspace")).toBe(true); | ||||||
| }); | ||||||
|
|
||||||
| it("surfaces the remote error when online mode has no local docs fallback", async () => { | ||||||
| await expect( | ||||||
| loadInventory( | ||||||
| { | ||||||
| mode: "online", | ||||||
| }, | ||||||
| { | ||||||
| fetchImpl: vi.fn(async () => { | ||||||
| throw new Error("certificate failure"); | ||||||
| }) as typeof fetch, | ||||||
| readBinaryFileImpl: async (filePath) => readFileSync(filePath), | ||||||
| readTextFileImpl: async (filePath) => readFileSync(filePath, "utf8"), | ||||||
| }, | ||||||
| ), | ||||||
| ).rejects.toThrow("certificate failure"); | ||||||
| }); | ||||||
| }); | ||||||
|
|
||||||
| describe("loadDocDetail", () => { | ||||||
| it("loads documentation detail from a local docs directory", async () => { | ||||||
| const localDocsDirectory = createLocalDocsDirectory(); | ||||||
| const referenceDir = path.join(localDocsDirectory, "stable/reference/generated"); | ||||||
| mkdirSync(referenceDir, { recursive: true }); | ||||||
| writeFileSync( | ||||||
| path.join(referenceDir, "numpy.linspace.html"), | ||||||
| readFileSync(path.join(process.cwd(), "src/__tests__/fixtures/numpy.linspace.html"), "utf8"), | ||||||
|
||||||
| readFileSync(path.join(process.cwd(), "src/__tests__/fixtures/numpy.linspace.html"), "utf8"), | |
| readFileSync(new URL("./fixtures/numpy.linspace.html", import.meta.url), "utf8"), |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,27 +1,94 @@ | ||
| import { useFetch } from "@raycast/utils"; | ||
| import { useCallback, useEffect, useState } from "react"; | ||
| import { loadDocDetail, type DocumentationSourceMode, type ResolvedDocumentationSource } from "../lib/docs-source"; | ||
| import type { DocDetail } from "../lib/doc-detail"; | ||
| import type { InventoryItem } from "../lib/inventory"; | ||
| import { parseDocDetail, type DocDetail } from "../lib/doc-detail"; | ||
|
|
||
| interface UseDocDetailResult { | ||
| data?: DocDetail; | ||
| isLoading: boolean; | ||
| error?: Error; | ||
| revalidate: () => void; | ||
| source?: ResolvedDocumentationSource; | ||
| } | ||
|
|
||
| export function useDocDetail(item: InventoryItem | undefined): UseDocDetailResult { | ||
| const { data, isLoading, error, revalidate } = useFetch<DocDetail>(item?.url ?? "", { | ||
| execute: Boolean(item), | ||
| keepPreviousData: true, | ||
| parseResponse: async (response) => { | ||
| if (!response.ok) { | ||
| throw new Error(`Failed to load documentation: ${response.status} ${response.statusText}`); | ||
| } | ||
|
|
||
| const html = await response.text(); | ||
| return parseDocDetail(html, item!); | ||
| }, | ||
| interface UseDocDetailOptions { | ||
| inventorySource?: ResolvedDocumentationSource; | ||
| item: InventoryItem | undefined; | ||
| localDocsDirectory?: string; | ||
| mode: DocumentationSourceMode; | ||
| } | ||
|
|
||
| export function useDocDetail(options: UseDocDetailOptions): UseDocDetailResult { | ||
| const [reloadToken, setReloadToken] = useState(0); | ||
|
|
||
| const revalidate = useCallback(() => { | ||
| setReloadToken((token) => token + 1); | ||
| }, []); | ||
|
|
||
| const [state, setState] = useState<UseDocDetailResult>({ | ||
| isLoading: false, | ||
| revalidate, | ||
| }); | ||
|
|
||
| return { data, isLoading, error, revalidate }; | ||
| useEffect(() => { | ||
| let cancelled = false; | ||
|
|
||
| if (!options.item || !options.inventorySource) { | ||
| setState({ | ||
| data: undefined, | ||
| error: undefined, | ||
| isLoading: false, | ||
| revalidate, | ||
| source: undefined, | ||
| }); | ||
| return () => { | ||
| cancelled = true; | ||
| }; | ||
| } | ||
|
|
||
| setState((current) => ({ | ||
| ...current, | ||
| error: undefined, | ||
| isLoading: true, | ||
| revalidate, | ||
| })); | ||
|
|
||
| void loadDocDetail({ | ||
| inventorySource: options.inventorySource, | ||
| item: options.item, | ||
| localDocsDirectory: options.localDocsDirectory, | ||
| mode: options.mode, | ||
| }) | ||
| .then((result) => { | ||
| if (cancelled) { | ||
| return; | ||
| } | ||
|
|
||
| setState({ | ||
| data: result.data, | ||
| error: undefined, | ||
| isLoading: false, | ||
| revalidate, | ||
| source: result.source, | ||
| }); | ||
| }) | ||
| .catch((error: unknown) => { | ||
| if (cancelled) { | ||
| return; | ||
| } | ||
|
|
||
| setState((current) => ({ | ||
| ...current, | ||
| error: error instanceof Error ? error : new Error(String(error)), | ||
| isLoading: false, | ||
| revalidate, | ||
| })); | ||
| }); | ||
|
|
||
| return () => { | ||
| cancelled = true; | ||
| }; | ||
| }, [options.inventorySource, options.item, options.localDocsDirectory, options.mode, reloadToken, revalidate]); | ||
|
|
||
| return state; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The changelog now includes
{PR_MERGE_DATE}placeholders (and replaces the previously concrete date for 1.2.3). If the repository expects released versions to have real dates, these placeholders should be replaced with actual dates before merge/release so the changelog remains accurate and user-facing.