Conversation
* Introduced `launch.json` for debugging configuration. * Added `tasks.json` to define npm tasks for background execution.
…or package.json * Added "amodio.tsl-problem-matcher" to the recommended extensions. * Introduced a new command for `vscode/package.json` to run `pnpm --filter ./vscode run ext:gen`.
* Added `reactive-vscode` and `@reactive-vscode/vueuse` to the vscode catalog. * Updated existing vscode dependencies for better compatibility.
…ovider - Introduced a new VSCode extension for visualizing and managing UCD files. - Added commands for browsing UCD files, visualizing files, refreshing the explorer, and opening entries. - Implemented a content provider to fetch and display UCD file content. - Created a tree view for navigating UCD versions and files. - Integrated configuration options for local data file paths and API URLs. - Set up ESLint configuration and TypeScript build configurations. - Established a logger for better debugging and error handling.
|
WalkthroughAdds a new VS Code extension workspace under vscode/, including configs, build tooling, and extension scaffolding. Implements activation, a UCD explorer view with lazy-loading, a content provider for ucd: URIs, command registrations (browse, refresh, open, visualize placeholder), and a VS Code FS bridge. Updates root workspace to include vscode. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor VSCode
participant Ext as Extension
participant View as UCD Explorer View
participant Store as UCD Store
participant CP as UCD Content Provider
VSCode->>Ext: activate()
Ext->>View: initializeUCDExplorerView()
Ext->>Ext: registerCommands()
Ext->>CP: registerTextDocumentContentProvider("ucd")
Ext-->>VSCode: activation complete
note over View: User expands a version folder
VSCode->>View: onDidExpandElement(version)
View->>Store: loadChildrenForVersion(version)
Store-->>View: TreeViewNode[]
View-->>VSCode: render children
sequenceDiagram
autonumber
actor User
participant VSCode
participant Cmd as openEntry Command
participant CP as UCD Content Provider
User->>VSCode: Execute "ucd.openEntry"
VSCode->>Cmd: invoke(version/file or tree item)
alt Tree item with URL
Cmd->>VSCode: executeCommand("vscode.open", Uri)
else Version + file path
Cmd->>VSCode: openTextDocument(ucd:<version>/<path>)
VSCode->>CP: provideTextDocumentContent(uri)
CP-->>VSCode: fetch text or error string
VSCode->>VSCode: showTextDocument + set language "ucd"
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
📋 OpenAPI Schema Analysis✅ No changes detected - The OpenAPI schema is identical to the main branch.🤖 This comment is automatically updated when you push new commits. |
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
…ndencies * Added a README.md file detailing commands, configurations, and languages for the vscode-ucd extension. * Updated turbo.json to ensure `typecheck` task depends on `ext:gen`.
Preview Deployment for WebThe Web worker has been deployed successfully. Preview URL: https://preview.ucdjs.dev This preview was built from commit d45a8a8 🤖 This comment will be updated automatically when you push new commits to this PR. |
Preview Deployment for ApiThe Api worker has been deployed successfully. Preview URL: https://preview.api.ucdjs.dev This preview was built from commit d45a8a8 🤖 This comment will be updated automatically when you push new commits to this PR. |
There was a problem hiding this comment.
Actionable comments posted: 8
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
package.json (1)
5-6: Update Node.js engines requirement.The Node.js engines requirement should be >= 22.17 according to the coding guidelines for the root package.json.
- "node": ">=22.18" + "node": ">=22.17"As per coding guidelines
🧹 Nitpick comments (13)
vscode/src/commands/index.ts (1)
6-11: Guard against duplicate command registrationIf called twice, command registration may throw (“command already exists”). Add an idempotency guard.
Based on learnings
import { useVisualizeFileCommand } from "./visualize-file"; +let registered = false; + export function registerCommands() { + if (registered) return; + registered = true; useBrowseUcdFilesCommand(); useRefreshExplorerCommand(); useVisualizeFileCommand(); useOpenEntryCommand(); }Ensure activation calls this exactly once.
vscode/src/commands/visualize-file.ts (1)
1-9: LGTM! Well-structured command stub with appropriate placeholder.The implementation follows consistent patterns with other commands in the codebase and correctly uses reactive-vscode for command registration. The error message clearly indicates the incomplete state.
Since this is a placeholder implementation, would you like me to help generate a working visualization command that could:
- Parse UCD file content
- Display it in a webview panel
- Handle different UCD file types appropriately
Based on learnings about reactive-vscode patterns and VS Code extension development.
vscode/src/views/ucd-explorer.ts (1)
16-18: Handle thenable treeItem correctly.The logic correctly handles both synchronous TreeItem objects and thenable promises, but the type checking could be more robust.
Consider a more precise type guard:
- const treeItem = typeof element.treeItem === "object" && "then" in element.treeItem - ? await element.treeItem - : element.treeItem; + const treeItem = element.treeItem && typeof element.treeItem === "object" && "then" in element.treeItem + ? await element.treeItem + : element.treeItem;vscode/package.json (1)
24-26: Validate minimum VS Code engine versionConfirm the extension uses APIs introduced in VS Code 1.100 (released May 8 2025). Otherwise, lower the
"vscode"engine in package.json to^1.99.0to avoid excluding users still on 1.99.x.vscode/src/composables/useUCDStore.ts (3)
33-34: Use logger consistently instead of console.error.Replace console.error with logger.error for consistent logging and easier tracing.
Apply this diff:
- console.error("Failed to initialize UCD store:", error); + logger.error("Failed to initialize UCD store:", error as Error);- console.error("Failed to create UCD store:", error); + logger.error("Failed to create UCD store:", error as Error);Also applies to: 49-51
12-14: Avoid JSON.stringify in logs; pass structured data.Prefer structured logging to keep objects intact.
Example:
- logger.info("Creating UCD store with config:", JSON.stringify({ localDataFilesStore, globalFilters })); + logger.info("Creating UCD store with config", { localDataFilesStore, globalFilters });If the logger doesn’t support objects, keep as-is. [Based on learnings]
39-54: Recreate store when global filters change.Currently only local-store-path triggers recreation. Include store-filters to reflect filter changes.
Example update:
watch( [() => config["local-store-path"], () => config["store-filters"]], async ([newPath, _newFilters], [oldPath, _oldFilters]) => { if (newPath === oldPath) return; // creation logic as above (with seq guard) }, { immediate: true }, );vscode/src/commands/open-entry.ts (2)
45-50: Compose URIs safely and handle open failures.Use Uri.from to avoid encoding issues and wrap in try/catch to surface errors.
Apply this diff:
- const textEditor = await window.showTextDocument(Uri.parse(`ucd:${version}/${hasUCDFolderPath(version) ? "ucd/" : ""}${filePath}`)); - // I can't figure out how to set the language of the text editor directly, - // so we use the languages API to set the language for the document. - // The only issue is that, this triggers a close event, and a open event... - await languages.setTextDocumentLanguage(textEditor.document, "ucd"); + try { + const path = `/${version}/${hasUCDFolderPath(version) ? "ucd/" : ""}${filePath}`; + const uri = Uri.from({ scheme: "ucd", path }); + const textEditor = await window.showTextDocument(uri); + // Setting the language triggers a reopen; acceptable trade-off for now. + await languages.setTextDocumentLanguage(textEditor.document, "ucd"); + } catch (err) { + logger.error("Failed to open UCD entry", err as Error); + }
16-37: Tighten tree-item checks and remove redundancy.Single guard on __ucd and url is enough.
Apply this diff:
- if (typeof versionOrTreeView === "object" && "treeItem" in versionOrTreeView) { + if (typeof versionOrTreeView === "object" && "treeItem" in versionOrTreeView) { const treeView = versionOrTreeView; - - if (!treeView.treeItem || !(treeView.treeItem as UCDTreeItem).__ucd) { - logger.error("Invalid entry provided to openEntry command."); - return; - } - - const ucdItem = (treeView.treeItem as UCDTreeItem).__ucd; - if (!ucdItem) { - logger.error("UCD item is undefined or null."); - return; - } - - if (!ucdItem?.url) { - logger.error("UCD item does not have a valid URL."); - return; - } - - executeCommand("vscode.open", Uri.parse(ucdItem.url)); + const ucdItem = (treeView.treeItem as UCDTreeItem | undefined)?.__ucd; + if (!ucdItem?.url) { + logger.error("Invalid UCD tree item provided to openEntry command."); + return; + } + await executeCommand("vscode.open", Uri.parse(ucdItem.url)); return; }vscode/src/lib/vscode-fs-bridge.ts (4)
4-4: Avoid magic numbers; use FileType enum.Replace 2 with FileType.Directory and import FileType.
Apply this diff:
-import { Uri, workspace } from "vscode"; +import { Uri, workspace, FileType } from "vscode";- const isDirectory = type === 2; // FileType.Directory + const isDirectory = type === FileType.Directory;- if (type === 2) { // Directory + if (type === FileType.Directory) { // DirectoryAlso applies to: 36-36, 71-71
114-121: Resolve parent directory robustly (avoid appending “..”).Compute parent with path.dirname to avoid edge cases.
Apply this diff:
- const parentUri = Uri.joinPath(resolvedUri, ".."); + const parentUri = Uri.file(path.dirname(resolvedUri.fsPath));And add this import at the top of the file:
import * as path from "node:path";
19-20: Be explicit about encoding.Specify utf-8 for clarity.
Apply this diff:
- return new TextDecoder().decode(uint8Array); + return new TextDecoder("utf-8").decode(uint8Array);
123-126: Mirror explicit encoding on write.For symmetry with read; optional.
Apply this diff:
- const uint8Array = typeof data === "string" - ? new TextEncoder().encode(data) + const uint8Array = typeof data === "string" + ? new TextEncoder().encode(data) // utf-8 by default : data;
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (29)
.vscode/extensions.json(1 hunks).vscode/launch.json(1 hunks).vscode/settings.json(1 hunks).vscode/tasks.json(1 hunks)package.json(1 hunks)pnpm-workspace.yaml(3 hunks)vscode/.gitignore(1 hunks)vscode/README.md(1 hunks)vscode/eslint.config.js(1 hunks)vscode/package.json(1 hunks)vscode/src/commands/browse-ucd-files.ts(1 hunks)vscode/src/commands/index.ts(1 hunks)vscode/src/commands/open-entry.ts(1 hunks)vscode/src/commands/refresh-explorer.ts(1 hunks)vscode/src/commands/visualize-file.ts(1 hunks)vscode/src/composables/useUCDContentProvider.ts(1 hunks)vscode/src/composables/useUCDExplorer.ts(1 hunks)vscode/src/composables/useUCDStore.ts(1 hunks)vscode/src/config.ts(1 hunks)vscode/src/extension.ts(1 hunks)vscode/src/lib/files.ts(1 hunks)vscode/src/lib/ucd-content-provider.ts(1 hunks)vscode/src/lib/vscode-fs-bridge.ts(1 hunks)vscode/src/logger.ts(1 hunks)vscode/src/views/ucd-explorer.ts(1 hunks)vscode/tsconfig.build.json(1 hunks)vscode/tsconfig.json(1 hunks)vscode/tsdown.config.ts(1 hunks)vscode/turbo.json(1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/src/**
📄 CodeRabbit inference engine (AGENTS.md)
Include all source files under any src directory in coverage
Files:
vscode/src/commands/index.tsvscode/src/commands/browse-ucd-files.tsvscode/src/extension.tsvscode/src/composables/useUCDStore.tsvscode/src/composables/useUCDContentProvider.tsvscode/src/commands/refresh-explorer.tsvscode/src/config.tsvscode/src/commands/open-entry.tsvscode/src/views/ucd-explorer.tsvscode/src/commands/visualize-file.tsvscode/src/lib/ucd-content-provider.tsvscode/src/composables/useUCDExplorer.tsvscode/src/logger.tsvscode/src/lib/files.tsvscode/src/lib/vscode-fs-bridge.ts
package.json
📄 CodeRabbit inference engine (AGENTS.md)
package.json: Set Node.js engines >= 22.17 in the root package.json
Pin TypeScript to version 5.9.2 in the root devDependencies
Files:
package.json
**/package.json
📄 CodeRabbit inference engine (AGENTS.md)
Use ESM across the codebase (package.json "type": "module")
Files:
package.jsonvscode/package.json
🧠 Learnings (5)
📚 Learning: 2025-06-29T11:20:13.668Z
Learnt from: luxass
PR: ucdjs/ucd#87
File: packages/worker-shared/tsconfig.build.json:1-4
Timestamp: 2025-06-29T11:20:13.668Z
Learning: In the ucdjs/ucd project, the packages use tsdown instead of tsc for building libraries. The tsconfig.build.json files are primarily for IDE experience and type checking, not for direct compilation, so including "test" directories in these configs doesn't affect build output.
Applied to files:
vscode/tsconfig.jsonvscode/tsdown.config.tsvscode/tsconfig.build.json
📚 Learning: 2025-07-20T05:37:40.565Z
Learnt from: luxass
PR: ucdjs/ucd#131
File: tooling/eslint-plugin/package.json:0-0
Timestamp: 2025-07-20T05:37:40.565Z
Learning: In the ucdjs/ucd project, internal tooling packages (private packages in the tooling/ directory) export TypeScript files directly without requiring a build step, unlike published packages which use tsdown to build and export from ./dist/. Examples include ucdjs/tsdown-config and ucdjs/eslint-plugin.
Applied to files:
vscode/tsconfig.jsonvscode/tsdown.config.tsvscode/package.jsonvscode/tsconfig.build.json
📚 Learning: 2025-09-10T14:28:08.625Z
Learnt from: CR
PR: ucdjs/ucd#0
File: AGENTS.md:0-0
Timestamp: 2025-09-10T14:28:08.625Z
Learning: Applies to turbo.json : Manage build orchestration and caching via the root turbo.json
Applied to files:
vscode/turbo.jsonpackage.json
📚 Learning: 2025-09-10T14:28:08.625Z
Learnt from: CR
PR: ucdjs/ucd#0
File: AGENTS.md:0-0
Timestamp: 2025-09-10T14:28:08.625Z
Learning: Applies to packages/*/eslint.config.js : Maintain per-package ESLint configuration in packages/*/eslint.config.js
Applied to files:
vscode/eslint.config.js
📚 Learning: 2025-09-10T14:28:08.625Z
Learnt from: CR
PR: ucdjs/ucd#0
File: AGENTS.md:0-0
Timestamp: 2025-09-10T14:28:08.625Z
Learning: Applies to packages/*/tsdown.config.ts : Each package should include a tsdown.config.ts for building
Applied to files:
vscode/tsdown.config.tsvscode/tsconfig.build.json
🧬 Code graph analysis (11)
vscode/src/commands/index.ts (4)
vscode/src/commands/browse-ucd-files.ts (1)
useBrowseUcdFilesCommand(4-8)vscode/src/commands/refresh-explorer.ts (1)
useRefreshExplorerCommand(6-19)vscode/src/commands/visualize-file.ts (1)
useVisualizeFileCommand(5-9)vscode/src/commands/open-entry.ts (1)
useOpenEntryCommand(9-51)
vscode/src/extension.ts (4)
vscode/src/logger.ts (1)
logger(3-3)vscode/src/views/ucd-explorer.ts (1)
initializeUCDExplorerView(6-32)vscode/src/commands/index.ts (1)
registerCommands(6-11)vscode/src/composables/useUCDContentProvider.ts (1)
useUCDContentProvider(5-9)
vscode/src/composables/useUCDStore.ts (3)
vscode/src/config.ts (1)
config(4-7)vscode/src/logger.ts (1)
logger(3-3)vscode/src/lib/vscode-fs-bridge.ts (1)
vscodeFSBridge(7-144)
vscode/src/composables/useUCDContentProvider.ts (1)
vscode/src/lib/ucd-content-provider.ts (1)
UCDContentProvider(5-22)
vscode/src/commands/refresh-explorer.ts (2)
vscode/src/composables/useUCDExplorer.ts (1)
useUCDExplorer(18-93)vscode/src/logger.ts (1)
logger(3-3)
vscode/src/commands/open-entry.ts (2)
vscode/src/logger.ts (1)
logger(3-3)vscode/src/composables/useUCDExplorer.ts (1)
UCDTreeItem(11-16)
vscode/src/views/ucd-explorer.ts (2)
vscode/src/composables/useUCDExplorer.ts (2)
useUCDExplorer(18-93)UCDTreeItem(11-16)vscode/src/logger.ts (1)
logger(3-3)
vscode/src/lib/ucd-content-provider.ts (2)
vscode/src/logger.ts (1)
logger(3-3)apps/web/worker/index.ts (1)
fetch(2-5)
vscode/src/composables/useUCDExplorer.ts (3)
vscode/src/composables/useUCDStore.ts (1)
useUCDStore(8-57)vscode/src/lib/files.ts (1)
getFilesByVersion(46-62)vscode/src/logger.ts (1)
logger(3-3)
vscode/tsdown.config.ts (1)
tooling/tsdown-config/src/factory.ts (1)
createTsdownConfig(25-31)
vscode/src/lib/files.ts (2)
vscode/src/composables/useUCDExplorer.ts (1)
UCDTreeItem(11-16)vscode/src/logger.ts (1)
logger(3-3)
🔇 Additional comments (19)
.vscode/tasks.json (1)
1-26: LGTM! Well-configured background task for VS Code extension development.The task configuration correctly sets up a background npm task with appropriate problem matchers and lifecycle patterns for TypeScript/webpack builds. The configuration aligns with VS Code extension development best practices.
package.json (1)
11-12: LGTM! Proper workspace configuration.The addition of "vscode" to the workspaces array correctly integrates the VS Code extension into the monorepo structure.
vscode/src/logger.ts (1)
1-3: LGTM! Clean logger configuration.The logger setup using reactive-vscode's useLogger composable with a clear namespace is appropriate for VS Code extension development. This aligns with the reactive-vscode library's best practices for structured logging.
Based on learnings
vscode/turbo.json (1)
1-27: LGTM! Well-structured Turbo configuration.The configuration correctly:
- Extends the root turbo configuration
- Defines proper task dependencies (ext:gen before build/typecheck)
- Configures appropriate outputs for generated files and build artifacts
- Sets up non-persistent dev task for background development
The generated meta.ts pattern aligns with VS Code extension development practices.
vscode/src/commands/refresh-explorer.ts (1)
6-18: LGTM: clear and safe refresh commandCommand registration and cache reset look good; logging covers both failure and success paths.
vscode/eslint.config.js (1)
1-7: ESM support confirmed vscode/package.json already sets"type": "module", so no changes required..vscode/settings.json (1)
16-18: Fix run-on-save matcher for Windows paths- "match": "vscode/package.json", + "match": "vscode[\\\\/]+package\\.json$",Verify it triggers on both macOS/Linux and Windows when saving
vscode/package.json.pnpm-workspace.yaml (3)
15-15: LGTM! Workspace package addition aligns with PR objectives.Adding the
vscodeworkspace package is consistent with moving the VS Code extension into this repository.
85-85: LGTM! VS Code types version aligns with engine requirements.The
@types/vscodeversion 1.104.0 properly supports the VS Code engine requirement of^1.100.0specified in the extension manifest.
99-103: Verify reactive-vscode version compatibility.The VS Code catalog specifies reactive-vscode 0.3.2, but based on learnings, the latest published version is 0.2.14 (March 2025). Please confirm this version exists and is stable.
Based on learnings about reactive-vscode versions.Based on the search results, I can see that the latest version of @reactive-vscode/vueuse is 0.2.9, published a month ago, but the workspace configuration specifies version 0.3.2. Let me search for the main reactive-vscode package specifically.The search results confirm that reactive-vscode is in 0.x and may have API changes, but don't clearly show version 0.3.2. Based on the retrieved learnings which mention the latest published version as 0.2.14 (March 2025), and the search results showing @reactive-vscode/vueuse at 0.2.9, the specified version 0.3.2 appears to be newer than what's documented. This warrants verification but may not necessarily be an error - the project could have published newer versions.
vscode/src/views/ucd-explorer.ts (2)
20-25: LGTM! Proper lazy loading implementation with version extraction.The logic correctly:
- Checks the contextValue to identify version folders
- Extracts the version from the UCDTreeItem metadata
- Calls the explorer's loadChildrenForVersion method for lazy loading
This aligns well with the useUCDExplorer composable's caching and loading logic.
26-29: LGTM! Comprehensive error handling with proper logging.The try/catch block properly handles async errors and uses the centralized logger for consistent error reporting.
vscode/src/lib/files.ts (3)
10-13: LGTM! Proper null checking for defensive programming.The explicit null check prevents potential runtime errors and provides a clear error message.
37-43: Well-structured metadata attachment with proper URL construction.The
__ucdmetadata correctly includes version information and constructs URLs using thehasUCDFolderPathutility to handle version-specific path requirements. The recursive mapping maintains the tree structure properly.
46-62: LGTM! Proper async error handling with tuple destructuring.The function correctly:
- Uses tuple destructuring to handle the store's return format
- Checks for and throws errors when present
- Maps the data using the helper function
- Provides comprehensive error logging and safe fallback
The error handling ensures the UI remains functional even when data loading fails.
vscode/package.json (3)
6-6: LGTM! Proper ESM configuration aligns with coding guidelines.The
"type": "module"declaration correctly enables ESM across the codebase as required by the coding guidelines.As per coding guidelines requiring ESM configuration.
168-172: LGTM! Proper workspace dependencies for monorepo structure.The use of
workspace:*for internal packages correctly leverages the pnpm workspace setup for local development and ensures proper dependency management.Based on learnings about internal tooling packages in the ucdjs/ucd project.
22-22: Confirmed CJS build output matches .cjs main entry
tsdown.config.ts specifiesformat: "cjs", so thedist/extension.cjsartifact aligns with the manifest and will be recognized as CommonJS within a"module"package.vscode/src/commands/open-entry.ts (1)
3-3: Verify hasUCDFolderPath(version) semantics.Confirm it expects a version string (not a filesystem path) and matches your stored structure. If it requires a path, prepend the base path appropriately.
Also applies to: 39-45
| "outFiles": [ | ||
| "${workspaceFolder}/vscode/dist/**/*.js" | ||
| ], | ||
| "preLaunchTask": "npm: dev:vscode" | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
Verify dev task and build outputs
Ensure:
- npm script “dev:vscode” exists (root or vscode workspace) and is wired in tasks.json
- outFiles matches your compiled output path (dist) with source maps enabled during dev
🏁 Script executed:
#!/bin/bash
# Check npm script presence
rg -n --glob '**/package.json' -C2 '"dev:vscode"'
# Check VS Code tasks for npm: dev:vscode
rg -n -C2 '"dev:vscode"' .vscode/tasks.json
# Check tsconfig outDir for vscode package
rg -n -C2 '"outDir"' vscode/tsconfig*.jsonLength of output: 119
Define missing dev:vscode npm script and configure outDir
- package.json doesn’t define
"dev:vscode"yet.vscode/tasks.jsoninvokes it - no
"outDir"invscode/tsconfig*.json; set it to"vscode/dist"(with sourceMap) so it matches your launch.jsonoutFiles
| "ucd.data-files-api": { | ||
| "type": "string", | ||
| "description": "API URL to fetch UCD data files from", | ||
| "default": "https://unicode-api.luxass.dev", | ||
| "enum": [ | ||
| "https://unicode-api.luxass.dev", | ||
| "https://preview.unicode-api.luxass.dev" | ||
| ] | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
Validate API URLs and consider environment configuration.
The configuration provides two hardcoded API endpoints. Consider:
- Verifying these URLs are accessible and return expected data
- Whether additional configuration for self-hosted instances might be valuable
🏁 Script executed:
#!/bin/bash
# Verify the API endpoints are accessible
echo "Testing UCD API endpoints..."
# Test production API
echo "Testing production API:"
curl -sf "https://unicode-api.luxass.dev" -I || echo "Production API not accessible"
# Test preview API
echo "Testing preview API:"
curl -sf "https://preview.unicode-api.luxass.dev" -I || echo "Preview API not accessible"
# Check if these APIs return expected data structure
echo "Checking API response format:"
curl -sf "https://unicode-api.luxass.dev" -H "Accept: application/json" | head -c 200 || echo "No JSON response"Length of output: 1458
Fix UCD data-files API URLs in vscode/package.json
- Default and enum values under
ucd.data-files-apipoint to the root URLs, which serve HTML docs (HTTP 200 text/html), not JSON data. Update them to the actual JSON endpoints (e.g. include/data-filesor the correct API path). - Add support for custom self-hosted instances via an environment-driven override.
🤖 Prompt for AI Agents
In vscode/package.json around lines 88 to 96, the ucd.data-files-api default and
enum entries currently point to root HTML endpoints instead of the actual JSON
API path; update the default and enum values to the correct JSON endpoints (e.g.
append the proper API path such as /data-files or the real API route used by the
service) and ensure the schema allows a custom self-hosted URL by documenting
and wiring an environment-driven override (read from an env var like
UCD_DATA_FILES_API in runtime/config and prefer it over the package.json
default). Ensure the enum contains the actual JSON endpoint URLs and the default
matches a working JSON endpoint.
| useCommand(Meta.commands.browseUcdFiles, async () => { | ||
| executeCommand("ucd:explorer.focus"); | ||
| }); |
There was a problem hiding this comment.
Await the focus command so failures surface properly
The async handler returns before executeCommand finishes, so any rejection turns into an unhandled promise and users receive no feedback. Await (or return) the command promise so errors propagate through the command invocation chain.
- executeCommand("ucd:explorer.focus");
+ await executeCommand("ucd:explorer.focus");📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| useCommand(Meta.commands.browseUcdFiles, async () => { | |
| executeCommand("ucd:explorer.focus"); | |
| }); | |
| useCommand(Meta.commands.browseUcdFiles, async () => { | |
| await executeCommand("ucd:explorer.focus"); | |
| }); |
🤖 Prompt for AI Agents
In vscode/src/commands/browse-ucd-files.ts around lines 5 to 7, the async
command handler calls executeCommand("ucd:explorer.focus") but does not await or
return its promise so rejections become unhandled; change the handler to await
(or return) the executeCommand call so the command promise is propagated (e.g.,
await executeCommand(...)) and consider letting the caller surface the error
instead of silently dropping the promise.
| const childrenCache = ref<Map<string, TreeViewNode[]>>(new Map()); | ||
| const loadingPromises = ref<Map<string, Promise<TreeViewNode[]>>>(new Map()); | ||
|
|
||
| function refresh() { | ||
| childrenCache.value.clear(); | ||
| loadingPromises.value.clear(); | ||
| } | ||
|
|
||
| async function loadChildrenForVersion(version: string): Promise<TreeViewNode[]> { | ||
| const cached = childrenCache.value.get(version); | ||
| if (cached) { | ||
| return cached; | ||
| } | ||
|
|
||
| // return existing promise if already loading (prevents duplicate requests) | ||
| const existingPromise = loadingPromises.value.get(version); | ||
| if (existingPromise) { | ||
| return existingPromise; | ||
| } | ||
|
|
||
| // create new loading promise | ||
| const loadingPromise = (async () => { | ||
| try { | ||
| const storeValue = toRaw(store.value); | ||
| if (!(storeValue instanceof UCDStore)) { | ||
| throw new TypeError("UCD Store is not initialized"); | ||
| } | ||
|
|
||
| const files = await getFilesByVersion( | ||
| storeValue, | ||
| version, | ||
| ); | ||
|
|
||
| childrenCache.value.set(version, files); | ||
| return files; | ||
| } catch (error) { | ||
| logger.error(`Failed to load files for version ${version}:`, error); | ||
| return []; | ||
| } finally { | ||
| // clean up loading promise regardless of success/failure | ||
| loadingPromises.value.delete(version); | ||
| } | ||
| })(); | ||
|
|
||
| // store the promise to prevent duplicate requests | ||
| loadingPromises.value.set(version, loadingPromise); | ||
| return loadingPromise; | ||
| } |
There was a problem hiding this comment.
Fix cache reactivity to avoid stale tree nodes
childrenCache (and loadingPromises) are refs that wrap a mutable Map, but we only mutate the inner map via .set(), .clear(), and .delete() without ever replacing childrenCache.value. Vue/reactive-vscode won't emit a change signal in this situation, so your computed tree never recomputes—expanded folders stay empty even after loadChildrenForVersion resolves. Reassign the ref with a fresh Map whenever you mutate it (including refresh) to keep the explorer responsive.
const childrenCache = ref<Map<string, TreeViewNode[]>>(new Map());
const loadingPromises = ref<Map<string, Promise<TreeViewNode[]>>>(new Map());
function refresh() {
- childrenCache.value.clear();
- loadingPromises.value.clear();
+ childrenCache.value = new Map();
+ loadingPromises.value = new Map();
}
async function loadChildrenForVersion(version: string): Promise<TreeViewNode[]> {
@@
- const files = await getFilesByVersion(
- storeValue,
- version,
- );
-
- childrenCache.value.set(version, files);
+ const files = await getFilesByVersion(storeValue, version);
+ const nextCache = new Map(childrenCache.value);
+ nextCache.set(version, files);
+ childrenCache.value = nextCache;
return files;
} catch (error) {
logger.error(`Failed to load files for version ${version}:`, error);
return [];
} finally {
// clean up loading promise regardless of success/failure
- loadingPromises.value.delete(version);
+ const nextPromises = new Map(loadingPromises.value);
+ nextPromises.delete(version);
+ loadingPromises.value = nextPromises;
}
})();
// store the promise to prevent duplicate requests
- loadingPromises.value.set(version, loadingPromise);
+ const nextPromises = new Map(loadingPromises.value);
+ nextPromises.set(version, loadingPromise);
+ loadingPromises.value = nextPromises;
return loadingPromise;
}Based on learnings
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const childrenCache = ref<Map<string, TreeViewNode[]>>(new Map()); | |
| const loadingPromises = ref<Map<string, Promise<TreeViewNode[]>>>(new Map()); | |
| function refresh() { | |
| childrenCache.value.clear(); | |
| loadingPromises.value.clear(); | |
| } | |
| async function loadChildrenForVersion(version: string): Promise<TreeViewNode[]> { | |
| const cached = childrenCache.value.get(version); | |
| if (cached) { | |
| return cached; | |
| } | |
| // return existing promise if already loading (prevents duplicate requests) | |
| const existingPromise = loadingPromises.value.get(version); | |
| if (existingPromise) { | |
| return existingPromise; | |
| } | |
| // create new loading promise | |
| const loadingPromise = (async () => { | |
| try { | |
| const storeValue = toRaw(store.value); | |
| if (!(storeValue instanceof UCDStore)) { | |
| throw new TypeError("UCD Store is not initialized"); | |
| } | |
| const files = await getFilesByVersion( | |
| storeValue, | |
| version, | |
| ); | |
| childrenCache.value.set(version, files); | |
| return files; | |
| } catch (error) { | |
| logger.error(`Failed to load files for version ${version}:`, error); | |
| return []; | |
| } finally { | |
| // clean up loading promise regardless of success/failure | |
| loadingPromises.value.delete(version); | |
| } | |
| })(); | |
| // store the promise to prevent duplicate requests | |
| loadingPromises.value.set(version, loadingPromise); | |
| return loadingPromise; | |
| } | |
| const childrenCache = ref<Map<string, TreeViewNode[]>>(new Map()); | |
| const loadingPromises = ref<Map<string, Promise<TreeViewNode[]>>>(new Map()); | |
| function refresh() { | |
| childrenCache.value = new Map(); | |
| loadingPromises.value = new Map(); | |
| } | |
| async function loadChildrenForVersion(version: string): Promise<TreeViewNode[]> { | |
| const cached = childrenCache.value.get(version); | |
| if (cached) { | |
| return cached; | |
| } | |
| // return existing promise if already loading (prevents duplicate requests) | |
| const existingPromise = loadingPromises.value.get(version); | |
| if (existingPromise) { | |
| return existingPromise; | |
| } | |
| // create new loading promise | |
| const loadingPromise = (async () => { | |
| try { | |
| const storeValue = toRaw(store.value); | |
| if (!(storeValue instanceof UCDStore)) { | |
| throw new TypeError("UCD Store is not initialized"); | |
| } | |
| const files = await getFilesByVersion(storeValue, version); | |
| const nextCache = new Map(childrenCache.value); | |
| nextCache.set(version, files); | |
| childrenCache.value = nextCache; | |
| return files; | |
| } catch (error) { | |
| logger.error(`Failed to load files for version ${version}:`, error); | |
| return []; | |
| } finally { | |
| // clean up loading promise regardless of success/failure | |
| const nextPromises = new Map(loadingPromises.value); | |
| nextPromises.delete(version); | |
| loadingPromises.value = nextPromises; | |
| } | |
| })(); | |
| // store the promise to prevent duplicate requests | |
| const nextPromises = new Map(loadingPromises.value); | |
| nextPromises.set(version, loadingPromise); | |
| loadingPromises.value = nextPromises; | |
| return loadingPromise; | |
| } |
🤖 Prompt for AI Agents
In vscode/src/composables/useUCDExplorer.ts around lines 21 to 68, childrenCache
and loadingPromises are refs wrapping Map objects but are only mutated in-place
(.set, .delete, .clear), so Vue won't react; update the code to reassign the ref
to a new Map whenever you mutate it (e.g., after setting files do
childrenCache.value = new Map(childrenCache.value), after deleting a key do
loadingPromises.value = new Map(loadingPromises.value), and in refresh replace
both refs with new Map() instances) to ensure the computed tree recomputes and
expanded folders update correctly.
| try { | ||
| await _store.init(); | ||
| } catch (error) { | ||
| console.error("Failed to initialize UCD store:", error); | ||
| } | ||
|
|
||
| return _store; |
There was a problem hiding this comment.
Avoid returning a half-initialized store; propagate init failure.
If init fails, rethrow so callers can handle (we set store to null upstream).
Apply this diff:
try {
await _store.init();
} catch (error) {
- console.error("Failed to initialize UCD store:", error);
+ logger.error("Failed to initialize UCD store:", error as Error);
+ throw error;
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| try { | |
| await _store.init(); | |
| } catch (error) { | |
| console.error("Failed to initialize UCD store:", error); | |
| } | |
| return _store; | |
| try { | |
| await _store.init(); | |
| } catch (error) { | |
| logger.error("Failed to initialize UCD store:", error as Error); | |
| throw error; | |
| } | |
| return _store; |
🤖 Prompt for AI Agents
In vscode/src/composables/useUCDStore.ts around lines 30 to 36, the current code
catches init errors and logs them then returns the store, which may be
half-initialized; change this to propagate the failure: remove the swallowing
catch (or rethrow after logging) so that when _store.init() rejects the error is
thrown to callers (upstream expects null on failure) — ensure the function does
not return _store on init failure.
| watch( | ||
| () => config["local-store-path"], | ||
| async (newVal, oldVal) => { | ||
| if (newVal === oldVal) { | ||
| return; | ||
| } | ||
|
|
||
| try { | ||
| store.value = await createStoreFromConfig(newVal); | ||
| } catch (error) { | ||
| console.error("Failed to create UCD store:", error); | ||
| store.value = null; | ||
| } | ||
| }, | ||
| { immediate: true }, | ||
| ); |
There was a problem hiding this comment.
Guard against race conditions on fast config changes (last-write-wins).
Out-of-order async resolutions can overwrite with stale stores. Use a sequence token to ensure only the latest result wins; optionally dispose the previous store if supported.
Apply this diff inside the watcher:
- async (newVal, oldVal) => {
+ async (newVal, oldVal) => {
if (newVal === oldVal) {
return;
}
- try {
- store.value = await createStoreFromConfig(newVal);
+ try {
+ const seq = ++createSeq;
+ const next = await createStoreFromConfig(newVal);
+ if (seq !== createSeq) return; // stale
+ const prev = store.value;
+ store.value = next;
+ // optional cleanup if supported by the implementation
+ if (prev && typeof (prev as any).dispose === "function") {
+ try { (prev as any).dispose(); } catch {}
+ }
} catch (error) {
- console.error("Failed to create UCD store:", error);
+ logger.error("Failed to create UCD store:", error as Error);
store.value = null;
}
},And add this variable near the top of the composable (outside the watcher):
// add after `const store = ref<UCDStore | null>(null);`
let createSeq = 0;🤖 Prompt for AI Agents
In vscode/src/composables/useUCDStore.ts around lines 39 to 54, the watcher can
suffer race conditions where slower async createStoreFromConfig calls overwrite
newer results; add a numeric sequence token to enforce last-write-wins: declare
let createSeq = 0 just after const store = ref<UCDStore | null>(null); then
inside the watcher increment a local token (e.g., const seq = ++createSeq)
before awaiting createStoreFromConfig and after the await check that seq ===
createSeq before assigning store.value; if a previous store instance exists and
the new assignment is winning, dispose/close the old store if the store API
supports it to avoid leaks.
| external: [ | ||
| "vscode", | ||
| ], |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
Update external dependency configuration.
The external property should be replaced with externalIncludes to match the modern tsdown API. Based on the retrieved learnings about reactive-vscode, this configuration should align with current best practices.
- external: [
- "vscode",
- ],
+ externalIncludes: ["vscode"],Based on learnings
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| external: [ | |
| "vscode", | |
| ], | |
| externalIncludes: ["vscode"], |
🤖 Prompt for AI Agents
In vscode/tsdown.config.ts around lines 9 to 11, the config uses the outdated
property name "external"; replace that key with "externalIncludes" and keep the
same array contents (e.g., ["vscode"]) so the config matches the modern tsdown
API and current reactive-vscode best practices.
| // Bundle workspace packages so they're included in the extension | ||
| noExternal: [ | ||
| /^@ucdjs\//, | ||
| ], |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
Update bundling configuration property.
The noExternal property should be replaced with noExternalIncludes to match the modern tsdown API.
- // Bundle workspace packages so they're included in the extension
- noExternal: [
- /^@ucdjs\//,
- ],
+ // Bundle workspace packages so they're included in the extension
+ noExternalIncludes: [/^@ucdjs\//],Based on learnings
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| // Bundle workspace packages so they're included in the extension | |
| noExternal: [ | |
| /^@ucdjs\//, | |
| ], | |
| // Bundle workspace packages so they're included in the extension | |
| noExternalIncludes: [/^@ucdjs\//], |
🤖 Prompt for AI Agents
In vscode/tsdown.config.ts around lines 12 to 15, the config uses the legacy
noExternal property; replace it with noExternalIncludes to match the current
tsdown API, keeping the same array contents (the /^@ucdjs\// regex) and ensure
the property name is updated only (no other structural changes).
🔗 Linked issue
📚 Description
This is moved from https://github.com/ucdjs/vscode-ucd to have more freedom when changing code.
Summary by CodeRabbit
New Features
Documentation
Chores