This commit is contained in:
Alex Yatskov 2016-12-17 18:45:19 -08:00
parent 5c94923264
commit d98f4566bc
8 changed files with 74 additions and 78 deletions

View File

@ -117,15 +117,15 @@ class Database {
} }
const tagMeta = this.tagMetaCache[dictionary] = {}; const tagMeta = this.tagMetaCache[dictionary] = {};
const promise = this.db.tagMeta.where('dictionary').equals(dictionary).each(row => { promises.push(
this.db.tagMeta.where('dictionary').equals(dictionary).each(row => {
tagMeta[row.tag] = { tagMeta[row.tag] = {
category: row.category, category: row.category,
notes: row.notes, notes: row.notes,
order: row.order order: row.order
}; };
}); })
);
promises.push(promise);
} }
return Promise.all(promises).then(() => this.tagMetaCache); return Promise.all(promises).then(() => this.tagMetaCache);

View File

@ -18,22 +18,22 @@
class Deinflection { class Deinflection {
constructor(term, tags=[], rule='') { constructor(term, rules=[], reason='') {
this.children = []; this.children = [];
this.term = term; this.term = term;
this.tags = tags; this.rules = rules;
this.rule = rule; this.reason = reason;
} }
validate(validator) { validate(validator) {
return validator(this.term).then(sets => { return validator(this.term).then(sets => {
for (const tags of sets) { for (const rules of sets) {
if (this.tags.length === 0) { if (this.rules.length === 0) {
return true; return true;
} }
for (const tag of this.tags) { for (const rule of this.rules) {
if (tags.includes(tag)) { if (rules.includes(rule)) {
return true; return true;
} }
} }
@ -43,19 +43,19 @@ class Deinflection {
}); });
} }
deinflect(validator, rules) { deinflect(validator, reasons) {
const promises = [ const promises = [
this.validate(validator).then(valid => { this.validate(validator).then(valid => {
const child = new Deinflection(this.term, this.tags); const child = new Deinflection(this.term, this.rules);
this.children.push(child); this.children.push(child);
}) })
]; ];
for (const rule in rules) { for (const reason in reasons) {
for (const variant of rules[rule]) { for (const variant of reasons[reason]) {
let allowed = this.tags.length === 0; let allowed = this.rules.length === 0;
for (const tag of this.tags) { for (const rule of this.rules) {
if (variant.tagsIn.includes(tag)) { if (variant.rulesIn.includes(rule)) {
allowed = true; allowed = true;
break; break;
} }
@ -70,9 +70,9 @@ class Deinflection {
continue; continue;
} }
const child = new Deinflection(term, variant.tagsOut, rule); const child = new Deinflection(term, variant.rulesOut, reason);
promises.push( promises.push(
child.deinflect(validator, rules).then(valid => { child.deinflect(validator, reasons).then(valid => {
if (valid) { if (valid) {
this.children.push(child); this.children.push(child);
} }
@ -88,14 +88,14 @@ class Deinflection {
gather() { gather() {
if (this.children.length === 0) { if (this.children.length === 0) {
return [{root: this.term, tags: this.tags, rules: []}]; return [{root: this.term, rules: this.rules, reasons: []}];
} }
const paths = []; const paths = [];
for (const child of this.children) { for (const child of this.children) {
for (const path of child.gather()) { for (const path of child.gather()) {
if (this.rule.length > 0) { if (this.reason.length > 0) {
path.rules.push(this.rule); path.reasons.push(this.reason);
} }
path.source = this.term; path.source = this.term;
@ -110,15 +110,15 @@ class Deinflection {
class Deinflector { class Deinflector {
constructor() { constructor() {
this.rules = {}; this.reasons = {};
} }
setRules(rules) { setReasons(reasons) {
this.rules = rules; this.reasons = reasons;
} }
deinflect(term, validator) { deinflect(term, validator) {
const node = new Deinflection(term); const node = new Deinflection(term);
return node.deinflect(validator, this.rules).then(success => success ? node.gather() : []); return node.deinflect(validator, this.reasons).then(success => success ? node.gather() : []);
} }
} }

View File

@ -66,11 +66,11 @@ templates['kanji.html'] = template({"1":function(container,depth0,helpers,partia
var helper, alias1=depth0 != null ? depth0 : {}, alias2=helpers.helperMissing, alias3="function", alias4=container.escapeExpression; var helper, alias1=depth0 != null ? depth0 : {}, alias2=helpers.helperMissing, alias3="function", alias4=container.escapeExpression;
return " <span class=\"tag tag-" return " <span class=\"tag tag-"
+ alias4(((helper = (helper = helpers["class"] || (depth0 != null ? depth0["class"] : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"class","hash":{},"data":data}) : helper))) + alias4(((helper = (helper = helpers.category || (depth0 != null ? depth0.category : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"category","hash":{},"data":data}) : helper)))
+ "\" title=\"" + "\" title=\""
+ alias4(((helper = (helper = helpers.desc || (depth0 != null ? depth0.desc : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"desc","hash":{},"data":data}) : helper))) + alias4(((helper = (helper = helpers.notes || (depth0 != null ? depth0.notes : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"notes","hash":{},"data":data}) : helper)))
+ "\">" + "\">"
+ alias4(((helper = (helper = helpers.name || (depth0 != null ? depth0.name : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"name","hash":{},"data":data}) : helper))) + alias4(((helper = (helper = helpers.tag || (depth0 != null ? depth0.tag : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"tag","hash":{},"data":data}) : helper)))
+ "</span>\n"; + "</span>\n";
},"8":function(container,depth0,helpers,partials,data) { },"8":function(container,depth0,helpers,partials,data) {
return " <li><span>" return " <li><span>"
@ -190,11 +190,11 @@ templates['term.html'] = template({"1":function(container,depth0,helpers,partial
var helper, alias1=depth0 != null ? depth0 : {}, alias2=helpers.helperMissing, alias3="function", alias4=container.escapeExpression; var helper, alias1=depth0 != null ? depth0 : {}, alias2=helpers.helperMissing, alias3="function", alias4=container.escapeExpression;
return " <span class=\"tag tag-" return " <span class=\"tag tag-"
+ alias4(((helper = (helper = helpers["class"] || (depth0 != null ? depth0["class"] : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"class","hash":{},"data":data}) : helper))) + alias4(((helper = (helper = helpers.category || (depth0 != null ? depth0.category : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"category","hash":{},"data":data}) : helper)))
+ "\" title=\"" + "\" title=\""
+ alias4(((helper = (helper = helpers.desc || (depth0 != null ? depth0.desc : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"desc","hash":{},"data":data}) : helper))) + alias4(((helper = (helper = helpers.notes || (depth0 != null ? depth0.notes : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"notes","hash":{},"data":data}) : helper)))
+ "\">" + "\">"
+ alias4(((helper = (helper = helpers.name || (depth0 != null ? depth0.name : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"name","hash":{},"data":data}) : helper))) + alias4(((helper = (helper = helpers.tag || (depth0 != null ? depth0.tag : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"tag","hash":{},"data":data}) : helper)))
+ "</span>\n"; + "</span>\n";
},"15":function(container,depth0,helpers,partials,data) { },"15":function(container,depth0,helpers,partials,data) {
return " <li><span>" return " <li><span>"

View File

@ -20,7 +20,7 @@
class Translator { class Translator {
constructor() { constructor() {
this.loaded = false; this.loaded = false;
this.tagMeta = null; this.ruleMeta = null;
this.database = new Database(); this.database = new Database();
this.deinflector = new Deinflector(); this.deinflector = new Deinflector();
} }
@ -31,21 +31,21 @@ class Translator {
} }
const promises = [ const promises = [
loadJsonInt('bg/data/rules.json'), loadJsonInt('bg/data/reasons.json'),
this.database.prepare() this.database.prepare()
]; ];
return Promise.all(promises).then(([rules]) => { return Promise.all(promises).then(([reasons]) => {
this.deinflector.setRules(rules); this.deinflector.setReasons(reasons);
this.loaded = true; this.loaded = true;
}); });
} }
findTerm(text, dictionaries, enableSoftKatakanaSearch) { findTerm(text, dictionaries, enableSoftKatakanaSearch) {
return this.findTermGroups(text, dictionaries).then(groups => { return this.findDeinflectGroups(text, dictionaries).then(groups => {
const textHiragana = wanakana._katakanaToHiragana(text); const textHiragana = wanakana._katakanaToHiragana(text);
if (text !== textHiragana && enableSoftKatakanaSearch) { if (text !== textHiragana && enableSoftKatakanaSearch) {
return this.findTermGroups(textHiragana, dictionaries).then(groupsHiragana => { return this.findDeinflectGroups(textHiragana, dictionaries).then(groupsHiragana => {
for (const key in groupsHiragana) { for (const key in groupsHiragana) {
groups[key] = groups[key] || groupsHiragana[key]; groups[key] = groups[key] || groupsHiragana[key];
} }
@ -87,25 +87,27 @@ class Translator {
return Promise.all(promises).then(sets => this.processKanji(sets.reduce((a, b) => a.concat(b), []))); return Promise.all(promises).then(sets => this.processKanji(sets.reduce((a, b) => a.concat(b), [])));
} }
findTermGroups(text, dictionaries) { findDeinflectGroups(text, dictionaries) {
const deinflectGroups = {}; const deinflectGroups = {};
const deinflectPromises = []; const deinflectPromises = [];
for (let i = text.length; i > 0; --i) { for (let i = text.length; i > 0; --i) {
deinflectPromises.push( deinflectPromises.push(
this.deinflector.deinflect(text.slice(0, i), term => { this.deinflector.deinflect(text.slice(0, i), term => {
return this.database.findTerm(term, dictionaries).then(definitions => definitions.map(definition => definition.tags)); return this.database.findTerm(term, dictionaries).then(definitions => definitions.map(definition => definition.rules));
}).then(deinflects => { }).then(deinflects => {
const processPromises = []; const processPromises = [];
for (const deinflect of deinflects) { for (const deinflect of deinflects) {
processPromises.push(this.processTerm( processPromises.push(
this.processDeinflection(
deinflectGroups, deinflectGroups,
deinflect.source, deinflect.source,
deinflect.tags,
deinflect.rules, deinflect.rules,
deinflect.reasons,
deinflect.root, deinflect.root,
dictionaries dictionaries
)); )
);
} }
return Promise.all(processPromises); return Promise.all(processPromises);
@ -116,16 +118,16 @@ class Translator {
return Promise.all(deinflectPromises).then(() => deinflectGroups); return Promise.all(deinflectPromises).then(() => deinflectGroups);
} }
processTerm(groups, source, tags, rules, root, dictionaries) { processDeinflection(groups, source, rules, reasons, root, dictionaries) {
return this.database.findTerm(root, dictionaries).then(definitions => { return this.database.findTerm(root, dictionaries).then(definitions => {
for (const definition of definitions) { for (const definition of definitions) {
if (definition.id in groups) { if (definition.id in groups) {
continue; continue;
} }
let matched = tags.length === 0; let matched = rules.length === 0;
for (const tag of tags) { for (const rule of rules) {
if (definition.tags.includes(tag)) { if (definition.rules.includes(rule)) {
matched = true; matched = true;
break; break;
} }
@ -138,26 +140,20 @@ class Translator {
const tagItems = []; const tagItems = [];
for (const tag of definition.tags) { for (const tag of definition.tags) {
const tagItem = { const tagItem = {
name: tag, tag,
class: 'default', category: 'default',
order: Number.MAX_SAFE_INTEGER, order: Number.MAX_SAFE_INTEGER,
score: 0, notes: ''
desc: definition.entities[tag] || '',
}; };
applyTagMeta(tagItem, this.tagMeta); applyTagMeta(tagItem, definition.tagMeta);
tagItems.push(tagItem); tagItems.push(tagItem);
} }
let score = 0;
for (const tagItem of tagItems) {
score += tagItem.score;
}
groups[definition.id] = { groups[definition.id] = {
score,
source, source,
rules, reasons,
score: definition.score,
expression: definition.expression, expression: definition.expression,
reading: definition.reading, reading: definition.reading,
glossary: definition.glossary, glossary: definition.glossary,
@ -172,13 +168,13 @@ class Translator {
const tagItems = []; const tagItems = [];
for (const tag of definition.tags) { for (const tag of definition.tags) {
const tagItem = { const tagItem = {
name: tag, tag,
class: 'default', category: 'default',
order: Number.MAX_SAFE_INTEGER, order: Number.MAX_SAFE_INTEGER,
desc: '', notes: ''
}; };
applyTagMeta(tagItem, this.tagMeta); applyTagMeta(tagItem, definition.tagMeta);
tagItems.push(tagItem); tagItems.push(tagItem);
} }

View File

@ -84,8 +84,8 @@ function sortTermDefs(definitions) {
return 1; return 1;
} }
const rl1 = v1.rules.length; const rl1 = v1.reasons.length;
const rl2 = v2.rules.length; const rl2 = v2.reasons.length;
if (rl1 < rl2) { if (rl1 < rl2) {
return -1; return -1;
} else if (rl1 > rl2) { } else if (rl1 > rl2) {

View File

@ -30,7 +30,7 @@
<div class="kanji-tags"> <div class="kanji-tags">
{{#each tags}} {{#each tags}}
<span class="tag tag-{{class}}" title="{{desc}}">{{name}}</span> <span class="tag tag-{{category}}" title="{{notes}}">{{tag}}</span>
{{/each}} {{/each}}
</div> </div>

View File

@ -23,7 +23,7 @@
<div class="term-tags"> <div class="term-tags">
{{#each tags}} {{#each tags}}
<span class="tag tag-{{class}}" title="{{desc}}">{{name}}</span> <span class="tag tag-{{category}}" title="{{notes}}">{{tag}}</span>
{{/each}} {{/each}}
</div> </div>