Merge pull request #15376 from keymanapp/refactor/web/keyboard-storage

refactor(web): remove defaults in keyboard-storage

- Also renamed `prefixed` and `withoutPrefix` functions to use the name   that was aliased on most cases: `toPrefixedKeyboardId` and   `toUnprefixedKeyboardId`. 
- Renamed `ModelManager` class to `ModelCache` which was the name used   everywhere except in comments.

Part-of: #15292
This commit is contained in:
Eberhard Beilharz 2025-12-22 14:53:28 +01:00 • committed by GitHub
commit 4ba1fcbfb3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 37 additions and 41 deletions

View file

@ -247,7 +247,7 @@ function deregisterModel(modelID) {
}
function enableSuggestions(model, suggestionType) {
// Set the options first so that KMW's ModelManager can properly handle model enablement states
// Set the options first so that KMW's ModelCache can properly handle model enablement states
// the moment we actually register the new model.
// Use console_debug
console_debug('enableSuggestions(model, maySuggest='+suggestionType+')');

View file

@ -327,7 +327,7 @@ function toHex(theString) {
}
function enableSuggestions(model, mayPredict, mayCorrect) {
// Set the options first so that KMW's ModelManager can properly handle model enablement states
// Set the options first so that KMW's ModelCache can properly handle model enablement states
// the moment we actually register the new model.
keyman.core.languageProcessor.mayPredict = mayPredict;
keyman.core.languageProcessor.mayCorrect = mayCorrect;

View file

@ -1,2 +1,2 @@
export { CloudQueryResult, default as QueryEngine } from './queryEngine.js';
export { default as RequesterInterface } from './requesterInterface.js';
export { CloudQueryResult, CloudQueryEngine as QueryEngine } from './queryEngine.js';
export { CloudRequesterInterface as RequesterInterface } from './requesterInterface.js';

View file

@ -2,9 +2,9 @@ import { EventEmitter } from 'eventemitter3';
import { PathConfiguration } from 'keyman/engine/interfaces';
import { default as KeyboardStub, ErrorStub, KeyboardAPISpec } from '../keyboardStub.js';
import { KeyboardStub, ErrorStub, KeyboardAPISpec } from '../keyboardStub.js';
import { LanguageAPIPropertySpec, ManagedPromise, Version } from 'keyman/engine/keyboard';
import CloudRequesterInterface from './requesterInterface.js';
import { CloudRequesterInterface } from './requesterInterface.js';
// For when the API call straight-up times out.
export const CLOUD_TIMEOUT_ERR = "The Cloud API request timed out.";
@ -56,7 +56,7 @@ interface EventMap {
'unboundregister': (registration: ReturnType<CloudQueryEngine['_registerCore']>) => void
}
export default class CloudQueryEngine extends EventEmitter<EventMap> {
export class CloudQueryEngine extends EventEmitter<EventMap> {
private cloudResolutionPromises: Map<number, ManagedPromise<KeyboardStub[] | LanguageAPIPropertySpec[]>> = new Map();
private _languageListPromise: ManagedPromise<LanguageAPIPropertySpec[]>;

View file

@ -1,6 +1,6 @@
import { ManagedPromise } from 'keyman/engine/keyboard';
export default interface CloudRequesterInterface {
export interface CloudRequesterInterface {
request<T>(query: string): {
promise: ManagedPromise<T>,
queryId: number

View file

@ -1,8 +1,8 @@
import { ManagedPromise } from 'keyman/engine/keyboard';
import CloudRequesterInterface from './cloud/requesterInterface.js';
import { CloudRequesterInterface } from './cloud/requesterInterface.js';
import { CLOUD_MALFORMED_OBJECT_ERR, CLOUD_TIMEOUT_ERR, CLOUD_STUB_REGISTRATION_ERR } from './cloud/queryEngine.js';
export default class DOMCloudRequester implements CloudRequesterInterface {
export class DOMCloudRequester implements CloudRequesterInterface {
private readonly fileLocal: boolean;
constructor(fileLocal: boolean = false) {

View file

@ -2,15 +2,15 @@
export {
ErrorStub,
type KeyboardAPISpec,
default as KeyboardStub,
KeyboardStub,
mergeAndResolveStubPromises,
RawKeyboardStub,
REGIONS,
REGION_CODES
} from './keyboardStub.js';
export { default as StubAndKeyboardCache, toPrefixedKeyboardId, toUnprefixedKeyboardId } from './stubAndKeyboardCache.js';
export { CloudQueryResult, default as CloudQueryEngine } from './cloud/queryEngine.js';
export { default as CloudRequesterInterface } from './cloud/requesterInterface.js';
export { default as KeyboardRequisitioner } from './keyboardRequisitioner.js';
export { default as ModelCache } from './modelCache.js';
export { default as DOMCloudRequester } from './domCloudRequester.js';
export { StubAndKeyboardCache, toPrefixedKeyboardId, toUnprefixedKeyboardId } from './stubAndKeyboardCache.js';
export { CloudQueryResult, CloudQueryEngine } from './cloud/queryEngine.js';
export { CloudRequesterInterface } from './cloud/requesterInterface.js';
export { KeyboardRequisitioner } from './keyboardRequisitioner.js';
export { ModelCache } from './modelCache.js';
export { DOMCloudRequester } from './domCloudRequester.js';

View file

@ -17,7 +17,7 @@ import {
mergeAndResolveStubPromises,
toUnprefixedKeyboardId as unprefixed
} from "./index.js";
import { default as CloudRequesterInterface } from "./cloud/requesterInterface.js";
import { CloudRequesterInterface } from "./cloud/requesterInterface.js";
import { rejectErrorStubs } from "./keyboardStub.js";
class CloudRequestEntry {
@ -89,7 +89,7 @@ function isUniqueRequest(cache: StubAndKeyboardCache, cloudList: {id: string, la
};
// TODO: Move to the keyboard-cache child project - we can test it headlessly there!
export default class KeyboardRequisitioner {
export class KeyboardRequisitioner {
readonly cache: StubAndKeyboardCache;
readonly cloudQueryEngine: CloudQueryEngine;
readonly pathConfig: PathConfiguration;

View file

@ -48,7 +48,7 @@ function configureFilePathing(path: string, configurationBasePath: string) {
}
}
export default class KeyboardStub extends KeyboardProperties {
export class KeyboardStub extends KeyboardProperties {
KR: string;
KRC: string;
KF: string;

View file

@ -1,6 +1,6 @@
import { ModelSpec } from 'keyman/engine/interfaces';
export default class ModelManager {
export class ModelCache {
// Tracks registered models by ID.
private registeredModels: {[id: string]: ModelSpec} = {};

View file

@ -1,11 +1,11 @@
import { type Keyboard, JSKeyboard, KeyboardLoaderBase as KeyboardLoader, KMXKeyboard } from "keyman/engine/keyboard";
import { EventEmitter } from "eventemitter3";
import KeyboardStub from "./keyboardStub.js";
import { KeyboardStub } from "./keyboardStub.js";
const KEYBOARD_PREFIX = "Keyboard_";
function prefixed(text: string) {
export function toPrefixedKeyboardId(text: string) {
if(!text.startsWith(KEYBOARD_PREFIX)) {
return KEYBOARD_PREFIX + text;
} else {
@ -13,9 +13,7 @@ function prefixed(text: string) {
}
}
export {prefixed as toPrefixedKeyboardId};
function withoutPrefix(text: string) {
export function toUnprefixedKeyboardId(text: string) {
if(text.startsWith(KEYBOARD_PREFIX)) {
return text.substring(KEYBOARD_PREFIX.length);
} else {
@ -23,8 +21,6 @@ function withoutPrefix(text: string) {
}
}
export {withoutPrefix as toUnprefixedKeyboardId};
interface EventMap {
/**
* Indicates that the specified stub has just been registered within the cache.
@ -41,7 +37,7 @@ interface EventMap {
keyboardadded: (keyboard: Keyboard) => void;
}
export default class StubAndKeyboardCache extends EventEmitter<EventMap> {
export class StubAndKeyboardCache extends EventEmitter<EventMap> {
private stubSetTable: Record<string, Record<string, KeyboardStub>> = {};
private keyboardTable: Record<string, Keyboard | Promise<Keyboard>> = {};
@ -70,7 +66,7 @@ export default class StubAndKeyboardCache extends EventEmitter<EventMap> {
if(!keyboardID) {
return null;
}
const entry = this.keyboardTable[prefixed(keyboardID)];
const entry = this.keyboardTable[toPrefixedKeyboardId(keyboardID)];
// Unit testing may 'trip up' in the DOM, as bundled versions of a class from one bundled
// module will fail against an `instanceof` expecting the version bundled in a second.
@ -123,7 +119,7 @@ export default class StubAndKeyboardCache extends EventEmitter<EventMap> {
}
addKeyboard(keyboard: Keyboard) {
const keyboardID = prefixed(keyboard.id);
const keyboardID = toPrefixedKeyboardId(keyboard.id);
this.keyboardTable[keyboardID] = keyboard;
this.emit('keyboardadded', keyboard);
@ -138,7 +134,7 @@ export default class StubAndKeyboardCache extends EventEmitter<EventMap> {
throw new Error("Keyboard ID must be specified");
}
keyboardID = prefixed(keyboardID);
keyboardID = toPrefixedKeyboardId(keyboardID);
const cachedEntry = this.keyboardTable[keyboardID];
return cachedEntry instanceof Promise;
@ -153,7 +149,7 @@ export default class StubAndKeyboardCache extends EventEmitter<EventMap> {
throw new Error("Cannot load keyboards; this cache was configured without a loader");
}
keyboardID = prefixed(keyboardID);
keyboardID = toPrefixedKeyboardId(keyboardID);
const cachedEntry = this.keyboardTable[keyboardID];
if(cachedEntry instanceof JSKeyboard) {
@ -164,11 +160,11 @@ export default class StubAndKeyboardCache extends EventEmitter<EventMap> {
const stub = this.getStub(keyboardID, null);
if(!stub) {
throw new Error(`No stub for ${withoutPrefix(keyboardID)} has been registered`);
throw new Error(`No stub for ${toUnprefixedKeyboardId(keyboardID)} has been registered`);
}
if(!stub.filename) {
throw new Error(`The registered stub for ${withoutPrefix(keyboardID)} lacks a path to the main keyboard file`);
throw new Error(`The registered stub for ${toUnprefixedKeyboardId(keyboardID)} lacks a path to the main keyboard file`);
}
const promise = this.keyboardLoader.loadKeyboardFromStub(stub);
@ -189,7 +185,7 @@ export default class StubAndKeyboardCache extends EventEmitter<EventMap> {
}
addStub(stub: KeyboardStub) {
const keyboardID = prefixed(stub.KI);
const keyboardID = toPrefixedKeyboardId(stub.KI);
const stubTable = this.stubSetTable[keyboardID] = this.stubSetTable[keyboardID] ?? {};
stubTable[stub.KLC] = stub;
@ -213,7 +209,7 @@ export default class StubAndKeyboardCache extends EventEmitter<EventMap> {
}
if(keyboardID) {
keyboardID = prefixed(keyboardID);
keyboardID = toPrefixedKeyboardId(keyboardID);
}
const stubTable = this.stubSetTable[keyboardID] ?? {};
@ -238,7 +234,7 @@ export default class StubAndKeyboardCache extends EventEmitter<EventMap> {
* If `false`, only forgets the metadata (stubs).
*/
forgetKeyboard(keyboard: string | JSKeyboard, purge: boolean = false) {
const id: string = (keyboard instanceof JSKeyboard) ? keyboard.id : prefixed(keyboard);
const id: string = (keyboard instanceof JSKeyboard) ? keyboard.id : toPrefixedKeyboardId(keyboard);
if(this.stubSetTable[id]) {
delete this.stubSetTable[id];

View file

@ -360,7 +360,7 @@ export class LanguageProcessor extends EventEmitter<LanguageProcessorEventMap> {
/**
* Retrieves the context and output state of KMW immediately before the prediction with
* token `id` was generated. Must correspond to a 'recent' one, as only so many are stored
* in `ModelManager`'s history buffer.
* in `ModelCache`'s history buffer.
* @param id A unique identifier corresponding to a recent `Transcription`.
* @returns The matching `Transcription`, or `null` none is found.
*/

View file

@ -1,10 +1,10 @@
import { ManagedPromise } from 'keyman/engine/keyboard';
import CloudRequesterInterface from '../../../../engine/src/keyboard-storage/cloud/requesterInterface.js';
import { CloudRequesterInterface } from '../../../../engine/src/keyboard-storage/cloud/requesterInterface.js';
import {
CLOUD_TIMEOUT_ERR,
CLOUD_STUB_REGISTRATION_ERR,
CloudQueryResult,
default as CloudQueryEngine
CloudQueryEngine
} from '../../../../engine/src/keyboard-storage/cloud/queryEngine.js';
import fs from 'node:fs';