Skip to content

Commit

Permalink
chore(developer): Merge branch 'master' into feat/developer/kmc-packa…
Browse files Browse the repository at this point in the history
…ge-source-files-from-remotes-2
  • Loading branch information
mcdurdin committed Dec 2, 2024
2 parents 952087f + ca9ac81 commit 7e17684
Show file tree
Hide file tree
Showing 380 changed files with 1,788 additions and 893 deletions.
2 changes: 2 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Contributing to Keyman

(Keyman team members, see also the [onboarding](https://docs.google.com/document/d/1i6fBi9K38-LitcJZiRfAvRu1-7H0iQ_op5kxDMdhSec/edit?usp=sharing) doc)

⭐ Thank you for your contribution! ⭐

The following is a set of guidelines for contributing to Keyman, Keyman
Expand Down
52 changes: 52 additions & 0 deletions HISTORY.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,57 @@
# Keyman Version History

## 18.0.149 alpha 2024-12-01

* refactor(developer): unify test action (#12736)

## 18.0.148 alpha 2024-11-29

* test(common/web/types): unit tests for unicodeset-parser-api (#12714)
* chore(developer): rename test files (#12707)
* feat(core,linux,developer,windows): implement loading KMX from blob (#12721)
* chore(common): add offline support for emscripten (#12740)

## 18.0.147 alpha 2024-11-28

* docs(android): Add android/docs/internal/README (#12717)
* test(common/web/types): unit tests for string-list (#12702)
* docs(common): linux and macOS emscripten setup (#12701)
* refactor(developer): output number of tests when running on TC (#12710)
* refactor(common): output number of tests when running on TC (#12719)
* chore(web): rename file missed in #12704 (#12720)
* fix(core): permanently disable logging (#12724)
* fix(linux): disable assertions in release builds of ibus-keyman (#12725)
* chore(common): improve offline builds (#12739)

## 18.0.146 alpha 2024-11-27

* test(developer): kmcmplib compiler unit tests 5 (#12612)
* refactor(common): move all lexical model types into `LexicalModelTypes` container (#12712)
* refactor(common): move remaining LDML keyboard types into `LdmlKeyboardTypes` (#12713)
* chore(web): rename test files and folders (#12704)
* chore(core): rename test files (#12705)
* chore(linux): rename test files (#12706)

## 18.0.145 alpha 2024-11-26

* docs(windows): update emscripten bash setup (#12700)
* chore(common): Add link to onboarding doc to `CONTRIBUTING.md` (#12697)

## 18.0.144 alpha 2024-11-25

* chore(deps): bump cross-spawn from 7.0.3 to 7.0.6 in /developer/src/server/src/win32/trayicon/addon-src (#12687)
* chore(developer): make package subfile description fully optional (#12665)
* fix(developer): box package compiler info fields (#12666)
* fix(developer): correct whitespace handling in virtual keys and remove partially implemented virtual key series in kmcmplib compiler (#12604)

## 18.0.143 alpha 2024-11-22

* chore(deps): bump cross-spawn from 7.0.3 to 7.0.6 (#12685)

## 18.0.142 alpha 2024-11-20

* chore(common): Update CODEOWNERS (#12680)

## 18.0.141 alpha 2024-11-15

* chore(linux): add support for Ubuntu 25.04 Plucky Puffin (#12675)
Expand Down
2 changes: 1 addition & 1 deletion VERSION.md
Original file line number Diff line number Diff line change
@@ -1 +1 @@
18.0.142
18.0.150
13 changes: 10 additions & 3 deletions android/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ analytics for Debug are associated with an App Bundle ID
### Compiling From Command Line

1. Launch a command prompt and cd to the directory **keyman/android**
2. Run the top level build script `./build.sh configure build --debug` which will:
2. Run the top level build script `./build.sh configure build:engine build:app --debug` which will:
* Compile KMEA (and its KMW dependency)
* Download default keyboard and dictionary resources as needed
* Compile KMAPro
Expand Down Expand Up @@ -79,7 +79,7 @@ analytics for Debug are associated with an App Bundle ID
Replace `SERIAL` with the device serial number listed in step 2.

### Compiling the app's offline help
Keyman for Android help is maintained in the Markdown files in android/docs/.
Keyman for Android help is maintained in the Markdown files in android/docs/help.
The script `/resources/build/build-help.inc.sh` uses the `pandoc` tool to convert the Markdown files into html.

```bash
Expand Down Expand Up @@ -121,7 +121,7 @@ Building these projects follow the same steps as KMAPro:

## How to Build Keyman Engine for Android
1. Open a terminal or Git Bash prompt and go to the Android project folder (e.g. `cd ~/keyman/android/`)
2. Run `./build.sh --debug`
2. Run `./build.sh build:engine --debug`

Keyman Engine for Android library (**keyman-engine.aar**) is now ready to be imported in any project.

Expand Down Expand Up @@ -167,3 +167,10 @@ dependencies {
````
5. include `import com.keyman.engine.*;` to use Keyman Engine in a class.

### Keyman Engine for Android help content
Keyman Engine for Android help is maintained in the Markdown files in android/docs/engine/.

## Design Documentation

Internal design documents about features pertaining to Keyman for Android and Keyman Engine for Android are maintained in the Markdown files in android/docs/internal/.
5 changes: 5 additions & 0 deletions android/docs/internal/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Keyman for Android and Keyman Engine for Android

## Internal Documents

This folder is for storing design documents of new features pertaining to Keyman for Android and Keyman Engine for Android
3 changes: 2 additions & 1 deletion common/web/types/.gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
src/schemas/
obj/
obj/
coverage/
9 changes: 8 additions & 1 deletion common/web/types/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -80,13 +80,20 @@ function do_configure() {
}

function do_test() {
local MOCHA_FLAGS=

if [[ "${TEAMCITY_GIT_PATH:-}" != "" ]]; then
# we're running in TeamCity
MOCHA_FLAGS="-reporter mocha-teamcity-reporter"
fi

eslint .
tsc --build test

readonly C8_THRESHOLD=60

# Excludes are defined in .c8rc.json
c8 -skip-full --reporter=lcov --reporter=text --lines $C8_THRESHOLD --statements $C8_THRESHOLD --branches $C8_THRESHOLD --functions $C8_THRESHOLD mocha "${builder_extra_params[@]}"
c8 -skip-full --reporter=lcov --reporter=text --lines $C8_THRESHOLD --statements $C8_THRESHOLD --branches $C8_THRESHOLD --functions $C8_THRESHOLD mocha ${MOCHA_FLAGS} "${builder_extra_params[@]}"
builder_echo warning "Coverage thresholds are currently $C8_THRESHOLD%, which is lower than ideal."
builder_echo warning "Please increase threshold in build.sh as test coverage improves."
}
Expand Down
8 changes: 8 additions & 0 deletions common/web/types/src/main-ldml-keyboard.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/*
* Keyman is copyright (C) SIL Global. MIT License.
*
* Just a wrapper to make `LdmlKeyboardTypes` export work.
*/
export { UnicodeSetParser, UnicodeSet } from './ldml-keyboard/unicodeset-parser-api.js';
export { VariableParser, MarkerParser } from './ldml-keyboard/pattern-parser.js';
export { ElementString } from './kmx/kmx-plus/element-string.js';
7 changes: 2 additions & 5 deletions common/web/types/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,8 @@ export * as Schemas from './schemas.js';
export * as SchemaValidators from './schema-validators.js';

export * as KMXPlus from './kmx/kmx-plus/kmx-plus.js';
// TODO: these exports are really not well named
export { UnicodeSetParser, UnicodeSet } from './ldml-keyboard/unicodeset-parser-api.js';
export { VariableParser, MarkerParser } from './ldml-keyboard/pattern-parser.js';
export { ElementString } from './kmx/kmx-plus/element-string.js';
export * as LdmlKeyboardTypes from './main-ldml-keyboard.js';

export { USVString, CasingForm, CasingFunction, TextWithProbability, LexiconTraversal, LexicalModel, LexicalModelPunctuation, Transform, Suggestion, Reversion, Keep, SuggestionTag, Context, Distribution, Outcome, WithOutcome, ProbabilityMass, Configuration, Capabilities, WordBreakingFunction, Span } from './lexical-model-types.js';
export * as LexicalModelTypes from './lexical-model-types.js';

export * as KeymanWebKeyboard from './keyboard-object.js';
216 changes: 216 additions & 0 deletions common/web/types/test/ldml-keyboard/test-string-list.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
/*
* Keyman is copyright (C) SIL Global. MIT License.
*
* Created by Dr Mark C. Sinclair on 2024-11-28
*
* Test code for string-lists.ts
*/

import 'mocha';
import { assert } from 'chai';
import { StrsItem, StrsOptions, DependencySections, Strs } from '../../src/kmx/kmx-plus/kmx-plus.js';
import { ListIndex, ListItem } from '../../src/ldml-keyboard/string-list.js';

describe('Test of String-List', () => {
describe('Test ListIndex', () => {
it('can construct a ListIndex', () => {
const strsItem = new StrsItem("abc");
const actual = new ListIndex(strsItem);
assert.deepEqual(actual.value, strsItem);
});
it('can check two ListIndex for equality', () => {
const listItemOne = new ListIndex(new StrsItem("abc"));
const listItemTwo = new ListIndex(new StrsItem("abc"));
assert.isTrue(listItemOne.isEqual(listItemTwo));
});
it('can check two different ListIndex are not equal', () => {
const listItemOne = new ListIndex(new StrsItem("abc"));
const listItemTwo = new ListIndex(new StrsItem("def"));
assert.isFalse(listItemOne.isEqual(listItemTwo));
});
it('can check a ListIndex and string for equality', () => {
const listItem = new ListIndex(new StrsItem("abc"));
const aString = "abc";
assert.isTrue(listItem.isEqual(aString));
});
it('can check a ListIndex and string for inequality', () => {
const listItem = new ListIndex(new StrsItem("abc"));
const aString = "def";
assert.isFalse(listItem.isEqual(aString));
});
it('can provide a correct string representation', () => {
const strsItem = new StrsItem("abc");
const listItem = new ListIndex(strsItem);
const expected = "abc";
assert.deepEqual(listItem.toString(), expected);
});
});
describe('Test ListItem', () => {
describe('Test fromStrings()', () => {
it('should return an empty ListItem if source is null', () => {
const actual = ListItem.fromStrings(null, null, null);
const expected = new ListItem();
assert.deepEqual(actual, expected);
});
it('should return a valid ListItem from a single source string', () => {
const source = ["abc"];
const sections = { strs: new Strs };
sections.strs.allocString = stubSectionsStrsAllocString;
const actual = ListItem.fromStrings(source, null, sections);
const expected = initListItem(source);
assert.deepEqual(actual, expected);
});
it('should return a valid ListItem from a longer source', () => {
const source = ["abc", "def", "ghi"];
const sections = { strs: new Strs };
sections.strs.allocString = stubSectionsStrsAllocString;
const actual = ListItem.fromStrings(source, null, sections);
const expected = initListItem(source);
assert.deepEqual(actual, expected);
});
});
describe('Test getItemOrder()', () => {
it('should return a valid index for the first item', () => {
const listItem = initListItem(["abc", "def", "ghi"]);
const index = listItem.getItemOrder("abc");
assert.equal(index, 0);
});
it('should return a valid index for a later item', () => {
const listItem = initListItem(["abc", "def", "ghi"]);
const index = listItem.getItemOrder("ghi");
assert.equal(index, 2);
});
it('should return -1 for a missing item', () => {
const listItem = initListItem(["abc", "def", "ghi"]);
const index = listItem.getItemOrder("jkl");
assert.equal(index, -1);
});
});
describe('Test isEqual()', () => {
it('should return true for two empty ListItems', () => {
const listItemOne = new ListItem();
const listItemTwo = new ListItem();
assert.isTrue(listItemOne.isEqual(listItemTwo));
});
it('should return false for empty and non-empty ListItems', () => {
const listItemOne = new ListItem();
const listItemTwo = initListItem(["abc"]);
assert.isFalse(listItemOne.isEqual(listItemTwo));
});
it('should return false for non-empty and empty ListItems', () => {
const listItemOne = initListItem(["abc"]);
const listItemTwo = new ListItem();
assert.isFalse(listItemOne.isEqual(listItemTwo));
});
it('should return true for identical ListItems', () => {
const listItemOne = initListItem(["abc", "def", "ghi"]);
const listItemTwo = initListItem(["abc", "def", "ghi"]);
assert.isTrue(listItemOne.isEqual(listItemTwo));
});
it('should return false for different ListItems', () => {
const listItemOne = initListItem(["abc", "def", "ghi"]);
const listItemTwo = initListItem(["abd", "def", "ghi"]);
assert.isFalse(listItemOne.isEqual(listItemTwo));
});
it('should return false for different length ListItems', () => {
const listItemOne = initListItem(["abc", "def"]);
const listItemTwo = initListItem(["abc", "def", "ghi"]);
assert.isFalse(listItemOne.isEqual(listItemTwo));
});
it('should return true for empty ListItem and string[]', () => {
const listItem = new ListItem();
assert.isTrue(listItem.isEqual([]));
});
it('should return false for empty ListItem and non-empty string[]', () => {
const listItem = new ListItem();
assert.isFalse(listItem.isEqual(["abc"]));
});
it('should return false for non-empty ListItem and empty string[]', () => {
const listItem = initListItem(["abc"]);;
assert.isFalse(listItem.isEqual([]));
});
it('should return true for identical ListItem and string[]', () => {
const listItem = initListItem(["abc", "def", "ghi"]);
assert.isTrue(listItem.isEqual(["abc", "def", "ghi"]));
});
it('should return false for different ListItem and string[]', () => {
const listItem = initListItem(["abc", "def", "ghi"]);
assert.isFalse(listItem.isEqual(["abd", "def", "ghi"]));
});
it('should return false for different length ListItem and string[]', () => {
const listItem = initListItem(["abc", "def"]);
assert.isFalse(listItem.isEqual(["abc", "def", "ghi"]));
});
});
describe('Test compareTo()', () => {
it('should return 0 for identical ListItems', () => {
const listItemOne = initListItem(["abc", "def", "ghi"]);
const listItemTwo = initListItem(["abc", "def", "ghi"]);
assert.equal(listItemOne.compareTo(listItemTwo), 0);
});
it('should return -1 for ListItems with different first items (smallest first)', () => {
const listItemOne = initListItem(["abc", "def", "ghi"]);
const listItemTwo = initListItem(["abd", "def", "ghi"]);
assert.equal(listItemOne.compareTo(listItemTwo), -1);
});
it('should return 1 for ListItems with different first items (smallest second)', () => {
const listItemOne = initListItem(["abd", "def", "ghi"]);
const listItemTwo = initListItem(["abc", "def", "ghi"]);
assert.equal(listItemOne.compareTo(listItemTwo), 1);
});
it('should return -1 for ListItems with different later items (smallest first)', () => {
const listItemOne = initListItem(["abc", "def", "ghi"]);
const listItemTwo = initListItem(["abc", "def", "ghj"]);
assert.equal(listItemOne.compareTo(listItemTwo), -1);
});
it('should return 1 for ListItems with different later items (smallest second)', () => {
const listItemOne = initListItem(["abc", "def", "ghj"]);
const listItemTwo = initListItem(["abc", "def", "ghi"]);
assert.equal(listItemOne.compareTo(listItemTwo), 1);
});
it('should return -1 for identical ListItems, except shorter first', () => {
const listItemOne = initListItem(["abc", "def", "ghi"]);
const listItemTwo = initListItem(["abc", "def", "ghi", "jkl"]);
assert.equal(listItemOne.compareTo(listItemTwo), -1);
});
it('should return 1 for identical ListItems, except longer first', () => {
const listItemOne = initListItem(["abc", "def", "ghi", "jkl"]);
const listItemTwo = initListItem(["abc", "def", "ghi"]);
assert.equal(listItemOne.compareTo(listItemTwo), 1);
});
});
describe('Test toString()', () => {
it('should return correct string', () => {
const listItem = initListItem(["abc", "def", "ghi"]);
assert.deepEqual(listItem.toString(), "abc def ghi");
});
it('should return correct string for empty ListItem', () => {
const listItem = new ListItem;
assert.deepEqual(listItem.toString(), "");
});
});
describe('Test toStringArray()', () => {
it('should return correct string[]', () => {
const source = ["abc", "def", "ghi"];
const listItem = initListItem(source);
assert.deepEqual(listItem.toStringArray(), source);
});
it('should return correct string[] for empty ListItem', () => {
const listItem = new ListItem;
assert.deepEqual(listItem.toStringArray(), []);
});
});
});
});

function stubSectionsStrsAllocString(s?: string, opts?: StrsOptions, sections?: DependencySections): StrsItem {
return new StrsItem(s);
}

function initListItem(source: Array<string>): ListItem {
const listItem = new ListItem();
for (const s of source) {
listItem.push(new ListIndex(new StrsItem(s)));
}
return listItem;
}
Loading

0 comments on commit 7e17684

Please sign in to comment.