feat(dictionary): add dictionary search, synonyms, and examples adapters (#241)

* feat(dictionary): add dictionary search, synonyms, and examples adapters

* feat: Improve dictionary commands with positional word arguments, URL encoding, enhanced phonetic parsing, and new E2E tests.
This commit is contained in:
VK
2026-03-24 16:56:00 +05:30
committed by GitHub
parent b1067b64ee
commit 3d39574501
9 changed files with 141 additions and 0 deletions
+1
View File
@@ -145,6 +145,7 @@ Run `opencli list` for the live registry.
| **bloomberg** | `main` `markets` `economics` `industries` `tech` `politics` `businessweek` `opinions` `feeds` `news` | Public / Browser |
| **ctrip** | `search` | Browser |
| **devto** | `top` `tag` `user` | Public |
| **dictionary** | `search` `synonyms` `examples` | Public |
| **arxiv** | `search` `paper` | Public |
| **wikipedia** | `search` `summary` `random` `trending` | Public |
| **hackernews** | `top` `new` `best` `ask` `show` `jobs` `search` `user` | Public |
+1
View File
@@ -147,6 +147,7 @@ npm install -g @jackwener/opencli@latest
| **bloomberg** | `main` `markets` `economics` `industries` `tech` `politics` `businessweek` `opinions` `feeds` `news` | 公共 API / 浏览器 |
| **ctrip** | `search` | 浏览器 |
| **devto** | `top` `tag` `user` | 公开 |
| **dictionary** | `search` `synonyms` `examples` | 公开 |
| **arxiv** | `search` `paper` | 公开 |
| **wikipedia** | `search` `summary` `random` `trending` | 公开 |
| **hackernews** | `top` `new` `best` `ask` `show` `jobs` `search` `user` | 公共 API |
+1
View File
@@ -81,6 +81,7 @@ export default defineConfig({
items: [
{ text: 'HackerNews', link: '/adapters/browser/hackernews' },
{ text: 'Dev.to', link: '/adapters/browser/devto' },
{ text: 'Dictionary', link: '/adapters/browser/dictionary' },
{ text: 'BBC', link: '/adapters/browser/bbc' },
{ text: 'Apple Podcasts', link: '/adapters/browser/apple-podcasts' },
{ text: 'Xiaoyuzhou', link: '/adapters/browser/xiaoyuzhou' },
+27
View File
@@ -0,0 +1,27 @@
# Dictionary
**Mode**: 🌐 Public · **Domain**: `api.dictionaryapi.dev`
Search the open dictionary to quickly fetch native definitions, part of speech contexts, and phonetic pronunciations directly in your IDE terminal.
## Commands
| Command | Description |
|---------|-------------|
| `opencli dictionary search` | Fetch the exact definition of a word |
| `opencli dictionary synonyms` | Find related synonyms for a word |
| `opencli dictionary examples` | Read real-world sentence usage examples |
## Usage Examples
```bash
# Look up a complex term
opencli dictionary search serendipity
# Discover phonetics
opencli dictionary search ephemeral
```
## Prerequisites
- No browser required — utilizes the fast, open JSON definitions API.
+1
View File
@@ -45,6 +45,7 @@ Run `opencli list` for the live registry.
| **[hackernews](/adapters/browser/hackernews)** | `top` `new` `best` `ask` `show` `jobs` `search` `user` | 🌐 Public |
| **[bbc](/adapters/browser/bbc)** | `news` | 🌐 Public |
| **[devto](/adapters/browser/devto)** | `top` `tag` `user` | 🌐 Public |
| **[dictionary](/adapters/browser/dictionary)** | `search` `synonyms` `examples` | 🌐 Public |
| **[apple-podcasts](/adapters/browser/apple-podcasts)** | `search` `episodes` `top` | 🌐 Public |
| **[xiaoyuzhou](/adapters/browser/xiaoyuzhou)** | `podcast` `podcast-episodes` `episode` | 🌐 Public |
| **[yahoo-finance](/adapters/browser/yahoo-finance)** | `quote` | 🌐 Public |
+25
View File
@@ -0,0 +1,25 @@
site: dictionary
name: examples
description: Read real-world example sentences utilizing the word
domain: api.dictionaryapi.dev
strategy: public
browser: false
args:
word:
type: string
required: true
positional: true
description: Word to get example sentences for
pipeline:
- fetch:
url: "https://api.dictionaryapi.dev/api/v2/entries/en/${{ args.word | urlencode }}"
- map:
word: "${{ item.word }}"
example: "${{ (() => { if (item.meanings) { for (const m of item.meanings) { if (m.definitions) { for (const d of m.definitions) { if (d.example) return d.example; } } } } return 'No example found in API.'; })() }}"
- limit: 1
columns: [word, example]
+27
View File
@@ -0,0 +1,27 @@
site: dictionary
name: search
description: Search the Free Dictionary API for definitions, parts of speech, and pronunciations.
domain: api.dictionaryapi.dev
strategy: public
browser: false
args:
word:
type: string
required: true
positional: true
description: Word to define (e.g., serendipity)
pipeline:
- fetch:
url: "https://api.dictionaryapi.dev/api/v2/entries/en/${{ args.word | urlencode }}"
- map:
word: "${{ item.word }}"
phonetic: "${{ (() => { if (item.phonetic) return item.phonetic; if (item.phonetics) { for (const p of item.phonetics) { if (p.text) return p.text; } } return ''; })() }}"
type: "${{ item.meanings[0].partOfSpeech }}"
definition: "${{ item.meanings[0].definitions[0].definition }}"
- limit: 1
columns: [word, phonetic, type, definition]
+25
View File
@@ -0,0 +1,25 @@
site: dictionary
name: synonyms
description: Find synonyms for a specific word
domain: api.dictionaryapi.dev
strategy: public
browser: false
args:
word:
type: string
required: true
positional: true
description: Word to find synonyms for (e.g., serendipity)
pipeline:
- fetch:
url: "https://api.dictionaryapi.dev/api/v2/entries/en/${{ args.word | urlencode }}"
- map:
word: "${{ item.word }}"
synonyms: "${{ (() => { const s = new Set(); if (item.meanings) { for (const m of item.meanings) { if (m.synonyms) { for (const syn of m.synonyms) s.add(syn); } if (m.definitions) { for (const d of m.definitions) { if (d.synonyms) { for (const syn of d.synonyms) s.add(syn); } } } } } const arr = Array.from(s); return arr.length > 0 ? arr.slice(0, 5).join(', ') : 'No synonyms found in API.'; })() }}"
- limit: 1
columns: [word, synonyms]
+33
View File
@@ -489,4 +489,37 @@ describe('public commands E2E', () => {
expect(data.length).toBeGreaterThan(0);
expect(data.every((d: any) => d.type === 'image')).toBe(true);
}, 30_000);
// ── dictionary (public API, browser: false) ──
it('dictionary search returns word definitions', async () => {
const { stdout, code } = await runCli(['dictionary', 'search', 'serendipity', '-f', 'json']);
expect(code).toBe(0);
const data = parseJsonOutput(stdout);
expect(Array.isArray(data)).toBe(true);
expect(data.length).toBeGreaterThanOrEqual(1);
expect(data[0]).toHaveProperty('word', 'serendipity');
expect(data[0]).toHaveProperty('phonetic');
expect(data[0]).toHaveProperty('definition');
}, 30_000);
it('dictionary synonyms returns synonyms', async () => {
const { stdout, code } = await runCli(['dictionary', 'synonyms', 'serendipity', '-f', 'json']);
expect(code).toBe(0);
const data = parseJsonOutput(stdout);
expect(Array.isArray(data)).toBe(true);
expect(data.length).toBeGreaterThanOrEqual(1);
expect(data[0]).toHaveProperty('word', 'serendipity');
expect(data[0]).toHaveProperty('synonyms');
}, 30_000);
it('dictionary examples returns examples', async () => {
const { stdout, code } = await runCli(['dictionary', 'examples', 'perfect', '-f', 'json']);
expect(code).toBe(0);
const data = parseJsonOutput(stdout);
expect(Array.isArray(data)).toBe(true);
expect(data.length).toBeGreaterThanOrEqual(1);
expect(data[0]).toHaveProperty('word', 'perfect');
expect(data[0]).toHaveProperty('example');
}, 30_000);
}, 30_000);
});