Better definition implementation

This commit is contained in:
Mr. Stallion 2021-01-22 17:18:41 -06:00
parent 60fd33a0f9
commit 3f8d84803c
26 changed files with 220 additions and 487200 deletions

View File

@ -1,7 +1,7 @@
# Changelog
## Canary
* Right click a word and select 'Look up...' to see its dictionary definition
* Right click any word and select 'Look up...' to see its dictionary definition
* Skip button for auto-post ads
* Image tab on the character profile view now loads up faster
* Search results view is now more responsive while scoring profiles

View File

@ -67,6 +67,7 @@ This repository contains a heavily customized version of the mainline F-Chat 3.0
* Use `Ctrl+Tab`, `Ctrl+Shift+Tab`, `Ctrl+PgDown`, and `Ctrl+PgUp` to switch between character tabs
* Show number of unread notes and messages in the bottom right corner
* Colorblind mode
* Right click any word and select 'Look up...' to see its dictionary definition
* Technical Details for Nerds
* Upgraded to Electron 10.x
* Replaced `node-spellchecker` with the built-in spellchecker that ships with Electron 8+

0
assets/keep Normal file
View File

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +0,0 @@
best well
better well
deeper deeply
farther far
further far
harder hard
hardest hard

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -89,8 +89,8 @@
</select>
</div>
</modal>
<modal :buttons="false" ref="wordDefinitionViewer" dialogClass="word-definition-viewer">
<word-definition :expression="wordDefinitionLookup" ref="characterPage"></word-definition>
<modal :buttons="false" ref="wordDefinitionViewer" dialogClass="w-100 word-definition-viewer">
<word-definition :expression="wordDefinitionLookup" ref="wordDefinitionLookup"></word-definition>
<template slot="title">
{{wordDefinitionLookup}}
@ -133,7 +133,6 @@
import * as SlimcatImporter from './importer';
import _ from 'lodash';
import { EventBus } from '../chat/preview/event-bus';
import { DefinitionDictionary } from '../learn/dictionary/definition-dictionary';
// import Bluebird from 'bluebird';
// import Connection from '../fchat/connection';
// import Notifications from './notifications';
@ -526,27 +525,23 @@
}
getCleanedWordDefinition(): string {
return DefinitionDictionary.cleanExpression(this.wordDefinitionLookup);
}
async openDefinitionWithDictionary(): Promise<void> {
await electron.remote.shell.openExternal(`https://www.dictionary.com/browse/${encodeURI(this.getCleanedWordDefinition())}`);
(this.$refs.wordDefinitionLookup as any).setMode('dictionary');
}
async openDefinitionWithThesaurus(): Promise<void> {
await electron.remote.shell.openExternal(`https://www.thesaurus.com/browse/${encodeURI(this.getCleanedWordDefinition())}`);
(this.$refs.wordDefinitionLookup as any).setMode('thesaurus');
}
async openDefinitionWithUrbanDictionary(): Promise<void> {
await electron.remote.shell.openExternal(`https://www.urbandictionary.com/define.php?term=${encodeURIComponent(this.getCleanedWordDefinition())}`);
(this.$refs.wordDefinitionLookup as any).setMode('urbandictionary');
}
async openDefinitionWithWikipedia(): Promise<void> {
await electron.remote.shell.openExternal(`https://en.wikipedia.org/wiki/${encodeURI(this.getCleanedWordDefinition())}`);
(this.$refs.wordDefinitionLookup as any).setMode('wikipedia');
}
}
</script>
@ -655,6 +650,8 @@
i {
color: #fadf4b;
text-transform: lowercase;
font-family: monospace;
}
}
@ -667,7 +664,30 @@
i {
color: black;
font-family: serif;
}
}
}
.word-definition-viewer {
.modal-content {
min-height: 60%;
}
.definition-wrapper {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
margin-left: 20px;
margin-right: 20px;
webview {
height: 100%;
padding-bottom: 10px;
}
}
}
</style>

View File

