aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/api.ts4
-rw-r--r--core/http/client.ts4
-rw-r--r--core/http/server.ts1
-rw-r--r--core/raw/api.ts14
-rw-r--r--db/db.ts28
-rw-r--r--examples/readme.md17
-rw-r--r--examples/sentence-word-lookup.ts23
-rw-r--r--language/parser.ts23
-rw-r--r--main.ts11
-rw-r--r--test/reading/test.ts3
10 files changed, 80 insertions, 48 deletions
diff --git a/core/api.ts b/core/api.ts
index 0891081..017e131 100644
--- a/core/api.ts
+++ b/core/api.ts
@@ -7,8 +7,8 @@ import { ParseResult } from "../language/types.ts";
* swapped easily.
*/
export default abstract class API {
- /** @summary prepare API client */
- abstract prepare(): Promise<void>;
+ /** @summary resolved when ready */
+ abstract ready: Promise<void>;
/** @summary parse sentence */
abstract parseSentence(input: string): Promise<ParseResult>;
diff --git a/core/http/client.ts b/core/http/client.ts
index a77b616..365aa76 100644
--- a/core/http/client.ts
+++ b/core/http/client.ts
@@ -1,6 +1,5 @@
import "../../util/array.ts";
-import { ParseResult } from "../../language/types.ts";
import API from "../api.ts";
import { ConnectionProps, ConnectionPropsDefault } from "./props.ts";
import { APIRequest, APIRequestParseSentence, APIResponseParseSentence } from "./types.ts";
@@ -13,13 +12,12 @@ import { APIRequest, APIRequestParseSentence, APIResponseParseSentence } from ".
*/
export default class YomikunRemoteAPIClient implements API {
private props: ConnectionProps;
+ ready: Promise<void> = Promise.resolve();
constructor(options?: ConnectionProps) {
this.props = { ...ConnectionPropsDefault, ...options };
}
- async prepare() { }
-
private async request(details: APIRequest) {
var response = await fetch(`http://${this.props.host}:${this.props.port}`, {
method: "POST",
diff --git a/core/http/server.ts b/core/http/server.ts
index b5d6c13..1af8d25 100644
--- a/core/http/server.ts
+++ b/core/http/server.ts
@@ -2,7 +2,6 @@ import { serve } from "https://deno.land/std@0.192.0/http/server.ts";
import "../../util/string.ts";
-import { ParseResult } from "../../language/types.ts";
import YomikunRAWAPI from "../raw/api.ts";
import { ConnectionProps, ConnectionPropsDefault } from "./props.ts";
import { APIRequest, APIRequestParseSentence, APIResponseParseSentence } from "./types.ts";
diff --git a/core/raw/api.ts b/core/raw/api.ts
index 2d29eed..06db022 100644
--- a/core/raw/api.ts
+++ b/core/raw/api.ts
@@ -5,6 +5,7 @@ import YomikunError from "../../util/error.ts";
/** @summary internal Yomikun API client (DO NOT USE DIRECTLY) */
export default class YomikunRAWAPI implements API {
private _parser: Parser;
+ ready: Promise<void>;
constructor() {
if (this.constructor === YomikunRAWAPI) {
@@ -12,16 +13,15 @@ export default class YomikunRAWAPI implements API {
}
this._parser = new Parser();
- }
- async prepare() {
- await Promise.all([
- this._parser.prepare(),
- ]);
- }
+ this.ready = new Promise(async resolve => {
+ await this._parser.ready;
+ resolve();
+ })
+ }
async parseSentence(input: string) {
- return this._parser.parse(input);
+ return await this._parser.parse(input);
}
};
diff --git a/db/db.ts b/db/db.ts
index d5a2b76..5605f40 100644
--- a/db/db.ts
+++ b/db/db.ts
@@ -3,7 +3,6 @@ import * as path from 'https://deno.land/std@0.102.0/path/mod.ts';
import { TokenTags } from "../language/tags.ts";
import "../util/string.ts";
-import YomikunError from "../util/error.ts";
export interface DBDictInfo {
id: number;
@@ -49,14 +48,15 @@ interface DBFindResult {
*/
export default class DB {
private connection: Database;
- public ready: boolean = false;
+ public ready: Promise<void>;
+ private here = path.dirname(path.fromFileUrl(import.meta.url));
private paths = {
db: {
- dict: path.resolve('db', 'dict.db'),
- user: path.resolve('db', 'user.db'),
+ dict: path.resolve(this.here, 'dict.db'),
+ user: path.resolve(this.here, 'user.db'),
},
query: {
- find: path.resolve('db', 'find.sql'),
+ find: path.resolve(this.here, 'find.sql'),
},
} as const;
private statement: {
@@ -68,25 +68,23 @@ export default class DB {
this.connection = new Database(":memory:", { create: false });
this.statement = {
attach: this.connection.prepare("attach database ? as ?"),
- queryTerm: this.connection.prepare(""), // initialized in prepare()
+ queryTerm: this.connection.prepare(""),
};
this.attach(this.paths.db.dict, 'dict');
this.attach(this.paths.db.user, 'user');
+ this.ready = new Promise<void>(async resolve => {
+ const statement = await Deno.readTextFile(this.paths.query.find);
+ this.statement.queryTerm = this.connection.prepare(statement);
+ resolve();
+ });
}
private attach(dbPath: string, alias?: string) {
this.statement.attach.run(dbPath, alias);
}
- async prepare() {
- const statement = await Deno.readTextFile(this.paths.query.find);
- this.statement.queryTerm = this.connection.prepare(statement);
- this.ready = true;
- }
-
- findTerm(term: string): FindResult[] {
- if (!this.ready) throw new YomikunError("DB not ready yet, call `async DB::prepare()` first");
-
+ async findTerm(term: string): Promise<FindResult[]> {
+ await this.ready;
var results = this.statement.queryTerm.all({ term }) as unknown as DBFindResult[];
var terms: FindResult[] = results?.map(term => {
if (term.rules == null) term.rules = "";
diff --git a/examples/readme.md b/examples/readme.md
new file mode 100644
index 0000000..9eb8760
--- /dev/null
+++ b/examples/readme.md
@@ -0,0 +1,17 @@
+# API Examples
+
+## **ALL OF THESE EXAMPLES ARE CURRENTLY NOT WORKING, AND ARE USED TO MODEL THE API UNTIL THEY WORK**
+
+~This folder contains API examples. These files show some common workflows
+using the Yomikun API.~
+
+Examples (checked = working):
+
+- [ ] Lookup a word in a sentence
+- [ ] Get furigana in HTML for a sentence
+- [ ] Correct the reading of a word (because of ambiguous word boundries) by inserting a break
+- [ ] Login as a regular user and ignore an expression
+- [ ] Login as root and import a dictionary from a local file
+- [ ] Series-specific search with a lot of jargon
+- [ ] Lookup kanji details of a word
+
diff --git a/examples/sentence-word-lookup.ts b/examples/sentence-word-lookup.ts
new file mode 100644
index 0000000..7f5331b
--- /dev/null
+++ b/examples/sentence-word-lookup.ts
@@ -0,0 +1,23 @@
+import YomikunDirectAPIClient from "../core/direct/client.ts";
+
+// Create a direct (local) API instance
+var api = new YomikunDirectAPIClient();
+// Excplicitly wait until everything is ready
+// await api.ready;
+
+// This sentence does not contain all information until it is explicitly
+// fetched by the user. Each subclass instantiated from an API instance keeps a
+// reference to that API instance for fetching additional data.
+var sentence = api.sentence("この紅茶は甘すぎる");
+
+// Pick the word 紅茶 from the sentence in some different ways:
+// var word = sentence.at("紅茶"); // reference substring (matches first only)
+// var word = sentence.terms[1]; // reference word index (depends on correct deconjugations/parsing)
+var word = sentence.terms.find(t => t.writing == "紅茶"); // filter terms by writing (matches first only)
+
+// Fetch definitions for word
+var glossary = word.glossary();
+
+
+// WIP
+
diff --git a/language/parser.ts b/language/parser.ts
index 9bfdc4b..27aa5ee 100644
--- a/language/parser.ts
+++ b/language/parser.ts
@@ -7,27 +7,28 @@ import "../util/set.ts";
/** @summary main Parser class */
export default class Parser {
db: DB;
+ ready: Promise<void>;
constructor() {
this.db = new DB();
- }
- async prepare() {
- await Promise.all([
- this.db.prepare(),
- ]);
+ this.ready = new Promise<void>(async resolve => {
+ await this.db.ready;
+ resolve();
+ });
}
- parse(sentence: string, options?: InputSentenceProps): ParseResult {
- let parseResult = this.parseTerms(sentence, options);
+ async parse(sentence: string, options?: InputSentenceProps): Promise<ParseResult> {
+ await this.ready;
+ let parseResult = await this.parseTerms(sentence, options);
if ((options?.depth || ParseDepth.Term) <= ParseDepth.Term) return parseResult;
- parseResult = this.addGlossary(parseResult, options);
+ parseResult = await this.addGlossary(parseResult, options);
if ((options?.depth || ParseDepth.Term) <= ParseDepth.Term) return parseResult;
return parseResult;
}
/** @summary parse sentence into terms with readings */
- private parseTerms(sentence: string, options?: InputSentenceProps): ParseResult {
+ private async parseTerms(sentence: string, options?: InputSentenceProps): Promise<ParseResult> {
const MAX_LOOKAHEAD = options?.lookahead ?? 15;
const PRIORITY_MOD_HIGHER = options?.priorityMod?.high ?? 10;
const PRIORITY_MOD_LOWER = options?.priorityMod?.low ?? 0.1;
@@ -38,7 +39,7 @@ export default class Parser {
};
for (let start = 0; start < sentence.length; start++) {
- var results = this.db.findTerm(sentence.substring(start, start + MAX_LOOKAHEAD));
+ var results = await this.db.findTerm(sentence.substring(start, start + MAX_LOOKAHEAD));
// current starting point did not yield results, try again at next character or until end of input
if (results.length == 0) continue;
@@ -112,7 +113,7 @@ export default class Parser {
return parseResult;
}
- private addGlossary(input: ParseResult, options?: InputSentenceProps): ParseResult {
+ private async addGlossary(input: ParseResult, options?: InputSentenceProps): Promise<ParseResult> {
// TODO: annotate input with glossaries from DB
options; // prevent unused warning
return input;
diff --git a/main.ts b/main.ts
index 5c59ea9..b062c1c 100644
--- a/main.ts
+++ b/main.ts
@@ -1,6 +1,3 @@
-import * as path from 'https://deno.land/std@0.102.0/path/mod.ts';
-Deno.chdir(path.dirname(path.fromFileUrl(Deno.mainModule)));
-
import { ParseResult } from "./language/types.ts";
function prettyprintParseResult(input: ParseResult) {
@@ -38,7 +35,7 @@ async function apiTest(api: API) {
// test 1 (direct api)
await (async () => {
var api = new YomikunDirectAPIClient();
- await api.prepare();
+ await api.ready;
console.log("Prepare direct api done");
await apiTest(api);
@@ -49,12 +46,10 @@ console.log("\n".repeat(2));
// test 2 (remote api)
await (async () => {
// default host = localhost:9400
- var server = new YomikunRemoteAPIServer();
- await server.prepare();
- server.start();
+ new YomikunRemoteAPIServer().start();
var api = new YomikunRemoteAPIClient();
- await api.prepare();
+ await api.ready;
console.log("Prepare remote api done");
await apiTest(api);
diff --git a/test/reading/test.ts b/test/reading/test.ts
index 9d426d4..9caf890 100644
--- a/test/reading/test.ts
+++ b/test/reading/test.ts
@@ -17,7 +17,8 @@ interface Test {
tags: Array<string>;
};
-const tests = JSON.parse(await Deno.readTextFile(path.resolve('test', 'reading', 'cases.json'))) as Test[];
+const here = path.dirname(path.fromFileUrl(import.meta.url));
+const tests = JSON.parse(await Deno.readTextFile(path.resolve(here, 'cases.json'))) as Test[];
console.log(`amount of sentences: ${tests.length}`);
console.log(`average sentence length: ${tests.map(t => t.test.input.length).reduce((a, b) => a + b) / tests.length}`);