Skip to content

Commit

Permalink
Add Rhymes and Alliterative Synonyms command
Browse files Browse the repository at this point in the history
  • Loading branch information
nqthqn committed Dec 14, 2022
1 parent bbe771a commit 80ccbaf
Show file tree
Hide file tree
Showing 2 changed files with 179 additions and 35 deletions.
151 changes: 121 additions & 30 deletions DatamuseApi.ts
Original file line number Diff line number Diff line change
@@ -1,35 +1,126 @@
export type SimilarWords = {
relatedWords: string[]
}
relatedWords: string[];
};

// This uses WordNet and RhymeZone
// https://www.datamuse.com/api/
type QueryParam =
| "rel_rhy" // Rhymes spade → aid
| "rel_nry" // Approximate rhymes forest → chorus
| "rel_hom" // Homophones (sound-alike words) course → coarse
| "rel_cns" // Consonant match sample → simple
| "rel_ant" // Antonyms late → early
| "rel_syn" // Synonyms ocean → sea
| "rel_spc" // "More general than" (direct hyponyms) boat → gondola
| "rel_gen" // "More general than" (direct hyponyms) boat → gondola
| "rel_com" // "Comprises" (direct holonyms) car → accelerator
| "rel_par"; //"Part of" (direct meronyms) trunk → tree

export class DatamuseApi {
baseUrl = new URL("https://api.datamuse.com/words");

async wordsSimilarTo(rootWord: string): Promise<SimilarWords> {
const similarWords: SimilarWords =
{
relatedWords: []
}
const urls = ["rel_syn", "rel_spc", "rel_gen", "rel_com", "rel_par"];
await Promise.all(urls.map(async (queryParam: string) => {
const url = `${this.baseUrl}?${queryParam}=${rootWord}`;
const resp = await fetch(url);
const data = await resp.json();
similarWords.relatedWords.push(...data.map((o: any) => o.word))
}));
return similarWords;
}

async wordsOppositeTo(rootWord: string): Promise<string[]> {
const results: string[] = [];
const urls = ["rel_ant"];
await Promise.all(urls.map(async (queryParam: string) => {
const url = `${this.baseUrl}?${queryParam}=${rootWord}`;
const resp = await fetch(url);
const data = await resp.json();
results.push(...data.map((o: any) => o.word))
}));
return results;
}
baseUrl = new URL("https://api.datamuse.com/words");

async wordsSimilarTo(rootWord: string, extra = false): Promise<string[]> {
const results: string[] = [];
const urls: QueryParam[] = [
"rel_syn",
"rel_spc",
"rel_gen",
"rel_com",
"rel_par",
];
await Promise.all(
urls.map(async (queryParam: QueryParam) => {
results.push(
...(await this.relatedWords(queryParam, rootWord))
);
})
);
if (extra) {
const extraResults: string[] = [];
await Promise.all(
results.map(async (similiarWord: string) => {
extraResults.push(
...(await this.relatedWords("rel_syn", similiarWord))
);
})
);
results.push(...extraResults);
}
return results;
}

async wordsOppositeTo(rootWord: string, extra = false): Promise<string[]> {
const results: string[] = [];
results.push(...(await this.relatedWords("rel_ant", rootWord)));

// Get antonyms for synonyms as well
const syns = await this.relatedWords("rel_syn", rootWord);
Promise.all(
syns.map(async (wordLikeRootWord: string) => {
const data = await this.relatedWords(
"rel_ant",
wordLikeRootWord
);
results.push(...data);
})
);
if (extra) {
// Get antonyms for each synonym
const extraResults: string[] = [];
const synonyms = [...(await this.wordsSimilarTo(rootWord))];

await Promise.all(
synonyms.map(async (similiarWord: string) => {
const antonyms = await this.relatedWords(
"rel_ant",
similiarWord
);
extraResults.push(...antonyms);
})
);
results.push(...extraResults);
}
return this.cleanUp(results);
}

async wordsThatRhymeWith(rootWord: string): Promise<string[]> {
const results: string[] = [];
const urls: QueryParam[] = ["rel_rhy", "rel_nry", "rel_hom", "rel_cns"];
await Promise.all(
urls.map(async (queryParam: QueryParam) => {
results.push(
...(await this.relatedWords(queryParam, rootWord))
);
})
);
return this.cleanUp(results);
}

async alliterativeSynonyms(
priorWord: string,
rootWord: string
): Promise<string[]> {
const data = await this.wordsSimilarTo(rootWord, true);
return [
...data
.filter((w) => w.startsWith(priorWord[0]))
.map((syn) => `${priorWord} ${syn}`),
];
}

private cleanUp(results: string[]) {
return [...new Set(results.filter((el) => !!el))];
}

private async relatedWords(
queryParam: QueryParam,
rootWord: string
): Promise<string[]> {
const results = [];
const url = `${this.baseUrl}?${queryParam}=${rootWord}`;
const resp = await fetch(url);
const data = await resp.json();
results.push(...data.map((o: any) => o.word));
return results;
}
}
63 changes: 58 additions & 5 deletions main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,13 @@ export default class WordyPlugin extends Plugin {
const similarWords = await this.datamuseApi.wordsSimilarTo(
rootWord
);
if (similarWords.relatedWords.length == 0) {
if (similarWords.length == 0) {
new Notice(`Oops — No synonyms found.`);
return;
}
new SearchableWordsModal(
this.app,
similarWords.relatedWords,
similarWords,
(selectedWord: string) => {
editor.replaceSelection(selectedWord);
}
Expand All @@ -66,9 +66,8 @@ export default class WordyPlugin extends Plugin {
editorCallback: async (editor: Editor, view: MarkdownView) => {
const rootWord = editor.getSelection();
if (rootWord != "") {
const oppositeWords = await this.datamuseApi.wordsOppositeTo(
rootWord
);
const oppositeWords =
await this.datamuseApi.wordsOppositeTo(rootWord, true);
if (oppositeWords.length == 0) {
new Notice(`Oops — No antonyms found.`);
return;
Expand All @@ -86,6 +85,60 @@ export default class WordyPlugin extends Plugin {
},
});

this.addCommand({
id: "wordy-rhy",
name: "Rhymes",
editorCallback: async (editor: Editor, view: MarkdownView) => {
const rootWord = editor.getSelection();
if (rootWord != "") {
const rhymes = await this.datamuseApi.wordsThatRhymeWith(
rootWord
);
if (rhymes.length == 0) {
new Notice(`Oops — No rhymes found.`);
return;
}
new SearchableWordsModal(
this.app,
rhymes,
(selectedWord: string) => {
editor.replaceSelection(selectedWord);
}
).open();
} else {
new Notice(`Oops — Select a word first.`);
}
},
});

this.addCommand({
id: "wordy-asyn",
name: "Alliterative Synonyms",
editorCallback: async (editor: Editor, view: MarkdownView) => {
const [priorWord, rootWord] = editor.getSelection().split(" ");
if (rootWord != "") {
const alliterativeSynonyms =
await this.datamuseApi.alliterativeSynonyms(
priorWord,
rootWord
);
if (alliterativeSynonyms.length == 0) {
new Notice(`Oops — No rhymes found.`);
return;
}
new SearchableWordsModal(
this.app,
alliterativeSynonyms,
(selectedWord: string) => {
editor.replaceSelection(`${selectedWord}`);
}
).open();
} else {
new Notice(`Oops — Select a word first.`);
}
},
});

// This adds a settings tab so the user can configure various aspects of the plugin
this.addSettingTab(new WordyPluginSettingTab(this.app, this));
}
Expand Down

0 comments on commit 80ccbaf

Please sign in to comment.