treewide: add and apply a bunch of lints

This commit is contained in:
2025-07-17 00:21:36 +02:00
parent 2803db9c12
commit bb68319527
39 changed files with 399 additions and 356 deletions

41
analysis_options.yaml Normal file
View File

@@ -0,0 +1,41 @@
# This file configures the analyzer, which statically analyzes Dart code to
# check for errors, warnings, and lints.
#
# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
# invoked from the command line by running `flutter analyze`.
# The following line activates a set of recommended lints for Flutter apps,
# packages, and plugins designed to encourage good coding practices.
include:
- package:lints/recommended.yaml
linter:
# The lint rules applied to this project can be customized in the
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
# included above or to enable additional rules. A list of all available lints
# and their documentation is published at https://dart.dev/lints.
#
# Instead of disabling a lint rule for the entire project in the
# section below, it can also be suppressed for a single line of code
# or a specific dart file by using the `// ignore: name_of_lint` and
# `// ignore_for_file: name_of_lint` syntax on the line or in the file
# producing the lint.
rules:
always_declare_return_types: true
annotate_redeclares: true
avoid_print: false
avoid_setters_without_getters: true
avoid_slow_async_io: true
directives_ordering: true
eol_at_end_of_file: true
prefer_const_declarations: true
prefer_contains: true
prefer_final_fields: true
prefer_final_locals: true
prefer_single_quotes: true
use_key_in_widget_constructors: true
use_null_aware_elements: true
# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options

View File