@ -1,39 +1,128 @@
<template>
<div>
<ul v-if="definitions.length > 0">
<li v-for="definition in definitions">
<p><i>({{definition.type}}.)</i> {{definition.definition}}</p>
<small>{{definition.synonyms.join(', ').replace(/_/g, ' ')}}</small>
</li>
</ul>
<div v-else class="error">No definitions found for '{{ expression }}'.</div>
<div class="definition-wrapper">
<webview
:src="getWebUrl()"
webpreferences="autoplayPolicy=no-user-gesture-required,contextIsolation,sandbox,disableDialogs,disableHtmlFullScreenWindowResize,webSecurity,enableWebSQL=no,nodeIntegration=no,nativeWindowOpen=no,nodeIntegrationInWorker=no,nodeIntegrationInSubFrames=no,webviewTag=no"
enableremotemodule="false"
allowpopups="false"
nodeIntegration="false"
id="defintion-preview"
ref="definitionPreview"
class="definition-preview"
></webview>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import { Definition, DefinitionDictionary } from './definition-dictionary';
import electron from 'electron';
import { Component, Prop, Watch } from '@f-list/vue-ts';
// import { EventBus } from '../../chat/preview/event-bus';
import { WebviewTag } from 'electron';
import { Component, Hook, Prop } from '@f-list/vue-ts';
import { EventBusEvent } from '../../chat/preview/event-bus';
import anyAscii from 'any-ascii';
import log from 'electron-log'; //tslint:disable-line:match-default-export-name
// tslint:disable-next-line:ban-ts-ignore
// @ts-ignore
// tslint:disable-next-line:no-submodule-imports ban-ts-ignore match-default-export-name
import mutatorScript from '!!raw-loader!./assets/mutator.raw.js';
const scripts: Record<string, string> = {
mutator: mutatorScript
}
@Component({})
export default class WordDefinition extends Vue {
private wordDef = new DefinitionDictionary(electron.remote.app.getAppPath());
mode: 'dictionary' | 'thesaurus' | 'urbandictionary' | 'wikipedia' = 'dictionary';
@Prop
readonly expression?: string;
public definitions: Definition[] = [];
@Hook('mounted')
mounted(): void {
const webview = this.getWebview();
// @Hook('mounted')
// mounted(): void {
//
// }
webview.addEventListener(
'update-target-url', // 'did-navigate', // 'dom-ready',
(event: EventBusEvent) => {
const js = this.wrapJs(this.getMutator(this.mode));
@Watch('expression')
async onWordChange(newExpression: string): Promise<void> {
this.definitions = await this.wordDef.getDefinition(newExpression);
// tslint:disable-next-line
this.executeJavaScript(js, event);
}
);
}
setMode(mode: 'dictionary' | 'thesaurus' | 'urbandictionary' | 'wikipedia'): void {
this.mode = mode;
}
getWebUrl(): string {
switch(this.mode) {
case 'dictionary':
return `https://www.dictionary.com/browse/${encodeURI(this.getCleanedWordDefinition())}`;
case 'thesaurus':
return `https://www.thesaurus.com/browse/${encodeURI(this.getCleanedWordDefinition())}`;
case 'urbandictionary':
return `https://www.urbandictionary.com/define.php?term=${encodeURIComponent(this.getCleanedWordDefinition())}`;
case 'wikipedia':
return `https://en.m.wikipedia.org/wiki/${encodeURI(this.getCleanedWordDefinition())}`;
}
}
getCleanedWordDefinition(expression = this.expression): string {
return anyAscii(expression || '')
.toLowerCase()
.replace(/[^a-z0-9\-]/g, ' ')
.replace(/ +/g, ' ')
.trim();
}
protected getWebview(): WebviewTag {
return this.$refs.definitionPreview as WebviewTag;
}
protected async executeJavaScript(js: string | undefined, logDetails?: any): Promise<any> {
const webview = this.getWebview();
if (!js) {
log.debug('word-definition.execute-js.missing', { logDetails });
return;
}
try {
const result = await (webview.executeJavaScript(js) as unknown as Promise<any>);
log.debug('word-definition.execute-js.result', result);
return result;
} catch (err) {
log.debug('word-definition.execute-js.error', err);
}
}
protected wrapJs(mutatorJs: string): string {
return `(() => { try { ${mutatorJs} } catch (err) { console.error('Mutator error', err); } })();`;
}
protected getMutator(mode: string): string {
const js = scripts.mutator; // ./assets/mutator.raw.js
return js.replace(/## SITE ##/g, mode);
}
}
</script>

View File

@ -0,0 +1,76 @@
class FChatDefinitionMutator {
mutateDictionary() {
document.querySelectorAll('html')[0].setAttribute('style', 'border: 0 !important; padding: 0 !important; margin: 0 !important;');
document.querySelectorAll('body')[0].setAttribute('style', 'border: 0 !important; padding: 0 !important; margin: 0 !important;');
document.querySelectorAll('.app-base')[0].setAttribute('style', 'padding: 0 !important; margin: 0 !important;');
document.querySelectorAll('header, footer, .serp-nav-button, aside, .sailthru-overlay-container, .bxc, #marketingBanner-right, #marketingBanner-right-button')
.forEach(e => e.setAttribute('style', 'display: none !important'));
const headword = document.querySelector('.entry-headword');
const parent = headword.parentElement.parentElement;
let el = headword.parentElement.nextElementSibling;
while (el) {
const dEl = el;
el = el.nextElementSibling;
parent.removeChild(dEl);
}
}
mutateThesaurus() {
document.querySelectorAll('html')[0].setAttribute('style', 'border: 0 !important; padding: 0 !important; margin: 0 !important;');
document.querySelectorAll('body')[0].setAttribute('style', 'border: 0 !important; padding: 0 !important; margin: 0 !important;');
document.querySelectorAll('.app-base')[0].setAttribute('style', 'padding: 0 !important; margin: 0 !important;');
document.querySelectorAll('header, footer, .serp-nav-button, aside, button, .sailthru-overlay-container, .bxc, #marketingBanner-right, #marketingBanner-right-button')
.forEach(e => e.setAttribute('style', 'display: none !important'));
}
mutateWikipedia() {
document.querySelectorAll('header').forEach(e => e.setAttribute('style', 'display: none !important'));
}
mutateUrbanDictionary() {
document.querySelectorAll('.column, .columns')
.forEach(e => e.setAttribute('style', 'padding: 0 !important'));
document.querySelectorAll('.row')
.forEach(e => e.setAttribute('style', 'max-width: 100% !important'));
document.querySelectorAll('#urban-top-bar, .ad-panel, .panel, .hide-for-large-up, .show-for-large-up, .show-for-medium-up, .pagination-centered, .header, .mug-ad, iframe')
.forEach(e => e.setAttribute('style', 'display: none !important'));
}
run(site) {
switch(site) {
case 'dictionary':
this.mutateDictionary();
break;
case 'thesaurus':
this.mutateThesaurus();
break;
case 'urbandictionary':
this.mutateUrbanDictionary();
break;
case 'wikipedia':
this.mutateWikipedia();
break;
}
}
}
const mutator = new FChatDefinitionMutator();
mutator.run('## SITE ##');

View File

@ -1,81 +0,0 @@
import _ from 'lodash';
import path from 'path';
// tslint:disable-next-line ban-ts-ignore
// @ts-ignore
import anyAscii from 'any-ascii';
// tslint:disable-next-line ban-ts-ignore
// @ts-ignore
import WordNet from './wordnet/wordnet';
export interface Definition {
definition: string;
synonyms: string[];
type: string;
}
export class DefinitionDictionary {
private wordnet: any;
private extendedWords: Record<string, Definition[]> = {};
constructor(basePath: string) {
const dataDir = path.join(basePath, 'assets', 'wordnet-dictionary');
// tslint:disable-next-line:ban-ts-ignore
// @ts-ignore
this.wordnet = new WordNet(
{
dataDir
}
);
}
async getDefinition(expression: string): Promise<Definition[]> {
const exp = DefinitionDictionary.cleanExpression(expression);
const forms = await this.getWordNetValidForms(exp);
const results = await Promise.all(
[
this.getExtendedDefinitions(forms),
this.getWordNetDefinitions(forms)
]
);
return _.flatten(results);
}
private async getExtendedDefinitions(forms: string[]) {
return _.flatten(_.map(forms, (f) => this.extendedWords[f] || []));
}
private async getWordNetValidForms(expression: string): Promise<string[]> {
return [...(await this.wordnet.validFormsAsync(expression)), expression];
}
private async getWordNetDefinitions(forms: string[]): Promise<Definition[]> {
const definitions = await Promise.all(_.map(forms, (f: string) => this.wordnet.lookupAsync(f).catch(() => [])));
return _.map(
_.reverse(_.flatten(definitions)),
(r) => (
{
definition: r.def,
synonyms: r.synonyms,
type: r.pos
} as any as Definition
)
);
}
public static cleanExpression(expression: string): string {
return anyAscii(expression).toLowerCase().replace(/[^a-z0-9\-]/g, ' ').replace(/ +/g, ' ').trim();
}
}

View File

@ -1,79 +0,0 @@
var DataFile, WordNetFile, fs, util,
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
hasProp = {}.hasOwnProperty;
WordNetFile = require('./wordnet_file');
fs = require('fs');
util = require('util');
module.exports = DataFile = (function(superClass) {
extend(DataFile, superClass);
function DataFile(dataDir, name) {
DataFile.__super__.constructor.call(this, dataDir, 'data.' + name);
}
DataFile.prototype.get = function(location, callback) {
var buff, self;
self = this;
buff = new Buffer(4096);
return this.open(function(err, fd) {
if (err != null) {
return callback.call(self, err, null);
}
return this.appendLineChar(fd, location, 0, buff, function(err, line) {
var base, data, definition, element, examples, glossArray, i, j, k, l, len, m, ptrOffset, ptrs, ref, ref1, synonyms, synsetOffset, tokens, wCnt;
if (err != null) {
return callback.call(self, err, null);
}
data = line.split('| ');
tokens = data[0].split(/\s+/);
ptrs = [];
wCnt = parseInt(tokens[3], 16);
synonyms = [];
for (i = j = 0, ref = wCnt - 1; j <= ref; i = j += 1) {
synonyms.push(tokens[4 + i * 2]);
}
ptrOffset = (wCnt - 1) * 2 + 6;
for (i = l = 0, ref1 = parseInt(tokens[ptrOffset], 10) - 1; l <= ref1; i = l += 1) {
base = i * 4 + ptrOffset;
ptrs.push({
pointerSymbol: tokens[base + 1],
synsetOffset: parseInt(tokens[base + 2], 10),
pos: tokens[base + 3],
sourceTarget: tokens[base + 4]
});
}
glossArray = data[1].split("; ");
definition = glossArray[0];
examples = glossArray.slice(1);
for (k = m = 0, len = examples.length; m < len; k = ++m) {
element = examples[k];
examples[k] = examples[k].replace(/\"/g, '').replace(/\s\s+/g, '');
}
synsetOffset = parseInt(tokens[0], 10);
if (synsetOffset !== location) {
return callback.call(self, "Invalid synsetOffset: " + location, null);
}
return callback.call(self, null, {
synsetOffset: parseInt(tokens[0], 10),
lexFilenum: parseInt(tokens[1], 10),
pos: tokens[2],
wCnt: wCnt,
lemma: tokens[4],
synonyms: synonyms,
lexId: tokens[5],
ptrs: ptrs,
gloss: data[1],
def: definition,
exp: examples
});
});
});
};
return DataFile;
})(WordNetFile);

View File

@ -1,143 +0,0 @@
var IndexFile, WordNetFile, fs, util,
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
hasProp = {}.hasOwnProperty;
WordNetFile = require('./wordnet_file');
fs = require('fs');
util = require('util');
module.exports = IndexFile = (function(superClass) {
var _findAt, _findPrevEOL, _getFileSize, _readLine;
extend(IndexFile, superClass);
function IndexFile(dataDir, name) {
IndexFile.__super__.constructor.call(this, dataDir, 'index.' + name);
}
_findPrevEOL = function(self, fd, pos, callback) {
var buff;
buff = new Buffer(1024);
if (pos === 0) {
return callback(null, 0);
} else {
return fs.read(fd, buff, 0, 1, pos, function(err, count) {
if (err != null) {
return callback(err, count);
}
if (buff[0] === 10) {
return callback(null, pos + 1);
} else {
return _findPrevEOL(self, fd, pos - 1, callback);
}
});
}
};
_readLine = function(self, fd, pos, callback) {
var buff;
buff = new Buffer(1024);
return _findPrevEOL(self, fd, pos, function(err, pos) {
if (err != null) {
return callback(err, pos);
}
return self.appendLineChar(fd, pos, 0, buff, callback);
});
};
_findAt = function(self, fd, size, pos, lastPos, adjustment, searchKey, callback, lastKey) {
if (lastPos === pos || pos >= size) {
return callback(null, {
status: 'miss'
});
} else {
return _readLine(self, fd, pos, function(err, line) {
var key, tokens;
if (err != null) {
return callback(err);
}
tokens = line.split(/\s+/);
key = tokens[0];
if (key === searchKey) {
return callback(null, {
status: 'hit',
key: key,
'line': line,
tokens: tokens
});
} else if (adjustment === 1 || key === lastKey) {
return callback(null, {
status: 'miss'
});
} else {
adjustment = Math.ceil(adjustment * 0.5);
if (key < searchKey) {
return _findAt(self, fd, size, pos + adjustment, pos, adjustment, searchKey, callback, key);
} else {
return _findAt(self, fd, size, pos - adjustment, pos, adjustment, searchKey, callback, key);
}
}
});
}
};
_getFileSize = function(path) {
var stat;
stat = fs.statSync(path);
return stat.size;
};
IndexFile.prototype.find = function(searchKey, callback) {
var self;
self = this;
return this.open(function(err, fd) {
var pos, size;
if (err != null) {
return callback(err, null);
}
size = _getFileSize(this.filePath) - 1;
pos = Math.ceil(size / 2);
return _findAt(self, fd, size, pos, null, pos, searchKey, function(err, result) {
return callback.call(self, err, result);
});
});
};
IndexFile.prototype.lookupFromFile = function(word, callback) {
return this.find(word, function(err, record) {
var i, indexRecord, j, k, offsets, ptrs, ref, ref1;
if (err != null) {
return callback.call(this, err, null);
}
indexRecord = null;
if (record.status === 'hit') {
ptrs = [];
offsets = [];
for (i = j = 0, ref = parseInt(record.tokens[3]) - 1; j <= ref; i = j += 1) {
ptrs.push(record.tokens[i]);
}
for (i = k = 0, ref1 = parseInt(record.tokens[2]) - 1; k <= ref1; i = k += 1) {
offsets.push(parseInt(record.tokens[ptrs.length + 6 + i], 10));
}
indexRecord = {
lemma: record.tokens[0],
pos: record.tokens[1],
ptrSymbol: ptrs,
senseCnt: parseInt(record.tokens[ptrs.length + 4], 10),
tagsenseCnt: parseInt(record.tokens[ptrs.length + 5], 10),
synsetOffset: offsets
};
}
return callback.call(this, null, indexRecord);
});
};
IndexFile.prototype.lookup = function(word, callback) {
return this.lookupFromFile(word, callback);
};
return IndexFile;
})(WordNetFile);

View File

@ -1,681 +0,0 @@
var DataFile, IndexFile, LRU, Promise, WordNet, async, fs, path,
slice = [].slice;
IndexFile = require('./index_file');
DataFile = require('./data_file');
async = require('async');
Promise = require('bluebird');
path = require('path');
fs = require('fs');
LRU = require('lru-cache');
WordNet = (function() {
var _forms, _loadExceptions, _validForms, _validFormsWithExceptions, exceptions, forms, tokenDetach, unique;
function WordNet(options) {
var WNdb, e, error;
if (typeof options === 'string') {
options = {
dataDir: options
};
} else {
if (options == null) {
options = {};
}
}
if (options.dataDir == null) {
try {
WNdb = require('wndb-with-exceptions');
} catch (error) {
e = error;
console.error("Please 'npm install wndb-with-exceptions' before using WordNet module or specify a dict directory.");
throw e;
}
options.dataDir = WNdb.path;
}
if (!options.cache) {
this.cache = null;
} else {
if (options.cache === true) {
options.cache = {
max: 2000
};
}
if (typeof options.cache === 'object' && typeof options.cache.get === 'function') {
this.cache = options.cache;
} else {
this.cache = LRU(options.cache);
}
}
this.path = options.dataDir;
this.nounIndex = new IndexFile(this.path, 'noun');
this.verbIndex = new IndexFile(this.path, 'verb');
this.adjIndex = new IndexFile(this.path, 'adj');
this.advIndex = new IndexFile(this.path, 'adv');
this.nounData = new DataFile(this.path, 'noun');
this.verbData = new DataFile(this.path, 'verb');
this.adjData = new DataFile(this.path, 'adj');
this.advData = new DataFile(this.path, 'adv');
this.allFiles = [
{
index: this.nounIndex,
data: this.nounData,
pos: 'n'
}, {
index: this.verbIndex,
data: this.verbData,
pos: 'v'
}, {
index: this.adjIndex,
data: this.adjData,
pos: 'a'
}, {
index: this.advIndex,
data: this.advData,
pos: 'r'
}
];
}
WordNet.prototype.get = function(synsetOffset, pos, callback) {
var dataFile, hit, query, wordnet;
wordnet = this;
if (this.cache) {
query = "get:" + synsetOffset + ":" + pos;
if (hit = wordnet.cache.get(query)) {
if (callback.length === 1) {
return callback.call(wordnet, hit);
} else {
return callback.call(wordnet, null, hit);
}
}
}
dataFile = wordnet.getDataFile(pos);
return dataFile.get(synsetOffset, function(err, result) {
if (query && (err == null)) {
wordnet.cache.set(query, result);
}
if (callback.length === 1) {
return callback.call(wordnet, result);
} else {
return callback.call(wordnet, err, result);
}
});
};
WordNet.prototype.getAsync = function(synsetOffset, pos) {
var wordnet;
wordnet = this;
return new Promise(function(resolve, reject) {
return wordnet.get(synsetOffset, pos, function(err, data) {
if (err != null) {
return reject(err);
} else {
return resolve(data);
}
});
});
};
WordNet.prototype.lookup = function(input, callback) {
var hit, lword, pos, query, ref, selectedFiles, word, wordnet;
wordnet = this;
ref = input.split('#'), word = ref[0], pos = ref[1];
lword = word.toLowerCase().replace(/\s+/g, '_');
if (this.cache) {
query = "lookup:" + input;
if (hit = wordnet.cache.get(query)) {
if (callback.length === 1) {
return callback.call(wordnet, hit);
} else {
return callback.call(wordnet, null, hit);
}
}
}
selectedFiles = !pos ? wordnet.allFiles.slice() : wordnet.allFiles.filter(function(file) {
return file.pos === pos;
});
return wordnet.lookupFromFiles(selectedFiles, [], lword, function(err, results) {
if (err != null) {
return callback.call(wordnet, err);
}
if (query) {
wordnet.cache.set(query, results);
}
if (callback.length === 1) {
return callback.call(wordnet, results);
} else {
return callback.call(wordnet, null, results);
}
});
};
WordNet.prototype.lookupAsync = function(input, callback) {
var wordnet;
wordnet = this;
return new Promise(function(resolve, reject) {
return wordnet.lookup(input, function(err, data) {
if (err != null) {
return reject(err);
} else {
return resolve(data);
}
});
});
};
WordNet.prototype.findSense = function(input, callback) {
var hit, lword, pos, query, ref, selectedFiles, sense, senseNumber, word, wordnet;
wordnet = this;
ref = input.split('#'), word = ref[0], pos = ref[1], senseNumber = ref[2];
if (this.cache) {
query = "findSense:" + input;
if (hit = wordnet.cache.get(query)) {
if (callback.length === 1) {
return callback.call(wordnet, hit);
} else {
return callback.call(wordnet, null, hit);
}
}
}
sense = parseInt(senseNumber);
if (Number.isNaN(sense)) {
throw new Error("Sense number should be an integer");
} else if (sense < 1) {
throw new Error("Sense number should be a positive integer");
}
lword = word.toLowerCase().replace(/\s+/g, '_');
selectedFiles = wordnet.allFiles.filter(function(file) {
return file.pos === pos;
});
return wordnet.lookupFromFiles(selectedFiles, [], lword, function(err, response) {
var result;
if (err != null) {
return callback.call(wordnet, err);
}
result = response[sense - 1];
if (query) {
wordnet.cache.set(query, result);
}
if (callback.length === 1) {
return callback.call(wordnet, result);
} else {
return callback.call(wordnet, null, result);
}
});
};
WordNet.prototype.findSenseAsync = function(input) {
var wordnet;
wordnet = this;
return new Promise(function(resolve, reject) {
return wordnet.findSense(input, function(err, data) {
if (err != null) {
return reject(err);
} else {
return resolve(data);
}
});
});
};
WordNet.prototype.querySense = function(input, callback) {
var hit, pos, query, ref, word, wordnet;
wordnet = this;
ref = input.split('#'), word = ref[0], pos = ref[1];
if (this.cache) {
query = "querySense:" + input;
if (hit = wordnet.cache.get(query)) {
if (callback.length === 1) {
return callback.call(wordnet, hit);
} else {
return callback.call(wordnet, null, hit);
}
}
}
return wordnet.lookup(input, function(err, results) {
var i, sense, senseCounts, senses;
if (err != null) {
return callback.call(wordnet, err);
}
senseCounts = {};
senses = (function() {
var j, len, results1;
results1 = [];
for (i = j = 0, len = results.length; j < len; i = ++j) {
sense = results[i];
pos = sense.pos;
if (pos === 's') {
pos = 'a';
}
if (senseCounts[pos] == null) {
senseCounts[pos] = 1;
}
results1.push(word + "#" + pos + "#" + senseCounts[pos]++);
}
return results1;
})();
if (query) {
wordnet.cache.set(query, senses);
}
if (callback.length === 1) {
return callback.call(wordnet, senses);
} else {
return callback.call(wordnet, null, senses);
}
});
};
WordNet.prototype.querySenseAsync = function(input) {
var wordnet;
wordnet = this;
return new Promise(function(resolve, reject) {
return wordnet.querySense(input, function(err, data) {
if (err != null) {
return reject(err);
} else {
return resolve(data);
}
});
});
};
WordNet.prototype.lookupFromFiles = function(files, results, word, callback) {
var file, wordnet;
wordnet = this;
if (files.length === 0) {
return callback.call(wordnet, null, results);
} else {
file = files.pop();
return file.index.lookup(word, function(err, record) {
if (record) {
return wordnet.pushResults(file.data, results, record.synsetOffset, function() {
return wordnet.lookupFromFiles(files, results, word, callback);
});
} else {
return wordnet.lookupFromFiles(files, results, word, callback);
}
});
}
};
WordNet.prototype.pushResults = function(data, results, offsets, callback) {
var wordnet;
wordnet = this;
if (offsets.length === 0) {
return callback(results);
} else {
return data.get(offsets.pop(), function(err, record) {
results.push(record);
return wordnet.pushResults(data, results, offsets, callback);
});
}
};
WordNet.prototype.loadResultSynonyms = function(synonyms, results, callback) {
var result, wordnet;
wordnet = this;
if (results.length > 0) {
result = results.pop();
return wordnet.loadSynonyms(synonyms, results, result.ptrs, callback);
} else {
return callback(synonyms);
}
};
WordNet.prototype.loadSynonyms = function(synonyms, results, ptrs, callback) {
var ptr, wordnet;
wordnet = this;
if (ptrs.length > 0) {
ptr = ptrs.pop();
return this.get(ptr.synsetOffset, ptr.pos, function(result) {
synonyms.push(result);
return wordnet.loadSynonyms(synonyms, results, ptrs, callback);
});
} else {
return wordnet.loadResultSynonyms(synonyms, results, callback);
}
};
WordNet.prototype.lookupSynonyms = function(word, callback) {
var wordnet;
wordnet = this;
return wordnet.lookup(word, function(results) {
return wordnet.loadResultSynonyms([], results, callback);
});
};
WordNet.prototype.getSynonyms = function() {
var callback, pos, synsetOffset, wordnet;
wordnet = this;
callback = arguments[2] ? arguments[2] : arguments[1];
pos = arguments[0].pos ? arguments[0].pos : arguments[1];
synsetOffset = arguments[0].synsetOffset ? arguments[0].synsetOffset : arguments[0];
return this.get(synsetOffset, pos, function(result) {
return wordnet.loadSynonyms([], [], result.ptrs, callback);
});
};
WordNet.prototype.getDataFile = function(pos) {
switch (pos) {
case 'n':
return this.nounData;
case 'v':
return this.verbData;
case 'a':
case 's':
return this.adjData;
case 'r':
return this.advData;
}
};
exceptions = [
{
name: "noun.exc",
pos: 'n'
}, {
name: "verb.exc",
pos: 'v'
}, {
name: "adj.exc",
pos: 'a'
}, {
name: "adv.exc",
pos: 'r'
}
];
_loadExceptions = function(wordnet, callback) {
var loadFile;
WordNet.prototype.exceptions = 'pending';
loadFile = function(exception, callback) {
var fullPath;
fullPath = path.join(wordnet.path, exception.name);
return fs.readFile(fullPath, function(err, data) {
var j, len, line, lines, ref, temp, term1, term2;
if (err) {
return callback(err);
}
temp = {};
lines = data.toString().split("\n");
for (j = 0, len = lines.length; j < len; j++) {
line = lines[j];
if (line.length > 0) {
ref = line.split(' '), term1 = ref[0], term2 = 2 <= ref.length ? slice.call(ref, 1) : [];
if (temp[term1] == null) {
temp[term1] = [];
}
Array.prototype.push.apply(temp[term1], term2);
}
}
return callback(null, {
pos: exception.pos,
data: temp
});
});
};
return async.map(exceptions, loadFile, function(err, results) {
var j, len, result;
exceptions = {};
for (j = 0, len = results.length; j < len; j++) {
result = results[j];
exceptions[result.pos] = result.data;
}
WordNet.prototype.exceptions = exceptions;
return callback();
});
};
WordNet.prototype.close = function() {
this.nounIndex.close();
this.verbIndex.close();
this.adjIndex.close();
this.advIndex.close();
this.nounData.close();
this.verbData.close();
this.adjData.close();
return this.advData.close();
};
unique = function(a) {
var found;
found = {};
return a.filter(function(item) {
if (found[item]) {
return false;
} else {
return found[item] = true;
}
});
};
tokenDetach = function(string) {
var detach, length, pos, ref, sense, word;
ref = string.split('#'), word = ref[0], pos = ref[1], sense = ref[2];
detach = [word];
length = word.length;
switch (pos) {
case 'n':
if (word.endsWith("s")) {
detach.push(word.substring(0, length - 1));
}
if (word.endsWith("ses")) {
detach.push(word.substring(0, length - 2));
}
if (word.endsWith("xes")) {
detach.push(word.substring(0, length - 2));
}
if (word.endsWith("zes")) {
detach.push(word.substring(0, length - 2));
}
if (word.endsWith("ches")) {
detach.push(word.substring(0, length - 2));
}
if (word.endsWith("shes")) {
detach.push(word.substring(0, length - 2));
}
if (word.endsWith("men")) {
detach.push(word.substring(0, length - 3) + "man");
}
if (word.endsWith("ies")) {
detach.push(word.substring(0, length - 3) + "y");
}
break;
case 'v':
if (word.endsWith("s")) {
detach.push(word.substring(0, length - 1));
}
if (word.endsWith("ies")) {
detach.push(word.substring(0, length - 3) + "y");
}
if (word.endsWith("es")) {
detach.push(word.substring(0, length - 2));
}
if (word.endsWith("ed")) {
detach.push(word.substring(0, length - 1));
}
if (word.endsWith("ed")) {
detach.push(word.substring(0, length - 2));
}
if (word.endsWith("ing")) {
detach.push(word.substring(0, length - 3) + "e");
}
if (word.endsWith("ing")) {
detach.push(word.substring(0, length - 3));
}
break;
case 'r':
if (word.endsWith("er")) {
detach.push(word.substring(0, length - 2));
}
if (word.endsWith("er")) {
detach.push(word.substring(0, length - 1));
}
if (word.endsWith("est")) {
detach.push(word.substring(0, length - 3));
}
if (word.endsWith("est")) {
detach.push(word.substring(0, length - 2));
}
}
return unique(detach);
};
_forms = function(wordnet, word, pos) {
var colloc, exception, forms, i, index, j, lword, ref, ref1, rtn, token, tokens;
lword = word.toLowerCase();
exception = (ref = wordnet.exceptions[pos]) != null ? ref[lword] : void 0;
if (exception) {
return [word].concat(exception);
}
tokens = word.split(/[ _]/g);
if (tokens.length === 1) {
return tokenDetach(tokens[0] + "#" + pos);
}
forms = tokens.map(function(token) {
return _forms(wordnet, token, pos);
});
rtn = [];
index = (function() {
var j, len, results1;
results1 = [];
for (j = 0, len = tokens.length; j < len; j++) {
token = tokens[j];
results1.push(0);
}
return results1;
})();
while (true) {
colloc = forms[0][index[0]];
for (i = j = 1, ref1 = tokens.length - 1; 1 <= ref1 ? j <= ref1 : j >= ref1; i = 1 <= ref1 ? ++j : --j) {
colloc = colloc + '_' + forms[i][index[i]];
}
rtn.push(colloc);
i = 0;
while (i < tokens.length) {
index[i] = index[i] + 1;
if (index[i] < forms[i].length) {
break;
} else {
index[i] = 0;
}
i = i + 1;
}
if (i >= tokens.length) {
break;
}
}
return rtn;
};
forms = function(wordnet, string) {
var element, j, len, pos, ref, results1, rtn, sense, word;
ref = string.split('#'), word = ref[0], pos = ref[1], sense = ref[2];
rtn = _forms(wordnet, word, pos);
results1 = [];
for (j = 0, len = rtn.length; j < len; j++) {
element = rtn[j];
results1.push(element + "#" + pos);
}
return results1;
};
_validForms = function(wordnet, string, callback) {
var eachFn, filteredResults, pos, possibleForms, reducer, ref, sense, word;
ref = string.split('#'), word = ref[0], pos = ref[1], sense = ref[2];
if (!pos) {
reducer = function(previous, current, next) {
return _validForms(wordnet, string + "#" + current, function(err, value) {
if (value === void 0) {
return next(null, previous);
} else {
return next(null, previous.concat(value));
}
});
};
return async.reduce(['n', 'v', 'a', 'r'], [], reducer, function(err, result) {
return callback(null, result);
});
} else {
possibleForms = forms(wordnet, word + "#" + pos);
filteredResults = [];
eachFn = function(term, done) {
return wordnet.lookup(term, function(err, data) {
if (err != null) {
return done(err);
}
if (data.length > 0) {
filteredResults.push(term);
}
return done();
});
};
return async.each(possibleForms, eachFn, function(err) {
return callback(err, filteredResults);
});
}
};
_validFormsWithExceptions = function(wordnet, string, callback) {
if (wordnet.exceptions === void 0) {
return _loadExceptions(wordnet, function() {
return _validFormsWithExceptions(wordnet, string, callback);
});
} else if (wordnet.exceptions === 'pending') {
return setImmediate(_validFormsWithExceptions, wordnet, string, callback);
} else {
return _validForms(wordnet, string, callback);
}
};
WordNet.prototype.validForms = function(string, callback) {
var hit, query, wordnet;
wordnet = this;
if (this.cache) {
query = "validForms:" + string;
if (hit = wordnet.cache.get(query)) {
if (callback.length === 1) {
return callback.call(wordnet, hit);
} else {
return callback.call(wordnet, null, hit);
}
}
}
return _validFormsWithExceptions(this, string, function(err, result) {
if (query) {
wordnet.cache.set(query, result);
}
if (callback.length === 1) {
return callback.call(wordnet, result);
} else {
return callback.call(wordnet, null, result);
}
});
};
WordNet.prototype.validFormsAsync = function(string) {
return new Promise((function(_this) {
return function(resolve, reject) {
return _this.validForms(string, function(err, data) {
if (err != null) {
return reject(err);
} else {
return resolve(data);
}
});
};
})(this));
};
return WordNet;
})();
module.exports = WordNet;

View File

@ -1,64 +0,0 @@
var WordNetFile, fs, path, util;
fs = require('fs');
path = require('path');
util = require('util');
module.exports = WordNetFile = (function() {
function WordNetFile(dataDir, fileName) {
this.dataDir = dataDir;
this.fileName = fileName;
this.filePath = path.join(this.dataDir, this.fileName);
}
WordNetFile.prototype.open = function(callback) {
var filePath, self;
self = this;
if (this.fd) {
return callback.call(self, null, this.fd);
}
filePath = this.filePath;
return fs.open(filePath, 'r', null, (function(_this) {
return function(err, fd) {
if (err != null) {
return callback.call(self, err, null);
}
_this.fd = fd;
return callback.call(self, err, fd);
};
})(this));
};
WordNetFile.prototype.close = function() {
if (this.fd != null) {
fs.close(this.fd);
return delete this.fd;
}
};
WordNetFile.prototype.appendLineChar = function(fd, pos, buffPos, buff, callback) {
var length, self, space;
self = this;
length = buff.length;
space = length - buffPos;
return fs.read(fd, buff, buffPos, space, pos, function(err, count, buffer) {
var i, j, newBuff, ref;
if (err != null) {
return callback.call(self, err, null);
}
for (i = j = 0, ref = count - 1; 0 <= ref ? j <= ref : j >= ref; i = 0 <= ref ? ++j : --j) {
if (buff[i] === 10) {
return callback.call(self, null, buff.slice(0, i).toString('ASCII'));
}
}
newBuff = new Buffer(length * 2);
buff.copy(newBuff, 0, 0, length);
return self.appendLineChar(fd, pos + length, length, newBuff, callback);
});
};
return WordNetFile;
})();

View File

@ -31,9 +31,7 @@
"extract-loader": "^5.1.0",
"file-loader": "^6.2.0",
"lodash": "^4.17.20",
"lru-cache": "^2.5.0",
"node-sass": "^4.14.1",
"node-wordnet": "^0.1.12",
"optimize-css-assets-webpack-plugin": "^5.0.4",
"qs": "^6.9.4",
"raven-js": "^3.27.2",
@ -51,8 +49,7 @@
"vue": "^2.6.12",
"vue-loader": "^15.9.4",
"vue-template-compiler": "^2.6.12",
"webpack": "^5.3.2",
"wndb-with-exceptions": "^3.0.2"
"webpack": "^5.3.2"
},
"dependencies": {
"@cliqz/adblocker-electron": "^1.18.3",

View File

@ -1446,11 +1446,6 @@ block-stream@*:
dependencies:
inherits "~2.0.0"
bluebird@^2.6.0:
version "2.11.0"
resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-2.11.0.tgz#534b9033c022c9579c56ba3b3e5a5caafbb650e1"
integrity sha1-U0uQM8AiyVecVro7Plpcqvu2UOE=
bluebird@^3.1.1, bluebird@^3.5.0, bluebird@^3.7.2:
version "3.7.2"
resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f"
@ -2809,11 +2804,6 @@ es6-error@^4.1.1:
resolved "https://registry.yarnpkg.com/es6-error/-/es6-error-4.1.1.tgz#9e3af407459deed47e9a91f9b885a84eb05c561d"
integrity sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==
es6-shim@^0.22.1:
version "0.22.2"
resolved "https://registry.yarnpkg.com/es6-shim/-/es6-shim-0.22.2.tgz#4afe7c54bb92b178e5d464dd5d9c31c5742d7521"
integrity sha1-Sv58VLuSsXjl1GTdXZwxxXQtdSE=
escalade@^3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
@ -4470,11 +4460,6 @@ lowercase-keys@^2.0.0:
resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479"
integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==
lru-cache@^2.5.0:
version "2.7.3"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-2.7.3.tgz#6d4524e8b955f95d4f5b58851ce21dd72fb4e952"
integrity sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=
lru-cache@^4.0.1, lru-cache@^4.1.2:
version "4.1.5"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd"
@ -4946,16 +4931,6 @@ node-sass@^4.14.1:
stdout-stream "^1.4.0"
"true-case-path" "^1.0.2"
node-wordnet@^0.1.12:
version "0.1.12"
resolved "https://registry.yarnpkg.com/node-wordnet/-/node-wordnet-0.1.12.tgz#62b0568f5dfc188bd02d136cf730832952fa9c1b"
integrity sha1-YrBWj138GIvQLRNs9zCDKVL6nBs=
dependencies:
async "^0.9.0"
bluebird "^2.6.0"
es6-shim "^0.22.1"
lru-cache "^2.5.0"
noop-logger@^0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/noop-logger/-/noop-logger-0.1.1.tgz#94a2b1633c4f1317553007d8966fd0e841b6a4c2"
@ -6982,18 +6957,6 @@ tar@^6.0.2, tar@^6.0.5:
mkdirp "^1.0.3"
yallist "^4.0.0"
tar@latest:
version "6.1.0"
resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.0.tgz#d1724e9bcc04b977b18d5c573b333a2207229a83"
integrity sha512-DUCttfhsnLCjwoDoFcI+B2iJgYa93vBnDUATYEeRx6sntCTdN01VnqsIuTlALXla/LWooNg0yEGeB+Y8WdFxGA==
dependencies:
chownr "^2.0.0"
fs-minipass "^2.0.0"
minipass "^3.0.0"
minizlib "^2.1.1"
mkdirp "^1.0.3"
yallist "^4.0.0"
temp@^0.9.0:
version "0.9.4"
resolved "https://registry.yarnpkg.com/temp/-/temp-0.9.4.tgz#cd20a8580cb63635d0e4e9d4bd989d44286e7620"
@ -7537,13 +7500,6 @@ wide-align@^1.1.0:
dependencies:
string-width "^1.0.2 || 2"
wndb-with-exceptions@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/wndb-with-exceptions/-/wndb-with-exceptions-3.0.2.tgz#7048c1be7e0d13d231a51e408e0b37426000bcbb"
integrity sha1-cEjBvn4NE9IxpR5Ajgs3QmAAvLs=
dependencies:
tar latest
worker-rpc@^0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/worker-rpc/-/worker-rpc-0.1.1.tgz#cb565bd6d7071a8f16660686051e969ad32f54d5"