Skip to content

Commit b96a949

Browse files
committed
add seach operator for complete annotation status (complete:true)
1 parent 232bc01 commit b96a949

6 files changed

Lines changed: 68 additions & 44 deletions

File tree

core/api.ts

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// api.ts
22
// implementation for the API
33

4-
import { config, emitter } from './commons.js';
4+
import { emitter, isAnnotated } from './commons.js';
55
import type { Entry, Store, ToaduaConfig } from './commons.js';
66
import { Search } from './search.js';
77
import * as shared from '../frontend/shared/index.js';
@@ -15,9 +15,9 @@ import type { PresentedEntry } from './search.js';
1515
// Workaround for bcryptjs' broken types
1616
const bcrypt = bcryptjs as typeof bcryptjs_types;
1717

18-
const PRONOMINAL_CLASSES = ['ho', 'maq', 'hoq', 'ta', 'raı'];
18+
export const PRONOMINAL_CLASSES = ['ho', 'maq', 'hoq', 'ta', 'raı'];
1919

20-
const FRAMES = [
20+
export const FRAMES = [
2121
'c',
2222
'c c',
2323
'c c c',
@@ -46,7 +46,7 @@ const FRAMES = [
4646
'c c 2xx',
4747
];
4848

49-
const DISTRIBUTIONS = [
49+
export const DISTRIBUTIONS = [
5050
'd',
5151
'n',
5252
'd d',
@@ -63,9 +63,16 @@ const DISTRIBUTIONS = [
6363
'n n n',
6464
];
6565

66-
const SUBJECTS = ['agent', 'individual', 'event', 'predicate', 'shape', 'free'];
66+
export const SUBJECTS = [
67+
'agent',
68+
'individual',
69+
'event',
70+
'predicate',
71+
'shape',
72+
'free',
73+
];
6774

68-
const FIXED_ANNOTATION_FIELDS = [
75+
export const FIXED_ANNOTATION_FIELDS = [
6976
'pronominal_class',
7077
'frame',
7178
'distribution',
@@ -189,15 +196,10 @@ export class Api {
189196
}
190197

191198
public async count(i: any, uname: string): Promise<ApiResponse> {
192-
const count = this.store.db.entries.length;
193-
const annotated = this.store.db.entries.filter(
194-
e =>
195-
(e.gloss || e.type === 'phrase') &&
196-
(e.type === 'predicate' && e.body.includes('▯')
197-
? FIXED_ANNOTATION_FIELDS.every(field => e[field])
198-
: e.type),
199-
).length;
200-
return good({ count, annotated });
199+
return good({
200+
count: this.store.db.entries.length,
201+
annotated: this.store.db.entries.filter(isAnnotated).length,
202+
});
201203
}
202204

203205
public async vote(i: any, uname: string): Promise<ApiResponse> {

core/commons.ts

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { existsSync, readFileSync } from 'node:fs';
77
import * as yaml from 'js-yaml';
88
import { EventEmitter } from 'node:events';
99
import { cwd } from 'node:process';
10+
import { FIXED_ANNOTATION_FIELDS } from './api.js';
1011

1112
const old_log = console.log;
1213

@@ -47,6 +48,15 @@ export enum MatchMode {
4748
Exact = 2,
4849
}
4950

51+
export function isAnnotated(e: CommonEntry): boolean {
52+
return (
53+
(e.gloss || e.type === 'phrase') &&
54+
(e.type === 'predicate' && e.body.includes('▯')
55+
? FIXED_ANNOTATION_FIELDS.every(field => e[field])
56+
: !!e.type)
57+
);
58+
}
59+
5060
export function deburrMatch(
5161
what: string[],
5262
where: string[],
@@ -118,27 +128,13 @@ export interface Note {
118128
content: string;
119129
}
120130

121-
export interface Entry {
122-
/// An entry ID string like `AbCdEfGhI`.
123-
id: string;
124-
/// An ISO 8601 date string like `2022-12-28T21:38:31.682Z`.
125-
date: string;
131+
export interface CommonEntry {
126132
/// The Toaq word this entry is for.
127133
head: string;
128134
/// The gloss of the word.
129135
gloss: string | undefined;
130136
/// The definition of the word.
131137
body: string;
132-
/// The name of the user that added the entry.
133-
user: string;
134-
/// The scope (`en`, `toa`...) the entry is in.
135-
scope: string;
136-
/// Notes left on this entry.
137-
notes: Note[];
138-
/// Map from usernames to individual votes.
139-
votes: Record<string, -1 | 0 | 1>;
140-
/// Total score of the entry, aggregated from votes.
141-
score: number;
142138
/// The type of the entry, e.g. `"predicate"`.
143139
type: string | undefined;
144140
/// The pronominal class of the entry, e.g. `"maq"`.
@@ -151,6 +147,23 @@ export interface Entry {
151147
subject: string | undefined;
152148
}
153149

150+
export interface Entry extends CommonEntry {
151+
/// An entry ID string like `AbCdEfGhI`.
152+
id: string;
153+
/// An ISO 8601 date string like `2022-12-28T21:38:31.682Z`.
154+
date: string;
155+
/// The name of the user that added the entry.
156+
user: string;
157+
/// The scope (`en`, `toa`...) the entry is in.
158+
scope: string;
159+
/// Notes left on this entry.
160+
notes: Note[];
161+
/// Map from usernames to individual votes.
162+
votes: Record<string, -1 | 0 | 1>;
163+
/// Total score of the entry, aggregated from votes.
164+
score: number;
165+
}
166+
154167
export interface Token {
155168
/// Username the token is for.
156169
name: string;

core/search.ts

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@ import {
1111
type Entry,
1212
Note,
1313
type Store,
14+
isAnnotated,
1415
} from './commons.js';
16+
import { PRONOMINAL_CLASSES, SUBJECTS } from './api.js';
1517

1618
// keep an own cache for entries
1719
interface CachedEntry {
@@ -67,9 +69,7 @@ export function extract_pronominal_class(notes: Note[]): string | undefined {
6769
.normalize('NFD')
6870
.replace(/[\u0300-\u036f]/g, '')
6971
.replace('i', 'ı');
70-
if (
71-
['ho', 'maq', 'hoq', 'ta', 'raı', 'particle', 'phrase'].includes(value)
72-
) {
72+
if (PRONOMINAL_CLASSES.includes(value)) {
7373
return value;
7474
}
7575
}
@@ -108,20 +108,12 @@ export function extract_distribution(notes: Note[]): string | undefined {
108108
}
109109

110110
export function extract_subject(notes: Note[]): string | undefined {
111-
const validSubjects = [
112-
'agent',
113-
'individual',
114-
'event',
115-
'predicate',
116-
'shape',
117-
'free',
118-
];
119111
for (let i = notes.length - 1; i >= 0; i--) {
120112
const note = notes[i];
121113
const match = note.content.toLowerCase().match(/subject\s*:\s*(.*)/);
122114
if (match) {
123115
const value = match[1].trim();
124-
if (validSubjects.includes(value)) {
116+
if (SUBJECTS.includes(value)) {
125117
return value;
126118
}
127119
}
@@ -356,6 +348,14 @@ export class Search {
356348
entry =>
357349
uname ? (entry.$.votes[uname] || 0) === vote : false,
358350
},
351+
complete: {
352+
type: OperationType.Other,
353+
check: args => args.length === 1 && typeof args[0] === 'boolean',
354+
build:
355+
([b]) =>
356+
entry =>
357+
b === isAnnotated(entry.$),
358+
},
359359
before: {
360360
type: OperationType.Other,
361361
check: one_string,

frontend/App.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@
239239
v-if="username"
240240
style="float: right"
241241
href="javascript:void(0)"
242-
@click="navigate('pronoun:none')"
242+
@click="navigate('complete:false')"
243243
>help out</a
244244
>
245245
</span>

frontend/Result.vue

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,12 @@ defineProps<{
223223
spellcheck="true"
224224
style="width: 100%; margin: 0"
225225
></textarea>
226-
<p v-else class="body" v-html="fancy_body" style="margin: 0"></p>
226+
<p
227+
v-else
228+
class="body"
229+
v-html="shared.replacements(new_body, false, false, theme)"
230+
style="margin: 0"
231+
></p>
227232
</div>
228233
<p v-else class="body" v-html="fancy_body"></p>
229234

@@ -391,6 +396,8 @@ import * as shared from './shared/index';
391396
392397
export default defineComponent({
393398
methods: {
399+
shared: () => shared,
400+
394401
score_color(score: number): string {
395402
return shared.score_color(score, this.theme).css;
396403
},

frontend/shared/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,8 @@ export function parse_query(query_string: string): {
213213
parts[0],
214214
['arity', 'myvote'].includes(parts[0])
215215
? parseInt(parts[1], 10) || 0
216+
: ['complete'].includes(parts[0])
217+
? parts[1] === 'true'
216218
: parts[1],
217219
];
218220
} else {

0 commit comments

Comments
 (0)