@@ -9,7 +9,7 @@ import 'package:jadb/cli/commands/query_word.dart';
Future<void> main(List<String> args) async {
final runner = CommandRunner(
'jadb',
"CLI tool to help creating and testing the jadb database",
'CLI tool to help creating and testing the jadb database',
);
runner.addCommand(CreateDb());

View File

@@ -16,6 +16,7 @@ abstract class Element extends SQLWritable {
this.nf,
});
@override
Map<String, Object?> get sqlValue => {
'reading': reading,
'news': news,
@@ -33,20 +34,13 @@ class KanjiElement extends Element {
KanjiElement({
this.info = const [],
required this.orderNum,
required String reading,
int? news,
int? ichi,
int? spec,
int? gai,
int? nf,
}) : super(
reading: reading,
news: news,
ichi: ichi,
spec: spec,
gai: gai,
nf: nf,
);
required super.reading,
super.news,
super.ichi,
super.spec,
super.gai,
super.nf,
});
@override
Map<String, Object?> get sqlValue => {
@@ -66,20 +60,13 @@ class ReadingElement extends Element {
required this.readingDoesNotMatchKanji,
this.info = const [],
this.restrictions = const [],
required String reading,
int? news,
int? ichi,
int? spec,
int? gai,
int? nf,
}) : super(
reading: reading,
news: news,
ichi: ichi,
spec: spec,
gai: gai,
nf: nf,
);
required super.reading,
super.news,
super.ichi,
super.spec,
super.gai,
super.nf,
});
@override
Map<String, Object?> get sqlValue => {
@@ -118,6 +105,7 @@ class Glossary extends SQLWritable {
const Glossary({required this.language, required this.phrase, this.type});
@override
Map<String, Object?> get sqlValue => {
'language': language,
'phrase': phrase,
@@ -216,5 +204,6 @@ class Entry extends SQLWritable {
required this.senses,
});
@override
Map<String, Object?> get sqlValue => {'entryId': entryId};
}

View File

@@ -21,9 +21,9 @@ ResolvedXref resolveXref(
(null, null) => throw Exception(
'Xref $xref has no kanji or reading reference',
),
(String k, null) => entriesByKanji[k]!.toList(),
(null, String r) => entriesByReading[r]!.toList(),
(String k, String r) =>
(final String k, null) => entriesByKanji[k]!.toList(),
(null, final String r) => entriesByReading[r]!.toList(),
(final String k, final String r) =>
entriesByKanji[k]!.intersection(entriesByReading[r]!).toList(),
};
@@ -41,7 +41,7 @@ ResolvedXref resolveXref(
xref.readingRef != null &&
candidateEntries.length > 1) {
final candidatesWithEmptyKanji = candidateEntries
.where((entry) => entry.kanji.length == 0)
.where((entry) => entry.kanji.isEmpty)
.toList();
if (candidatesWithEmptyKanji.isNotEmpty) {
@@ -53,7 +53,7 @@ ResolvedXref resolveXref(
// entry in case there are multiple candidates left.
candidateEntries.sortBy<num>((entry) => entry.senses.length);
if (candidateEntries.length == 0) {
if (candidateEntries.isEmpty) {
throw Exception(
'SKIPPING: Xref $xref has ${candidateEntries.length} entries, '
'kanjiRef: ${xref.kanjiRef}, readingRef: ${xref.readingRef}, '
@@ -180,7 +180,7 @@ Future<void> seedJMDictData(List<Entry> entries, Database db) async {
await b.commit(noResult: true);
print(' [JMdict] Building xref trees');
SplayTreeMap<String, Set<Entry>> entriesByKanji = SplayTreeMap();
final SplayTreeMap<String, Set<Entry>> entriesByKanji = SplayTreeMap();
for (final entry in entries) {
for (final kanji in entry.kanji) {
@@ -191,7 +191,7 @@ Future<void> seedJMDictData(List<Entry> entries, Database db) async {
}
}
}
SplayTreeMap<String, Set<Entry>> entriesByReading = SplayTreeMap();
final SplayTreeMap<String, Set<Entry>> entriesByReading = SplayTreeMap();
for (final entry in entries) {
for (final reading in entry.readings) {
if (entriesByReading.containsKey(reading.reading)) {

View File

@@ -8,9 +8,9 @@ List<int?> getPriorityValues(XmlElement e, String prefix) {
int? news, ichi, spec, gai, nf;
for (final pri in e.findElements('${prefix}_pri')) {
final txt = pri.innerText;
if (txt.startsWith('news'))
if (txt.startsWith('news')) {
news = int.parse(txt.substring(4));
else if (txt.startsWith('ichi'))
} else if (txt.startsWith('ichi'))
ichi = int.parse(txt.substring(4));
else if (txt.startsWith('spec'))
spec = int.parse(txt.substring(4));
@@ -80,7 +80,7 @@ List<Entry> parseJMDictData(XmlElement root) {
final List<Sense> senses = [];
for (final (kanjiNum, k_ele) in entry.findElements('k_ele').indexed) {
final ke_pri = getPriorityValues(k_ele, 'ke');
final kePri = getPriorityValues(k_ele, 'ke');
kanjiEls.add(
KanjiElement(
orderNum: kanjiNum + 1,
@@ -89,17 +89,17 @@ List<Entry> parseJMDictData(XmlElement root) {
.map((e) => e.innerText.substring(1, e.innerText.length - 1))
.toList(),
reading: k_ele.findElements('keb').first.innerText,
news: ke_pri[0],
ichi: ke_pri[1],
spec: ke_pri[2],
gai: ke_pri[3],
nf: ke_pri[4],
news: kePri[0],
ichi: kePri[1],
spec: kePri[2],
gai: kePri[3],
nf: kePri[4],
),
);
}
for (final (orderNum, r_ele) in entry.findElements('r_ele').indexed) {
final re_pri = getPriorityValues(r_ele, 're');
final rePri = getPriorityValues(r_ele, 're');
final readingDoesNotMatchKanji = r_ele
.findElements('re_nokanji')
.isNotEmpty;
@@ -116,11 +116,11 @@ List<Entry> parseJMDictData(XmlElement root) {
.map((e) => e.innerText)
.toList(),
reading: r_ele.findElements('reb').first.innerText,
news: re_pri[0],
ichi: re_pri[1],
spec: re_pri[2],
gai: re_pri[3],
nf: re_pri[4],
news: rePri[0],
ichi: rePri[1],
spec: rePri[2],
gai: rePri[3],
nf: rePri[4],
),
);
}

View File

@@ -245,6 +245,7 @@ class Character extends SQLWritable {
this.nanori = const [],
});
@override
Map<String, Object?> get sqlValue => {
'literal': literal,
'grade': grade,

View File

@@ -10,9 +10,9 @@ List<Character> parseKANJIDICData(XmlElement root) {
final codepoint = c.findElements('codepoint').firstOrNull;
final radical = c.findElements('radical').firstOrNull;
final misc = c.findElements('misc').first;
final dic_number = c.findElements('dic_number').firstOrNull;
final query_code = c.findElements('query_code').first;
final reading_meaning = c.findElements('reading_meaning').firstOrNull;
final dicNumber = c.findElements('dic_number').firstOrNull;
final queryCode = c.findElements('query_code').first;
final readingMeaning = c.findElements('reading_meaning').firstOrNull;
// TODO: Group readings and meanings by their rmgroup parent node.
@@ -70,7 +70,7 @@ List<Character> parseKANJIDICData(XmlElement root) {
)
.toList(),
dictionaryReferences:
dic_number
dicNumber
?.findElements('dic_ref')
.where((e) => e.getAttribute('dr_type') != 'moro')
.map(
@@ -83,7 +83,7 @@ List<Character> parseKANJIDICData(XmlElement root) {
.toList() ??
[],
dictionaryReferencesMoro:
dic_number
dicNumber
?.findElements('dic_ref')
.where((e) => e.getAttribute('dr_type') == 'moro')
.map(
@@ -96,7 +96,7 @@ List<Character> parseKANJIDICData(XmlElement root) {
)
.toList() ??
[],
querycodes: query_code
querycodes: queryCode
.findElements('q_code')
.map(
(e) => QueryCode(
@@ -108,7 +108,7 @@ List<Character> parseKANJIDICData(XmlElement root) {
)
.toList(),
readings:
reading_meaning
readingMeaning
?.findAllElements('reading')
.where(
(e) =>
@@ -124,7 +124,7 @@ List<Character> parseKANJIDICData(XmlElement root) {
.toList() ??
[],
kunyomi:
reading_meaning
readingMeaning
?.findAllElements('reading')
.where((e) => e.getAttribute('r_type') == 'ja_kun')
.map(
@@ -137,7 +137,7 @@ List<Character> parseKANJIDICData(XmlElement root) {
.toList() ??
[],
onyomi:
reading_meaning
readingMeaning
?.findAllElements('reading')
.where((e) => e.getAttribute('r_type') == 'ja_on')
.map(
@@ -151,7 +151,7 @@ List<Character> parseKANJIDICData(XmlElement root) {
.toList() ??
[],
meanings:
reading_meaning
readingMeaning
?.findAllElements('meaning')
.map(
(e) => Meaning(
@@ -163,7 +163,7 @@ List<Character> parseKANJIDICData(XmlElement root) {
.toList() ??
[],
nanori:
reading_meaning
readingMeaning
?.findElements('nanori')
.map((e) => e.innerText)
.toList() ??

View File

@@ -22,15 +22,15 @@ Future<Database> openLocalDb({
jadbPath = File(jadbPath).resolveSymbolicLinksSync();
if (libsqlitePath == null) {
throw Exception("LIBSQLITE_PATH is not set");
throw Exception('LIBSQLITE_PATH is not set');
}
if (!File(libsqlitePath).existsSync()) {
throw Exception("LIBSQLITE_PATH does not exist: $libsqlitePath");
throw Exception('LIBSQLITE_PATH does not exist: $libsqlitePath');
}
if (!File(jadbPath).existsSync()) {
throw Exception("JADB_PATH does not exist: $jadbPath");
throw Exception('JADB_PATH does not exist: $jadbPath');
}
final db =
@@ -42,9 +42,9 @@ Future<Database> openLocalDb({
options: OpenDatabaseOptions(
onConfigure: (db) async {
if (walMode) {
await db.execute("PRAGMA journal_mode = WAL");
await db.execute('PRAGMA journal_mode = WAL');
}
await db.execute("PRAGMA foreign_keys = ON");
await db.execute('PRAGMA foreign_keys = ON');
},
readOnly: !readWrite,
),

View File

@@ -24,10 +24,10 @@ Future<void> seedData(Database db) async {
Future<void> parseAndSeedDataFromJMdict(Database db) async {
print('[JMdict] Reading file content...');
String rawXML = File('data/tmp/JMdict.xml').readAsStringSync();
final String rawXML = File('data/tmp/JMdict.xml').readAsStringSync();
print('[JMdict] Parsing XML tags...');
XmlElement root = XmlDocument.parse(rawXML).getElement('JMdict')!;
final XmlElement root = XmlDocument.parse(rawXML).getElement('JMdict')!;
print('[JMdict] Parsing XML content...');
final entries = parseJMDictData(root);
@@ -38,10 +38,10 @@ Future<void> parseAndSeedDataFromJMdict(Database db) async {
Future<void> parseAndSeedDataFromKANJIDIC(Database db) async {
print('[KANJIDIC2] Reading file...');
String rawXML = File('data/tmp/kanjidic2.xml').readAsStringSync();
final String rawXML = File('data/tmp/kanjidic2.xml').readAsStringSync();
print('[KANJIDIC2] Parsing XML...');
XmlElement root = XmlDocument.parse(rawXML).getElement('kanjidic2')!;
final XmlElement root = XmlDocument.parse(rawXML).getElement('kanjidic2')!;
print('[KANJIDIC2] Parsing XML content...');
final entries = parseKANJIDICData(root);
@@ -52,7 +52,7 @@ Future<void> parseAndSeedDataFromKANJIDIC(Database db) async {
Future<void> parseAndSeedDataFromRADKFILE(Database db) async {
print('[RADKFILE] Reading file...');
File raw = File('data/tmp/RADKFILE');
final File raw = File('data/tmp/RADKFILE');
print('[RADKFILE] Parsing content...');
final blocks = parseRADKFILEBlocks(raw);
@@ -63,7 +63,7 @@ Future<void> parseAndSeedDataFromRADKFILE(Database db) async {
Future<void> parseAndSeedDataFromTanosJLPT(Database db) async {
print('[TANOS-JLPT] Reading files...');
Map<String, File> files = {
final Map<String, File> files = {
'N1': File('data/tanos-jlpt/n1.csv'),
'N2': File('data/tanos-jlpt/n2.csv'),
'N3': File('data/tanos-jlpt/n3.csv'),

View File

@@ -14,7 +14,7 @@ Future<List<JLPTRankedWord>> parseJLPTRankedWords(
final file = entry.value;
if (!file.existsSync()) {
throw Exception("File $jlptLevel does not exist");
throw Exception('File $jlptLevel does not exist');
}
final rows = await file
@@ -25,7 +25,7 @@ Future<List<JLPTRankedWord>> parseJLPTRankedWords(
for (final row in rows) {
if (row.length != 3) {
throw Exception("Invalid line in $jlptLevel: $row");
throw Exception('Invalid line in $jlptLevel: $row');
}
final kanji = (row[0] as String).isEmpty
@@ -35,7 +35,7 @@ Future<List<JLPTRankedWord>> parseJLPTRankedWords(
.replaceAll(RegExp(r'.*'), '');
final readings = (row[1] as String)
.split(RegExp('[・/、(:?\s+)]'))
.split(RegExp('[・/、(:?s+)]'))
.map((e) => e.trim())
.toList();

View File

@@ -13,5 +13,5 @@ class JLPTRankedWord {
@override
String toString() =>
'(${jlptLevel},${kanji},"${readings.join(",")}","${meanings.join(",")})';
'($jlptLevel,$kanji,"${readings.join(",")}","${meanings.join(",")})';
}

View File

@@ -1,6 +1,6 @@
import 'package:jadb/table_names/jmdict.dart';
import 'package:jadb/_data_ingestion/tanos-jlpt/objects.dart';
import 'package:jadb/_data_ingestion/tanos-jlpt/overrides.dart';
import 'package:jadb/table_names/jmdict.dart';
import 'package:sqflite_common/sqlite_api.dart';
Future<List<int>> _findReadingCandidates(JLPTRankedWord word, Database db) => db
@@ -84,7 +84,7 @@ Future<int?> findEntry(
throw Exception(
'Multiple override entries found for ${word.toString()}: $entryIds',
);
} else if (overrideEntries.length == 0 &&
} else if (overrideEntries.isEmpty &&
!word.readings.any(
(reading) => TANOS_JLPT_OVERRIDES.containsKey((word.kanji, reading)),
)) {

View File

@@ -5,7 +5,7 @@ Future<void> seedTanosJLPTData(
Map<String, Set<int>> resolvedEntries,
Database db,
) async {
Batch b = db.batch();
final Batch b = db.batch();
for (final jlptLevel in resolvedEntries.entries) {
final level = jlptLevel.key;

View File

@@ -1,14 +1,15 @@
import 'dart:io';
import 'package:args/command_runner.dart';
import 'package:jadb/_data_ingestion/open_local_db.dart';
import 'package:jadb/_data_ingestion/seed_database.dart';
import 'package:args/command_runner.dart';
import 'package:jadb/cli/args.dart';
class CreateDb extends Command {
final name = "create-db";
final description = "Create the database";
@override
final name = 'create-db';
@override
final description = 'Create the database';
CreateDb() {
addLibsqliteArg(argParser);
@@ -23,6 +24,7 @@ class CreateDb extends Command {
);
}
@override
Future<void> run() async {
if (argResults!.option('libsqlite') == null) {
print(argParser.usage);
@@ -38,10 +40,10 @@ class CreateDb extends Command {
bool failed = false;
await seedData(db)
.then((_) {
print("Database created successfully");
print('Database created successfully');
})
.catchError((error) {
print("Error creating database: $error");
print('Error creating database: $error');
failed = true;
})
.whenComplete(() {

View File

@@ -1,8 +1,7 @@
import 'dart:io';
import 'package:jadb/_data_ingestion/open_local_db.dart';
import 'package:args/command_runner.dart';
import 'package:jadb/_data_ingestion/open_local_db.dart';
import 'package:jadb/_data_ingestion/tanos-jlpt/csv_parser.dart';
import 'package:jadb/_data_ingestion/tanos-jlpt/objects.dart';
import 'package:jadb/_data_ingestion/tanos-jlpt/resolve.dart';
@@ -10,9 +9,11 @@ import 'package:jadb/cli/args.dart';
import 'package:sqflite_common/sqlite_api.dart';
class CreateTanosJlptMappings extends Command {
final name = "create-tanos-jlpt-mappings";
@override
final name = 'create-tanos-jlpt-mappings';
@override
final description =
"Resolve Tanos JLPT data against JMDict. This tool is useful to create overrides for ambiguous references";
'Resolve Tanos JLPT data against JMDict. This tool is useful to create overrides for ambiguous references';
CreateTanosJlptMappings() {
addLibsqliteArg(argParser);
@@ -26,6 +27,7 @@ class CreateTanosJlptMappings extends Command {
);
}
@override
Future<void> run() async {
if (argResults!.option('libsqlite') == null ||
argResults!.option('jadb') == null) {
@@ -40,7 +42,7 @@ class CreateTanosJlptMappings extends Command {
final useOverrides = argResults!.flag('overrides');
Map<String, File> files = {
final Map<String, File> files = {
'N1': File('data/tanos-jlpt/n1.csv'),
'N2': File('data/tanos-jlpt/n2.csv'),
'N3': File('data/tanos-jlpt/n3.csv'),
@@ -59,7 +61,7 @@ Future<void> resolveExisting(
Database db,
bool useOverrides,
) async {
List<JLPTRankedWord> missingWords = [];
final List<JLPTRankedWord> missingWords = [];
for (final (i, word) in rankedWords.indexed) {
try {
print(
@@ -90,7 +92,7 @@ Future<void> resolveExisting(
.toStringAsFixed(2);
print(
'${jlptLevel} failures: [${missingWordCount}/${totalWordCount}] (${failureRate}%)',
'$jlptLevel failures: [$missingWordCount/$totalWordCount] ($failureRate%)',
);
}

View File

@@ -1,14 +1,15 @@
// import 'dart:io';
import 'package:args/command_runner.dart';
// import 'package:jadb/_data_ingestion/open_local_db.dart';
import 'package:jadb/cli/args.dart';
import 'package:args/command_runner.dart';
import 'package:jadb/util/lemmatizer/lemmatizer.dart';
class Lemmatize extends Command {
final name = "lemmatize";
final description = "Lemmatize a word using the Jadb lemmatizer";
@override
final name = 'lemmatize';
@override
final description = 'Lemmatize a word using the Jadb lemmatizer';
Lemmatize() {
addLibsqliteArg(argParser);
@@ -21,6 +22,7 @@ class Lemmatize extends Command {
);
}
@override
Future<void> run() async {
// if (argResults!.option('libsqlite') == null ||
// argResults!.option('jadb') == null) {
@@ -41,6 +43,6 @@ class Lemmatize extends Command {
print(result.toString());
print("Lemmatization took ${time.elapsedMilliseconds}ms");
print('Lemmatization took ${time.elapsedMilliseconds}ms');
}
}

View File

@@ -1,22 +1,25 @@
import 'dart:convert';
import 'dart:io';
import 'package:args/command_runner.dart';
import 'package:jadb/_data_ingestion/open_local_db.dart';
import 'package:jadb/cli/args.dart';
import 'package:jadb/search.dart';
import 'package:args/command_runner.dart';
class QueryKanji extends Command {
final name = "query-kanji";
final description = "Query the database for kanji data";
final invocation = "jadb query-kanji [options] <kanji>";
@override
final name = 'query-kanji';
@override
final description = 'Query the database for kanji data';
@override
final invocation = 'jadb query-kanji [options] <kanji>';
QueryKanji() {
addLibsqliteArg(argParser);
addJadbArg(argParser);
}
@override
Future<void> run() async {
if (argResults!.option('libsqlite') == null ||
argResults!.option('jadb') == null) {
@@ -43,11 +46,11 @@ class QueryKanji extends Command {
time.stop();
if (result == null) {
print("No such kanji");
print('No such kanji');
} else {
print(JsonEncoder.withIndent(' ').convert(result.toJson()));
}
print("Query took ${time.elapsedMilliseconds}ms");
print('Query took ${time.elapsedMilliseconds}ms');
}
}

View File

@@ -1,17 +1,19 @@
import 'dart:convert';
import 'dart:io';
import 'package:args/command_runner.dart';
import 'package:jadb/_data_ingestion/open_local_db.dart';
import 'package:jadb/cli/args.dart';
import 'package:jadb/search.dart';
import 'package:args/command_runner.dart';
import 'package:sqflite_common/sqflite.dart';
class QueryWord extends Command {
final name = "query-word";
final description = "Query the database for word data";
final invocation = "jadb query-word [options] (<word> | <ID>)";
@override
final name = 'query-word';
@override
final description = 'Query the database for word data';
@override
final invocation = 'jadb query-word [options] (<word> | <ID>)';
QueryWord() {
addLibsqliteArg(argParser);
@@ -24,10 +26,11 @@ class QueryWord extends Command {
argParser.addOption('pageSize', valueHelp: 'NUM', defaultsTo: '30');
}
@override
Future<void> run() async {
if (argResults!.option('libsqlite') == null ||
argResults!.option('jadb') == null) {
print("You need to provide both libsqlite and jadb paths.");
print('You need to provide both libsqlite and jadb paths.');
print('');
printUsage();
exit(64);
@@ -45,7 +48,7 @@ class QueryWord extends Command {
exit(64);
}
final String searchWord = argResults!.rest.join(" ");
final String searchWord = argResults!.rest.join(' ');
final int? maybeId = int.tryParse(searchWord);
if (maybeId != null && maybeId >= 1000000) {
@@ -67,7 +70,7 @@ class QueryWord extends Command {
time.stop();
if (result == null) {
print("Invalid ID");
print('Invalid ID');
} else {
if (jsonOutput) {
print(JsonEncoder.withIndent(' ').convert(result));
@@ -76,7 +79,7 @@ class QueryWord extends Command {
}
}
print("Query took ${time.elapsedMilliseconds}ms");
print('Query took ${time.elapsedMilliseconds}ms');
}
Future<void> _searchWord(
@@ -97,22 +100,22 @@ class QueryWord extends Command {
time2.stop();
if (result == null) {
print("Invalid search");
print('Invalid search');
} else if (result.isEmpty) {
print("No matches");
print('No matches');
} else {
if (jsonOutput) {
print(JsonEncoder.withIndent(' ').convert(result));
} else {
for (final e in result) {
print(e.toString());
print("");
print('');
}
}
}
print("Total count: ${count}");
print("Count query took ${time.elapsedMilliseconds}ms");
print("Query took ${time2.elapsedMilliseconds}ms");
print('Total count: $count');
print('Count query took ${time.elapsedMilliseconds}ms');
print('Query took ${time2.elapsedMilliseconds}ms');
}
}

View File

@@ -43,6 +43,7 @@ enum JlptLevel implements Comparable<JlptLevel> {
int? get asInt =>
this == JlptLevel.none ? null : JlptLevel.values.indexOf(this);
@override
String toString() => toNullableString() ?? 'N/A';
Object? toJson() => toNullableString();

View File

@@ -11,7 +11,7 @@ String migrationDirPath() {
}
Future<void> createEmptyDb(DatabaseExecutor db) async {
List<String> migrationFiles = [];
final List<String> migrationFiles = [];
for (final file in Directory(migrationDirPath()).listSync()) {
if (file is File && file.path.endsWith('.sql')) {
migrationFiles.add(file.path);

View File

@@ -26,7 +26,7 @@ class KanjiSearchRadical extends Equatable {
});
@override
List<Object> get props => [symbol, this.names, forms, meanings];
List<Object> get props => [symbol, names, forms, meanings];
Map<String, dynamic> toJson() => {
'symbol': symbol,

View File

@@ -82,16 +82,16 @@ class WordSearchResult {
);
String _formatJapaneseWord(WordSearchRuby word) =>
word.furigana == null ? word.base : "${word.base} (${word.furigana})";
word.furigana == null ? word.base : '${word.base} (${word.furigana})';
@override
String toString() {
final japaneseWord = _formatJapaneseWord(japanese[0]);
final isCommonString = isCommon ? '(C)' : '';
final jlptLevelString = "(${jlptLevel.toString()})";
final jlptLevelString = '(${jlptLevel.toString()})';
return '''
${score} | [$entryId] $japaneseWord $isCommonString $jlptLevelString
$score | [$entryId] $japaneseWord $isCommonString $jlptLevelString
Other forms: ${japanese.skip(1).map(_formatJapaneseWord).join(', ')}
Senses: ${senses.map((s) => s.englishDefinitions).join(', ')}
'''

View File

@@ -1,12 +1,10 @@
import 'package:jadb/models/kanji_search/kanji_search_result.dart';
import 'package:jadb/models/verify_tables.dart';
import 'package:jadb/models/word_search/word_search_result.dart';
import 'package:jadb/models/kanji_search/kanji_search_result.dart';
import 'package:jadb/search/filter_kanji.dart';
import 'package:jadb/search/kanji_search.dart';
import 'package:jadb/search/radical_search.dart';
import 'package:jadb/search/word_search/word_search.dart';
import 'package:jadb/search/kanji_search.dart';
import 'package:sqflite_common/sqlite_api.dart';
extension JaDBConnection on DatabaseExecutor {

View File

@@ -1,8 +1,8 @@
import 'package:collection/collection.dart';
import 'package:jadb/table_names/kanjidic.dart';
import 'package:jadb/table_names/radkfile.dart';
import 'package:jadb/models/kanji_search/kanji_search_radical.dart';
import 'package:jadb/models/kanji_search/kanji_search_result.dart';
import 'package:jadb/table_names/kanjidic.dart';
import 'package:jadb/table_names/radkfile.dart';
import 'package:jadb/util/romaji_transliteration.dart';
import 'package:sqflite_common/sqflite.dart';
@@ -11,66 +11,66 @@ Future<KanjiSearchResult?> searchKanjiWithDbConnection(
String kanji,
) async {
late final List<Map<String, Object?>> characters;
final characters_query = connection.query(
final charactersQuery = connection.query(
KANJIDICTableNames.character,
where: "literal = ?",
where: 'literal = ?',
whereArgs: [kanji],
);
late final List<Map<String, Object?>> codepoints;
final codepoints_query = connection.query(
final codepointsQuery = connection.query(
KANJIDICTableNames.codepoint,
where: "kanji = ?",
where: 'kanji = ?',
whereArgs: [kanji],
);
late final List<Map<String, Object?>> kunyomis;
final kunyomis_query = connection.query(
final kunyomisQuery = connection.query(
KANJIDICTableNames.kunyomi,
where: "kanji = ?",
where: 'kanji = ?',
whereArgs: [kanji],
orderBy: "orderNum",
orderBy: 'orderNum',
);
late final List<Map<String, Object?>> onyomis;
final onyomis_query = connection.query(
final onyomisQuery = connection.query(
KANJIDICTableNames.onyomi,
where: "kanji = ?",
where: 'kanji = ?',
whereArgs: [kanji],
orderBy: "orderNum",
orderBy: 'orderNum',
);
late final List<Map<String, Object?>> meanings;
final meanings_query = connection.query(
final meaningsQuery = connection.query(
KANJIDICTableNames.meaning,
where: "kanji = ? AND language = ?",
where: 'kanji = ? AND language = ?',
whereArgs: [kanji, 'eng'],
orderBy: "orderNum",
orderBy: 'orderNum',
);
late final List<Map<String, Object?>> nanoris;
final nanoris_query = connection.query(
final nanorisQuery = connection.query(
KANJIDICTableNames.nanori,
where: "kanji = ?",
where: 'kanji = ?',
whereArgs: [kanji],
);
late final List<Map<String, Object?>> dictionary_references;
final dictionary_references_query = connection.query(
late final List<Map<String, Object?>> dictionaryReferences;
final dictionaryReferencesQuery = connection.query(
KANJIDICTableNames.dictionaryReference,
where: "kanji = ?",
where: 'kanji = ?',
whereArgs: [kanji],
);
late final List<Map<String, Object?>> query_codes;
final query_codes_query = connection.query(
late final List<Map<String, Object?>> queryCodes;
final queryCodesQuery = connection.query(
KANJIDICTableNames.queryCode,
where: "kanji = ?",
where: 'kanji = ?',
whereArgs: [kanji],
);
late final List<Map<String, Object?>> radicals;
final radicals_query = connection.rawQuery(
final radicalsQuery = connection.rawQuery(
'''
SELECT DISTINCT
"XREF__KANJIDIC_Radical__RADKFILE"."radicalSymbol" AS "symbol",
@@ -88,23 +88,23 @@ Future<KanjiSearchResult?> searchKanjiWithDbConnection(
);
late final List<Map<String, Object?>> parts;
final parts_query = connection.query(
final partsQuery = connection.query(
RADKFILETableNames.radkfile,
where: "kanji = ?",
where: 'kanji = ?',
whereArgs: [kanji],
);
late final List<Map<String, Object?>> readings;
final readings_query = connection.query(
final readingsQuery = connection.query(
KANJIDICTableNames.reading,
where: "kanji = ?",
where: 'kanji = ?',
whereArgs: [kanji],
);
late final List<Map<String, Object?>> stroke_miscounts;
final stroke_miscounts_query = connection.query(
late final List<Map<String, Object?>> strokeMiscounts;
final strokeMiscountsQuery = connection.query(
KANJIDICTableNames.strokeMiscount,
where: "kanji = ?",
where: 'kanji = ?',
whereArgs: [kanji],
);
@@ -121,24 +121,24 @@ Future<KanjiSearchResult?> searchKanjiWithDbConnection(
// filter JMdict_ReadingElement for kunyomi/onyomi, and then sort the main entry
// by JLPT, news frequency, etc.
await characters_query.then((value) => characters = value);
await charactersQuery.then((value) => characters = value);
if (characters.isEmpty) {
return null;
}
await Future.wait({
codepoints_query.then((value) => codepoints = value),
kunyomis_query.then((value) => kunyomis = value),
onyomis_query.then((value) => onyomis = value),
meanings_query.then((value) => meanings = value),
nanoris_query.then((value) => nanoris = value),
dictionary_references_query.then((value) => dictionary_references = value),
query_codes_query.then((value) => query_codes = value),
radicals_query.then((value) => radicals = value),
parts_query.then((value) => parts = value),
readings_query.then((value) => readings = value),
stroke_miscounts_query.then((value) => stroke_miscounts = value),
codepointsQuery.then((value) => codepoints = value),
kunyomisQuery.then((value) => kunyomis = value),
onyomisQuery.then((value) => onyomis = value),
meaningsQuery.then((value) => meanings = value),
nanorisQuery.then((value) => nanoris = value),
dictionaryReferencesQuery.then((value) => dictionaryReferences = value),
queryCodesQuery.then((value) => queryCodes = value),
radicalsQuery.then((value) => radicals = value),
partsQuery.then((value) => parts = value),
readingsQuery.then((value) => readings = value),
strokeMiscountsQuery.then((value) => strokeMiscounts = value),
// variants_query.then((value) => variants = value),
});
@@ -166,7 +166,7 @@ Future<KanjiSearchResult?> searchKanjiWithDbConnection(
);
// TODO: Add `SKIPMisclassification` to the entries
final queryCodes = query_codes
final queryCodes_ = queryCodes
.groupListsBy((item) => item['type'] as String)
.map(
(key, value) =>
@@ -174,8 +174,8 @@ Future<KanjiSearchResult?> searchKanjiWithDbConnection(
);
// TODO: Add `volume` and `page` to the entries
final dictionaryReferences = {
for (final entry in dictionary_references)
final dictionaryReferences_ = {
for (final entry in dictionaryReferences)
entry['type'] as String: entry['ref'] as String,
};
@@ -207,11 +207,11 @@ Future<KanjiSearchResult?> searchKanjiWithDbConnection(
},
nanori: nanoris.map((item) => item['nanori'] as String).toList(),
alternativeLanguageReadings: alternativeLanguageReadings,
strokeMiscounts: stroke_miscounts
strokeMiscounts: strokeMiscounts
.map((item) => item['strokeCount'] as int)
.toList(),
queryCodes: queryCodes,
dictionaryReferences: dictionaryReferences,
queryCodes: queryCodes_,
dictionaryReferences: dictionaryReferences_,
);
}

View File

@@ -59,14 +59,14 @@ Future<LinearWordQueryData> fetchLinearWordQueryData(
bool fetchXrefData = true,
}) async {
late final List<Map<String, Object?>> senses;
final Future<List<Map<String, Object?>>> senses_query = connection.query(
final Future<List<Map<String, Object?>>> sensesQuery = connection.query(
JMdictTableNames.sense,
where: 'entryId IN (${List.filled(entryIds.length, '?').join(',')})',
whereArgs: entryIds,
);
late final List<Map<String, Object?>> readingElements;
final Future<List<Map<String, Object?>>> readingElements_query = connection
final Future<List<Map<String, Object?>>> readingelementsQuery = connection
.query(
JMdictTableNames.readingElement,
where: 'entryId IN (${List.filled(entryIds.length, '?').join(',')})',
@@ -75,7 +75,7 @@ Future<LinearWordQueryData> fetchLinearWordQueryData(
);
late final List<Map<String, Object?>> kanjiElements;
final Future<List<Map<String, Object?>>> kanjiElements_query = connection
final Future<List<Map<String, Object?>>> kanjielementsQuery = connection
.query(
JMdictTableNames.kanjiElement,
where: 'entryId IN (${List.filled(entryIds.length, '?').join(',')})',
@@ -84,14 +84,14 @@ Future<LinearWordQueryData> fetchLinearWordQueryData(
);
late final List<Map<String, Object?>> jlptTags;
final Future<List<Map<String, Object?>>> jlptTags_query = connection.query(
final Future<List<Map<String, Object?>>> jlpttagsQuery = connection.query(
TanosJLPTTableNames.jlptTag,
where: 'entryId IN (${List.filled(entryIds.length, '?').join(',')})',
whereArgs: entryIds,
);
late final List<Map<String, Object?>> commonEntries;
final Future<List<Map<String, Object?>>> commonEntries_query = connection
final Future<List<Map<String, Object?>>> commonentriesQuery = connection
.query(
'JMdict_EntryCommon',
where: 'entryId IN (${List.filled(entryIds.length, '?').join(',')})',
@@ -99,11 +99,11 @@ Future<LinearWordQueryData> fetchLinearWordQueryData(
);
await Future.wait([
senses_query.then((value) => senses = value),
readingElements_query.then((value) => readingElements = value),
kanjiElements_query.then((value) => kanjiElements = value),
jlptTags_query.then((value) => jlptTags = value),
commonEntries_query.then((value) => commonEntries = value),
sensesQuery.then((value) => senses = value),
readingelementsQuery.then((value) => readingElements = value),
kanjielementsQuery.then((value) => kanjiElements = value),
jlpttagsQuery.then((value) => jlptTags = value),
commonentriesQuery.then((value) => commonEntries = value),
]);
// Sense queries
@@ -111,7 +111,7 @@ Future<LinearWordQueryData> fetchLinearWordQueryData(
final senseIds = senses.map((sense) => sense['senseId'] as int).toList();
late final List<Map<String, Object?>> senseAntonyms;
final Future<List<Map<String, Object?>>> senseAntonyms_query = connection
final Future<List<Map<String, Object?>>> senseantonymsQuery = connection
.rawQuery(
"""
SELECT
@@ -134,7 +134,7 @@ Future<LinearWordQueryData> fetchLinearWordQueryData(
);
late final List<Map<String, Object?>> senseDialects;
final Future<List<Map<String, Object?>>> senseDialects_query = connection
final Future<List<Map<String, Object?>>> sensedialectsQuery = connection
.query(
JMdictTableNames.senseDialect,
where: 'senseId IN (${List.filled(senseIds.length, '?').join(',')})',
@@ -142,14 +142,14 @@ Future<LinearWordQueryData> fetchLinearWordQueryData(
);
late final List<Map<String, Object?>> senseFields;
final Future<List<Map<String, Object?>>> senseFields_query = connection.query(
final Future<List<Map<String, Object?>>> sensefieldsQuery = connection.query(
JMdictTableNames.senseField,
where: 'senseId IN (${List.filled(senseIds.length, '?').join(',')})',
whereArgs: senseIds,
);
late final List<Map<String, Object?>> senseGlossaries;
final Future<List<Map<String, Object?>>> senseGlossaries_query = connection
final Future<List<Map<String, Object?>>> senseglossariesQuery = connection
.query(
JMdictTableNames.senseGlossary,
where: 'senseId IN (${List.filled(senseIds.length, '?').join(',')})',
@@ -157,14 +157,14 @@ Future<LinearWordQueryData> fetchLinearWordQueryData(
);
late final List<Map<String, Object?>> senseInfos;
final Future<List<Map<String, Object?>>> senseInfos_query = connection.query(
final Future<List<Map<String, Object?>>> senseinfosQuery = connection.query(
JMdictTableNames.senseInfo,
where: 'senseId IN (${List.filled(senseIds.length, '?').join(',')})',
whereArgs: senseIds,
);
late final List<Map<String, Object?>> senseLanguageSources;
final Future<List<Map<String, Object?>>> senseLanguageSources_query =
final Future<List<Map<String, Object?>>> senselanguagesourcesQuery =
connection.query(
JMdictTableNames.senseLanguageSource,
where: 'senseId IN (${List.filled(senseIds.length, '?').join(',')})',
@@ -172,21 +172,21 @@ Future<LinearWordQueryData> fetchLinearWordQueryData(
);
late final List<Map<String, Object?>> senseMiscs;
final Future<List<Map<String, Object?>>> senseMiscs_query = connection.query(
final Future<List<Map<String, Object?>>> sensemiscsQuery = connection.query(
JMdictTableNames.senseMisc,
where: 'senseId IN (${List.filled(senseIds.length, '?').join(',')})',
whereArgs: senseIds,
);
late final List<Map<String, Object?>> sensePOSs;
final Future<List<Map<String, Object?>>> sensePOSs_query = connection.query(
final Future<List<Map<String, Object?>>> sensepossQuery = connection.query(
JMdictTableNames.sensePOS,
where: 'senseId IN (${List.filled(senseIds.length, '?').join(',')})',
whereArgs: senseIds,
);
late final List<Map<String, Object?>> senseRestrictedToKanjis;
final Future<List<Map<String, Object?>>> senseRestrictedToKanjis_query =
final Future<List<Map<String, Object?>>> senserestrictedtokanjisQuery =
connection.query(
JMdictTableNames.senseRestrictedToKanji,
where: 'senseId IN (${List.filled(senseIds.length, '?').join(',')})',
@@ -194,7 +194,7 @@ Future<LinearWordQueryData> fetchLinearWordQueryData(
);
late final List<Map<String, Object?>> senseRestrictedToReadings;
final Future<List<Map<String, Object?>>> senseRestrictedToReadings_query =
final Future<List<Map<String, Object?>>> senserestrictedtoreadingsQuery =
connection.query(
JMdictTableNames.senseRestrictedToReading,
where: 'senseId IN (${List.filled(senseIds.length, '?').join(',')})',
@@ -202,7 +202,7 @@ Future<LinearWordQueryData> fetchLinearWordQueryData(
);
late final List<Map<String, Object?>> senseSeeAlsos;
final Future<List<Map<String, Object?>>> senseSeeAlsos_query = connection
final Future<List<Map<String, Object?>>> senseseealsosQuery = connection
.rawQuery(
"""
SELECT
@@ -225,7 +225,7 @@ Future<LinearWordQueryData> fetchLinearWordQueryData(
);
late final List<Map<String, Object?>> exampleSentences;
final Future<List<Map<String, Object?>>> exampleSentences_query = connection
final Future<List<Map<String, Object?>>> examplesentencesQuery = connection
.query(
'JMdict_ExampleSentence',
where: 'senseId IN (${List.filled(senseIds.length, '?').join(',')})',
@@ -239,7 +239,7 @@ Future<LinearWordQueryData> fetchLinearWordQueryData(
.toList();
late final List<Map<String, Object?>> readingElementInfos;
final Future<List<Map<String, Object?>>> readingElementInfos_query =
final Future<List<Map<String, Object?>>> readingelementinfosQuery =
connection.query(
JMdictTableNames.readingInfo,
where:
@@ -248,7 +248,7 @@ Future<LinearWordQueryData> fetchLinearWordQueryData(
);
late final List<Map<String, Object?>> readingElementRestrictions;
final Future<List<Map<String, Object?>>> readingElementRestrictions_query =
final Future<List<Map<String, Object?>>> readingelementrestrictionsQuery =
connection.query(
JMdictTableNames.readingRestriction,
where:
@@ -263,7 +263,7 @@ Future<LinearWordQueryData> fetchLinearWordQueryData(
.toList();
late final List<Map<String, Object?>> kanjiElementInfos;
final Future<List<Map<String, Object?>>> kanjiElementInfos_query = connection
final Future<List<Map<String, Object?>>> kanjielementinfosQuery = connection
.query(
JMdictTableNames.kanjiInfo,
where:
@@ -273,12 +273,12 @@ Future<LinearWordQueryData> fetchLinearWordQueryData(
// Xref data queries
await Future.wait([
senseAntonyms_query.then((value) => senseAntonyms = value),
senseSeeAlsos_query.then((value) => senseSeeAlsos = value),
senseantonymsQuery.then((value) => senseAntonyms = value),
senseseealsosQuery.then((value) => senseSeeAlsos = value),
]);
late final LinearWordQueryData? senseAntonymData;
final Future<LinearWordQueryData?> senseAntonymData_query =
final Future<LinearWordQueryData?> senseantonymdataQuery =
fetchXrefData
? fetchLinearWordQueryData(
connection,
@@ -290,7 +290,7 @@ Future<LinearWordQueryData> fetchLinearWordQueryData(
: Future.value(null);
late final LinearWordQueryData? senseSeeAlsoData;
final Future<LinearWordQueryData?> senseSeeAlsoData_query =
final Future<LinearWordQueryData?> senseseealsodataQuery =
fetchXrefData
? fetchLinearWordQueryData(
connection,
@@ -300,27 +300,27 @@ Future<LinearWordQueryData> fetchLinearWordQueryData(
: Future.value(null);
await Future.wait([
senseDialects_query.then((value) => senseDialects = value),
senseFields_query.then((value) => senseFields = value),
senseGlossaries_query.then((value) => senseGlossaries = value),
senseInfos_query.then((value) => senseInfos = value),
senseLanguageSources_query.then((value) => senseLanguageSources = value),
senseMiscs_query.then((value) => senseMiscs = value),
sensePOSs_query.then((value) => sensePOSs = value),
senseRestrictedToKanjis_query.then(
sensedialectsQuery.then((value) => senseDialects = value),
sensefieldsQuery.then((value) => senseFields = value),
senseglossariesQuery.then((value) => senseGlossaries = value),
senseinfosQuery.then((value) => senseInfos = value),
senselanguagesourcesQuery.then((value) => senseLanguageSources = value),
sensemiscsQuery.then((value) => senseMiscs = value),
sensepossQuery.then((value) => sensePOSs = value),
senserestrictedtokanjisQuery.then(
(value) => senseRestrictedToKanjis = value,
),
senseRestrictedToReadings_query.then(
senserestrictedtoreadingsQuery.then(
(value) => senseRestrictedToReadings = value,
),
exampleSentences_query.then((value) => exampleSentences = value),
readingElementInfos_query.then((value) => readingElementInfos = value),
readingElementRestrictions_query.then(
examplesentencesQuery.then((value) => exampleSentences = value),
readingelementinfosQuery.then((value) => readingElementInfos = value),
readingelementrestrictionsQuery.then(
(value) => readingElementRestrictions = value,
),
kanjiElementInfos_query.then((value) => kanjiElementInfos = value),
senseAntonymData_query.then((value) => senseAntonymData = value),
senseSeeAlsoData_query.then((value) => senseSeeAlsoData = value),
kanjielementinfosQuery.then((value) => kanjiElementInfos = value),
senseantonymdataQuery.then((value) => senseAntonymData = value),
senseseealsodataQuery.then((value) => senseSeeAlsoData = value),
]);
return LinearWordQueryData(

View File

@@ -1,5 +1,5 @@
import 'package:jadb/table_names/jmdict.dart';
import 'package:jadb/search/word_search/word_search.dart';
import 'package:jadb/table_names/jmdict.dart';
import 'package:jadb/util/text_filtering.dart';
import 'package:sqflite_common/sqlite_api.dart';
@@ -37,7 +37,7 @@ String _filterFTSSensitiveCharacters(String word) {
.replaceAll('(', '')
.replaceAll(')', '')
.replaceAll('^', '')
.replaceAll('\"', '');
.replaceAll('"', '');
}
(String, List<Object?>) _kanjiReadingTemplate(
@@ -65,27 +65,27 @@ String _filterFTSSensitiveCharacters(String word) {
WITH
fts_results AS (
SELECT DISTINCT
"${tableName}"."entryId",
"$tableName"."entryId",
100
+ (("${tableName}FTS"."reading" = ?) * 10000)
+ "JMdict_EntryScore"."score"
AS "score"
FROM "${tableName}FTS"
JOIN "${tableName}" USING ("elementId")
JOIN "$tableName" USING ("elementId")
JOIN "JMdict_EntryScore" USING ("elementId")
WHERE "${tableName}FTS"."reading" MATCH ? || '*'
AND "JMdict_EntryScore"."type" = '${tableName == JMdictTableNames.kanjiElement ? 'k' : 'r'}'
),
non_fts_results AS (
SELECT DISTINCT
"${tableName}"."entryId",
"$tableName"."entryId",
50
+ "JMdict_EntryScore"."score"
AS "score"
FROM "${tableName}"
FROM "$tableName"
JOIN "JMdict_EntryScore" USING ("elementId")
WHERE "reading" LIKE '%' || ? || '%'
AND "${tableName}"."entryId" NOT IN (SELECT "entryId" FROM "fts_results")
AND "$tableName"."entryId" NOT IN (SELECT "entryId" FROM "fts_results")
AND "JMdict_EntryScore"."type" = '${tableName == JMdictTableNames.kanjiElement ? 'k' : 'r'}'
)
@@ -105,8 +105,8 @@ String _filterFTSSensitiveCharacters(String word) {
_filterFTSSensitiveCharacters(word),
_filterFTSSensitiveCharacters(word),
_filterFTSSensitiveCharacters(word),
if (pageSize != null) pageSize,
if (offset != null) offset,
?pageSize,
?offset,
],
);
}
@@ -271,7 +271,6 @@ Future<List<ScoredEntryId>> fetchEntryIds(
default:
throw UnimplementedError('Search mode $searchMode is not implemented');
}
;
return entryIds;
}

View File

@@ -276,14 +276,14 @@ extension on DateTime {
/// See more info here:
/// - https://en.wikipedia.org/wiki/Nanboku-ch%C5%8D_period
/// - http://www.kumamotokokufu-h.ed.jp/kumamoto/bungaku/nengoui.html
String? japaneseEra({bool nanbokuchouPeriodUsesNorth = true}) {
String? japaneseEra() {
throw UnimplementedError('This function is not implemented yet.');
if (this.year < 645) {
if (year < 645) {
return null;
}
if (this.year < periodsNanbokuchouNorth.keys.first.$1) {
if (year < periodsNanbokuchouNorth.keys.first.$1) {
// TODO: find first where year <= this.year and jump one period back.
}
}
@@ -293,5 +293,5 @@ extension on DateTime {
/// Returns the date in Japanese format.
String japaneseDate({bool showWeekday = false}) =>
'$month月$day日' + (showWeekday ? '$japaneseWeekdayPrefix' : '');
'$month月$day日${showWeekday ? '$japaneseWeekdayPrefix' : ''}';
}

View File

@@ -183,7 +183,7 @@ class Lemmatized {
@override
String toString() {
final childrenString = children
.map((c) => ' - ' + c.toString().split('\n').join('\n '))
.map((c) => ' - ${c.toString().split('\n').join('\n ')}')
.join('\n');
if (children.isEmpty) {

View File

@@ -481,9 +481,9 @@ const Map<String, String> latin_to_hiragana = {
'#~': '',
};
bool _smallTsu(String for_conversion) => for_conversion == hiragana_small_tsu;
bool _nFollowedByYuYeYo(String for_conversion, String kana) =>
for_conversion == hiragana_syllabic_n &&
bool _smallTsu(String forConversion) => forConversion == hiragana_small_tsu;
bool _nFollowedByYuYeYo(String forConversion, String kana) =>
forConversion == hiragana_syllabic_n &&
kana.length > 1 &&
'やゆよ'.contains(kana.substring(1, 2));
@@ -495,17 +495,17 @@ String transliterateHiraganaToLatin(String hiragana) {
while (kana.isNotEmpty) {
final lengths = [if (kana.length > 1) 2, 1];
for (final length in lengths) {
final String for_conversion = kana.substring(0, length);
final String forConversion = kana.substring(0, length);
String? mora;
if (_smallTsu(for_conversion)) {
if (_smallTsu(forConversion)) {
geminate = true;
kana = kana.replaceRange(0, length, '');
break;
} else if (_nFollowedByYuYeYo(for_conversion, kana)) {
} else if (_nFollowedByYuYeYo(forConversion, kana)) {
mora = "n'";
}
mora ??= hiragana_to_latin[for_conversion];
mora ??= hiragana_to_latin[forConversion];
if (mora != null) {
if (geminate) {
@@ -516,7 +516,7 @@ String transliterateHiraganaToLatin(String hiragana) {
kana = kana.replaceRange(0, length, '');
break;
} else if (length == 1) {
romaji += for_conversion;
romaji += forConversion;
kana = kana.replaceRange(0, length, '');
}
}
@@ -524,14 +524,14 @@ String transliterateHiraganaToLatin(String hiragana) {
return romaji;
}
bool _doubleNFollowedByAIUEO(String for_conversion) =>
RegExp(r'^nn[aiueo]$').hasMatch(for_conversion);
bool _hasTableMatch(String for_conversion) =>
latin_to_hiragana[for_conversion] != null;
bool _hasDoubleConsonant(String for_conversion, int length) =>
for_conversion == 'tch' ||
bool _doubleNFollowedByAIUEO(String forConversion) =>
RegExp(r'^nn[aiueo]$').hasMatch(forConversion);
bool _hasTableMatch(String forConversion) =>
latin_to_hiragana[forConversion] != null;
bool _hasDoubleConsonant(String forConversion, int length) =>
forConversion == 'tch' ||
(length == 2 &&
RegExp(r'^([kgsztdnbpmyrlwchf])\1$').hasMatch(for_conversion));
RegExp(r'^([kgsztdnbpmyrlwchf])\1$').hasMatch(forConversion));
String transliterateLatinToHiragana(String latin) {
String romaji = latin
@@ -545,25 +545,25 @@ String transliterateLatinToHiragana(String latin) {
for (final length in lengths) {
String? mora;
int for_removal = length;
final String for_conversion = romaji.substring(0, length);
int forRemoval = length;
final String forConversion = romaji.substring(0, length);
if (_doubleNFollowedByAIUEO(for_conversion)) {
if (_doubleNFollowedByAIUEO(forConversion)) {
mora = hiragana_syllabic_n;
for_removal = 1;
} else if (_hasTableMatch(for_conversion)) {
mora = latin_to_hiragana[for_conversion];
} else if (_hasDoubleConsonant(for_conversion, length)) {
forRemoval = 1;
} else if (_hasTableMatch(forConversion)) {
mora = latin_to_hiragana[forConversion];
} else if (_hasDoubleConsonant(forConversion, length)) {
mora = hiragana_small_tsu;
for_removal = 1;
forRemoval = 1;
}
if (mora != null) {
kana += mora;
romaji = romaji.replaceRange(0, for_removal, '');
romaji = romaji.replaceRange(0, forRemoval, '');
break;
} else if (length == 1) {
kana += for_conversion;
kana += forConversion;
romaji = romaji.replaceRange(0, 1, '');
}
}

View File

@@ -1,3 +1,3 @@
String escapeStringValue(String value) {
return "'" + value.replaceAll("'", "''") + "'";
return "'${value.replaceAll("'", "''")}'";
}

View File

@@ -13,10 +13,10 @@ packages:
dependency: transitive
description:
name: analyzer
sha256: "754aed101003afceca3e6637fe88150dbe9739068e0135788a62645a131867bb"
sha256: b1ade5707ab7a90dfd519eaac78a7184341d19adb6096c68d499b59c7c6cf880
url: "https://pub.dev"
source: hosted
version: "7.5.9"
version: "7.7.0"
args:
dependency: "direct main"
description:
@@ -218,7 +218,7 @@ packages:
source: hosted
version: "2.2.0"
path:
dependency: transitive
dependency: "direct main"
description:
name: path
sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5"
@@ -322,13 +322,13 @@ packages:
source: hosted
version: "2.3.6"
sqlite3:
dependency: transitive
dependency: "direct main"
description:
name: sqlite3
sha256: c0503c69b44d5714e6abbf4c1f51a3c3cc42b75ce785f44404765e4635481d38
sha256: "608b56d594e4c8498c972c8f1507209f9fd74939971b948ddbbfbfd1c9cb3c15"
url: "https://pub.dev"
source: hosted
version: "2.7.6"
version: "2.7.7"
stack_trace:
dependency: transitive
description:

View File

@@ -11,8 +11,10 @@ dependencies:
collection: ^1.19.0
csv: ^6.0.0
equatable: ^2.0.0
path: ^1.9.1
sqflite_common: ^2.5.0
sqflite_common_ffi: ^2.3.0
sqlite3: ^2.7.7
xml: ^6.5.0
dev_dependencies:

View File

@@ -3,7 +3,7 @@ import 'package:jadb/const_data/kanji_grades.dart';
import 'package:test/test.dart';
void main() {
test("Assert 2136 kanji in jouyou set", () {
test('Assert 2136 kanji in jouyou set', () {
expect(JOUYOU_KANJI_BY_GRADES.values.flattenedToSet.length, 2136);
});
}

View File

@@ -4,26 +4,26 @@ import 'dart:io';
import 'package:jadb/models/create_empty_db.dart';
import 'package:jadb/search.dart';
import 'package:sqflite_common_ffi/sqflite_ffi.dart';
import 'package:test/test.dart';
import 'package:sqlite3/open.dart';
import 'package:test/test.dart';
Future<DatabaseExecutor> setup_inmemory_database() async {
final libsqlitePath = Platform.environment['LIBSQLITE_PATH'];
if (libsqlitePath == null) {
throw Exception("LIBSQLITE_PATH is not set");
throw Exception('LIBSQLITE_PATH is not set');
}
final db_connection = await createDatabaseFactoryFfi(
final dbConnection = await createDatabaseFactoryFfi(
ffiInit: () =>
open.overrideForAll(() => DynamicLibrary.open(libsqlitePath)),
).openDatabase(':memory:');
return db_connection;
return dbConnection;
}
void main() {
test("Create empty db", () async {
test('Create empty db', () async {
final db = await setup_inmemory_database();
await createEmptyDb(db);

View File

@@ -4,26 +4,26 @@ import 'package:test/test.dart';
import 'setup_database_connection.dart';
void main() {
test("Filter kanji", () async {
test('Filter kanji', () async {
final connection = await setup_database_connection();
final result = await connection.filterKanji([
"a",
"b",
"c",
"",
"",
"",
"",
"",
"",
".",
"!",
"@",
";",
"",
'a',
'b',
'c',
'',
'',
'',
'',
'',
'',
'.',
'!',
'@',
';',
'',
], deduplicate: false);
expect(result.join(), "漢字地字");
expect(result.join(), '漢字地字');
});
}

View File

@@ -5,16 +5,16 @@ import 'package:test/test.dart';
import 'setup_database_connection.dart';
void main() {
test("Search a kanji", () async {
test('Search a kanji', () async {
final connection = await setup_database_connection();
final result = await connection.jadbSearchKanji('');
expect(result, isNotNull);
});
group("Search all jouyou kanji", () {
group('Search all jouyou kanji', () {
JOUYOU_KANJI_BY_GRADES.forEach((grade, characters) {
test("Search all kanji in grade $grade", () async {
test('Search all kanji in grade $grade', () async {
final connection = await setup_database_connection();
for (final character in characters) {

View File

@@ -4,21 +4,21 @@ import 'package:jadb/_data_ingestion/open_local_db.dart';
import 'package:sqflite_common/sqlite_api.dart';
Future<Database> setup_database_connection() async {
final lib_sqlite_path = Platform.environment['LIBSQLITE_PATH'];
final jadb_path = Platform.environment['JADB_PATH'];
final libSqlitePath = Platform.environment['LIBSQLITE_PATH'];
final jadbPath = Platform.environment['JADB_PATH'];
if (lib_sqlite_path == null) {
throw Exception("LIBSQLITE_PATH is not set");
if (libSqlitePath == null) {
throw Exception('LIBSQLITE_PATH is not set');
}
if (jadb_path == null) {
throw Exception("JADB_PATH is not set");
if (jadbPath == null) {
throw Exception('JADB_PATH is not set');
}
final db_connection = await openLocalDb(
libsqlitePath: lib_sqlite_path,
jadbPath: jadb_path,
final dbConnection = await openLocalDb(
libsqlitePath: libSqlitePath,
jadbPath: jadbPath,
);
return db_connection;
return dbConnection;
}

View File

@@ -4,59 +4,59 @@ import 'package:test/test.dart';
import 'setup_database_connection.dart';
void main() {
test("Search a word - english - auto", () async {
test('Search a word - english - auto', () async {
final connection = await setup_database_connection();
final result = await connection.jadbSearchWord("kana");
final result = await connection.jadbSearchWord('kana');
expect(result, isNotNull);
});
test("Get word search count - english - auto", () async {
test('Get word search count - english - auto', () async {
final connection = await setup_database_connection();
final result = await connection.jadbSearchWordCount("kana");
final result = await connection.jadbSearchWordCount('kana');
expect(result, isNotNull);
});
test("Search a word - japanese kana - auto", () async {
test('Search a word - japanese kana - auto', () async {
final connection = await setup_database_connection();
final result = await connection.jadbSearchWord("かな");
final result = await connection.jadbSearchWord('かな');
expect(result, isNotNull);
});
test("Get word search count - japanese kana - auto", () async {
test('Get word search count - japanese kana - auto', () async {
final connection = await setup_database_connection();
final result = await connection.jadbSearchWordCount("かな");
final result = await connection.jadbSearchWordCount('かな');
expect(result, isNotNull);
});
test("Search a word - japanese kanji - auto", () async {
test('Search a word - japanese kanji - auto', () async {
final connection = await setup_database_connection();
final result = await connection.jadbSearchWord("仮名");
final result = await connection.jadbSearchWord('仮名');
expect(result, isNotNull);
});
test("Get word search count - japanese kanji - auto", () async {
test('Get word search count - japanese kanji - auto', () async {
final connection = await setup_database_connection();
final result = await connection.jadbSearchWordCount("仮名");
final result = await connection.jadbSearchWordCount('仮名');
expect(result, isNotNull);
});
test("Get a word by id", () async {
test('Get a word by id', () async {
final connection = await setup_database_connection();
final result = await connection.jadbGetWordById(1577090);
expect(result, isNotNull);
});
test(
"Serialize all words",
'Serialize all words',
() async {
final connection = await setup_database_connection();
// Test serializing all words
for (final letter in "aiueoksthnmyrw".split("")) {
for (final letter in 'aiueoksthnmyrw'.split('')) {
await connection.jadbSearchWord(letter);
}
},
timeout: Timeout.factor(100),
skip: "Very slow test",
skip: 'Very slow test',
);
}

View File

@@ -2,65 +2,65 @@ import 'package:jadb/util/romaji_transliteration.dart';
import 'package:test/test.dart';
void main() {
group("Romaji -> Hiragana", () {
test("Basic test", () {
final result = transliterateLatinToHiragana("katamari");
expect(result, "かたまり");
group('Romaji -> Hiragana', () {
test('Basic test', () {
final result = transliterateLatinToHiragana('katamari');
expect(result, 'かたまり');
});
test("Basic test with diacritics", () {
final result = transliterateLatinToHiragana("gadamari");
expect(result, "がだまり");
test('Basic test with diacritics', () {
final result = transliterateLatinToHiragana('gadamari');
expect(result, 'がだまり');
});
test("wi and we", () {
final result = transliterateLatinToHiragana("wiwe");
expect(result, "うぃうぇ");
test('wi and we', () {
final result = transliterateLatinToHiragana('wiwe');
expect(result, 'うぃうぇ');
});
test("nb = mb", () {
final result = transliterateLatinToHiragana("kanpai");
expect(result, "かんぱい");
test('nb = mb', () {
final result = transliterateLatinToHiragana('kanpai');
expect(result, 'かんぱい');
final result2 = transliterateLatinToHiragana("kampai");
expect(result2, "かんぱい");
final result2 = transliterateLatinToHiragana('kampai');
expect(result2, 'かんぱい');
});
test("Double n", () {
final result = transliterateLatinToHiragana("konnichiha");
expect(result, "こんにちは");
test('Double n', () {
final result = transliterateLatinToHiragana('konnichiha');
expect(result, 'こんにちは');
});
test("Double consonant", () {
final result = transliterateLatinToHiragana("kappa");
expect(result, "かっぱ");
test('Double consonant', () {
final result = transliterateLatinToHiragana('kappa');
expect(result, 'かっぱ');
});
});
group("Hiragana -> Romaji", () {
test("Basic test", () {
final result = transliterateHiraganaToLatin("かたまり");
expect(result, "katamari");
group('Hiragana -> Romaji', () {
test('Basic test', () {
final result = transliterateHiraganaToLatin('かたまり');
expect(result, 'katamari');
});
test("Basic test with diacritics", () {
final result = transliterateHiraganaToLatin("がだまり");
expect(result, "gadamari");
test('Basic test with diacritics', () {
final result = transliterateHiraganaToLatin('がだまり');
expect(result, 'gadamari');
});
test("whi and whe", () {
final result = transliterateHiraganaToLatin("うぃうぇ");
expect(result, "whiwhe");
test('whi and whe', () {
final result = transliterateHiraganaToLatin('うぃうぇ');
expect(result, 'whiwhe');
});
test("Double n", () {
final result = transliterateHiraganaToLatin("こんにちは");
expect(result, "konnichiha");
test('Double n', () {
final result = transliterateHiraganaToLatin('こんにちは');
expect(result, 'konnichiha');
});
test("Double consonant", () {
final result = transliterateHiraganaToLatin("かっぱ");
expect(result, "kappa");
test('Double consonant', () {
final result = transliterateHiraganaToLatin('かっぱ');
expect(result, 'kappa');
});
});
}