mirror of
https://github.com/keymanapp/keyman.git
synced 2026-09-15 20:17:43 +00:00
chore(common/models): Merge branch 'feat/common/models/applyCasing' into feat/common/models/applyCasing-use
This commit is contained in:
commit
04032dabbb
9 changed files with 30 additions and 34 deletions
|
|
@ -100,7 +100,7 @@ namespace models {
|
|||
return suggestion;
|
||||
}
|
||||
|
||||
export function defaultApplyCasing(casing: CasingEnum, text: string): string {
|
||||
export function defaultApplyCasing(casing: CasingForm, text: string): string {
|
||||
switch(casing) {
|
||||
case 'lower':
|
||||
return text.toLowerCase();
|
||||
|
|
@ -118,7 +118,7 @@ namespace models {
|
|||
|
||||
if(lowSurrogateCode >= 0xDC00 && lowSurrogateCode <= 0xDFFF) {
|
||||
// We have a surrogate pair; this pair is the 'first' character.
|
||||
headUnitLength++;
|
||||
headUnitLength = 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
6
common/models/types/index.d.ts
vendored
6
common/models/types/index.d.ts
vendored
|
|
@ -17,7 +17,7 @@
|
|||
*/
|
||||
declare type USVString = string;
|
||||
|
||||
declare type CasingEnum = 'lower' | 'initial' | 'upper';
|
||||
declare type CasingForm = 'lower' | 'initial' | 'upper';
|
||||
|
||||
/**
|
||||
* Used to facilitate edit-distance calculations by allowing the LMLayer to
|
||||
|
|
@ -117,7 +117,7 @@ declare interface LexicalModel {
|
|||
* @param form
|
||||
* @param text
|
||||
*/
|
||||
applyCasing?(form: CasingEnum, text: string): string
|
||||
applyCasing?(form: CasingForm, text: string): string
|
||||
|
||||
/**
|
||||
* Indicates a mapping function used by the model to simplify lookup operations
|
||||
|
|
@ -497,7 +497,7 @@ declare interface WordBreakingFunction {
|
|||
}
|
||||
|
||||
declare interface CasingFunction {
|
||||
(caseToApply: CasingEnum, text: string, defaultApplyCasing?: CasingFunction): string;
|
||||
(caseToApply: CasingForm, text: string, defaultApplyCasing?: CasingFunction): string;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import * as ts from "typescript";
|
|||
import * as fs from "fs";
|
||||
import * as path from "path";
|
||||
import { createTrieDataStructure } from "./build-trie";
|
||||
import { ModelPseudoclosure } from "./model-pseudoclosure";
|
||||
import { ModelDefinitions } from "./model-definitions";
|
||||
import {decorateWithJoin} from "./join-word-breaker-decorator";
|
||||
import {decorateWithScriptOverrides} from "./script-overrides-decorator";
|
||||
|
||||
|
|
@ -50,28 +50,28 @@ export default class LexicalModelCompiler {
|
|||
// file, rather than the current working directory.
|
||||
let filenames = modelSource.sources.map(filename => path.join(sourcePath, filename));
|
||||
|
||||
let pseudoclosure = new ModelPseudoclosure(modelSource);
|
||||
let definitions = new ModelDefinitions(modelSource);
|
||||
|
||||
func += pseudoclosure.compilePseudoclosure();
|
||||
func += definitions.compileDefinitions();
|
||||
|
||||
// Needs the actual searchTermToKey closure...
|
||||
// Which needs the actual applyCasing closure as well.
|
||||
func += `LMLayerWorker.loadModel(new models.TrieModel(${
|
||||
createTrieDataStructure(filenames, pseudoclosure.searchTermToKey)
|
||||
createTrieDataStructure(filenames, definitions.searchTermToKey)
|
||||
}, {\n`;
|
||||
|
||||
let wordBreakerSourceCode = compileWordBreaker(normalizeWordBreakerSpec(modelSource.wordBreaker));
|
||||
func += ` wordBreaker: ${wordBreakerSourceCode},\n`;
|
||||
|
||||
// START - the lexical mapping option block
|
||||
func += ` searchTermToKey: ${pseudoclosure.compileSearchTermToKey()},\n`;
|
||||
func += ` searchTermToKey: ${definitions.compileSearchTermToKey()},\n`;
|
||||
|
||||
if(modelSource.languageUsesCasing != null) {
|
||||
func += ` languageUsesCasing: ${modelSource.languageUsesCasing},\n`;
|
||||
} // else leave undefined.
|
||||
|
||||
if(modelSource.languageUsesCasing) {
|
||||
func += ` applyCasing: ${pseudoclosure.compileApplyCasing()},\n`;
|
||||
func += ` applyCasing: ${definitions.compileApplyCasing()},\n`;
|
||||
}
|
||||
// END - the lexical mapping option block.
|
||||
|
||||
|
|
|
|||
|
|
@ -100,8 +100,7 @@ interface LexicalModelSource extends LexicalModelDeclaration {
|
|||
readonly rootClass?: string
|
||||
|
||||
/**
|
||||
* Indicates that the language being modeled has syntactic casing rules. When set to
|
||||
* `true`, suggestions will attempt to match the case of the input text even if
|
||||
* When set to `true`, suggestions will attempt to match the case of the input text even if
|
||||
* the lexicon entries use a different casing scheme due to search term keying effects.
|
||||
* @since 14.0
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ export function defaultCasedSearchTermToKey(wordform: string, applyCasing: Casin
|
|||
* This may be overwritten as appropriate in model-specific implementations.
|
||||
* @param text The text to be modified.
|
||||
*/
|
||||
export function defaultApplyCasing(casing: CasingEnum, text: string): string {
|
||||
export function defaultApplyCasing(casing: CasingForm, text: string): string {
|
||||
switch(casing) {
|
||||
case 'lower':
|
||||
return text.toLowerCase();
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import { defaultApplyCasing,
|
|||
* will very closely match the organizational patterns of this class in order to
|
||||
* facilitate the maintenance of this approach.
|
||||
*/
|
||||
export class ModelPseudoclosure {
|
||||
export class ModelDefinitions {
|
||||
static readonly COMPILED_NAME = 'definitions';
|
||||
/**
|
||||
* A closure fully implementing the model's defined `applyCasing` behavior with
|
||||
|
|
@ -74,7 +74,7 @@ export class ModelPseudoclosure {
|
|||
|
||||
// Since the defined casing function may expect to take our default implementation
|
||||
// as a parameter, we can define the full implementation via closure capture.
|
||||
this.applyCasing = function(casing: CasingEnum, text: string) {
|
||||
this.applyCasing = function(casing: CasingForm, text: string) {
|
||||
return _this.model.applyCasing(casing, text, _this.defaults.applyCasing);
|
||||
};
|
||||
} else {
|
||||
|
|
@ -124,9 +124,8 @@ export class ModelPseudoclosure {
|
|||
* This should be written to the file within the same IIFE as the model but BEFORE
|
||||
* the model itself, as the model will need to refer to the definitions herein.
|
||||
*/
|
||||
compilePseudoclosure(): string {
|
||||
compileDefinitions(): string {
|
||||
let defn: string = '';
|
||||
let PSEUDOCLOSURE = ModelPseudoclosure.COMPILED_NAME;
|
||||
defn += `let ${PSEUDOCLOSURE} = {\n`
|
||||
|
||||
// ----------------------
|
||||
|
|
@ -201,8 +200,6 @@ export class ModelPseudoclosure {
|
|||
* compiled pseudoclosure.
|
||||
*/
|
||||
compileSearchTermToKey(): string {
|
||||
let PSEUDOCLOSURE = ModelPseudoclosure.COMPILED_NAME;
|
||||
|
||||
// Simply point the model to the constructed closure defined by `compilePseudoclosure`.
|
||||
// See "START - compiled closures" section.
|
||||
return `${PSEUDOCLOSURE}.searchTermToKey`;
|
||||
|
|
@ -212,11 +209,11 @@ export class ModelPseudoclosure {
|
|||
* Compiles the model-options entry for `applyCasing` in reference to the
|
||||
* compiled pseudoclosure.
|
||||
*/
|
||||
compileApplyCasing(): string {
|
||||
let PSEUDOCLOSURE = ModelPseudoclosure.COMPILED_NAME;
|
||||
|
||||
// Simply point the model to the constructed closure defined by `compilePseudoclosure`.
|
||||
compileApplyCasing(): string {// Simply point the model to the constructed closure defined by `compilePseudoclosure`.
|
||||
// See "START - compiled closures" section.
|
||||
return `${PSEUDOCLOSURE}.applyCasing`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Because it references the class field, this line must come afterward.
|
||||
const PSEUDOCLOSURE = ModelDefinitions.COMPILED_NAME;
|
||||
|
|
@ -10,7 +10,7 @@ describe('LexicalModelCompiler - pseudoclosure compilation + use', function () {
|
|||
const PATH = path.join(__dirname, 'fixtures', MODEL_ID);
|
||||
|
||||
describe('specifying custom methods: applyCasing and searchTermToKey', function () {
|
||||
let casingWithPrependedSymbols: CasingFunction = function(casingName: CasingEnum, text: string, defaultApplyCasing: CasingFunction) {
|
||||
let casingWithPrependedSymbols: CasingFunction = function(casingName: CasingForm, text: string, defaultApplyCasing: CasingFunction) {
|
||||
switch(casingName) {
|
||||
// Use of symbols, and of the `casingName` name, exist to serve as regex targets.
|
||||
case 'lower':
|
||||
|
|
|
|||
|
|
@ -101,7 +101,7 @@ describe('The default searchTermToKey() function', function () {
|
|||
// as U+0130's default handling is... not ideal in Turkish.
|
||||
//
|
||||
// Instead, we can get a simple-enough test with inverted casing.
|
||||
let customCasing = function(caseToApply: CasingEnum,
|
||||
let customCasing = function(caseToApply: CasingForm,
|
||||
text: string,
|
||||
defaultApplyCasing: CasingFunction): string {
|
||||
switch(caseToApply) {
|
||||
|
|
@ -116,7 +116,7 @@ describe('The default searchTermToKey() function', function () {
|
|||
}
|
||||
}
|
||||
|
||||
let customCasingClosure = function(caseToApply: CasingEnum, text: string): string {
|
||||
let customCasingClosure = function(caseToApply: CasingForm, text: string): string {
|
||||
return customCasing(caseToApply, text, defaultApplyCasing);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import 'mocha';
|
||||
import { assert } from 'chai';
|
||||
import { ModelPseudoclosure } from '../dist/lexical-model-compiler/model-pseudoclosure';
|
||||
import { ModelDefinitions } from '../dist/lexical-model-compiler/model-definitions';
|
||||
|
||||
describe('Model definition pseudoclosures', function () {
|
||||
describe('14.0 defaults', function() {
|
||||
|
|
@ -13,7 +13,7 @@ describe('Model definition pseudoclosures', function () {
|
|||
format: 'trie-1.0'
|
||||
};
|
||||
|
||||
let pseudoclosure = new ModelPseudoclosure(modelSource);
|
||||
let pseudoclosure = new ModelDefinitions(modelSource);
|
||||
|
||||
const testCases: [string, string, string][] = [
|
||||
// Note: not written the Turkish way. Turns out 'İ'.toLowerCase() decomposes the result,
|
||||
|
|
@ -61,7 +61,7 @@ describe('Model definition pseudoclosures', function () {
|
|||
format: 'trie-1.0'
|
||||
};
|
||||
|
||||
let pseudoclosure = new ModelPseudoclosure(modelSource);
|
||||
let pseudoclosure = new ModelDefinitions(modelSource);
|
||||
|
||||
const testCases: [string, string][] = [
|
||||
// Note: not written the Turkish way. Turns out 'İ'.toLowerCase() decomposes the result,
|
||||
|
|
@ -99,7 +99,7 @@ describe('Model definition pseudoclosures', function () {
|
|||
format: 'trie-1.0'
|
||||
};
|
||||
|
||||
let pseudoclosure = new ModelPseudoclosure(modelSource);
|
||||
let pseudoclosure = new ModelDefinitions(modelSource);
|
||||
|
||||
const testCases: [string, string][] = [
|
||||
// Note: not written the Turkish way. Turns out 'İ'.toLowerCase() decomposes the result,
|
||||
|
|
@ -132,7 +132,7 @@ describe('Model definition pseudoclosures', function () {
|
|||
describe('Model-defined applyCasing + (dependent) searchTermToKey', function() {
|
||||
// Note: this test only implements enough Turkish-related stuff to facilitate
|
||||
// a functional test. Not guaranteed to be sufficient for actual Turkish use.
|
||||
let turkishCasing = function(form: CasingEnum, text: string, defaultApplyCasing: (form: CasingEnum, text: string) => string): string {
|
||||
let turkishCasing = function(form: CasingForm, text: string, defaultApplyCasing: (form: CasingForm, text: string) => string): string {
|
||||
switch(form) {
|
||||
case 'lower':
|
||||
return defaultApplyCasing(form, text
|
||||
|
|
@ -163,7 +163,7 @@ describe('Model definition pseudoclosures', function () {
|
|||
format: 'trie-1.0'
|
||||
};
|
||||
|
||||
let pseudoclosure = new ModelPseudoclosure(modelSource);
|
||||
let pseudoclosure = new ModelDefinitions(modelSource);
|
||||
|
||||
const testCases: [string, string, string][] = [
|
||||
['İstanbul', 'istanbul', 'istanbul'],
|
||||
Loading…
Add table
Reference in a new issue