feat(developer): LDML keyboard compiler - infrastructure

This commit is contained in:
Marc Durdin 2022-08-23 10:27:34 +10:00
parent 3c7279deb8
commit 1a0b67a242
8 changed files with 324 additions and 0 deletions

2
developer/src/kmldmlc/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
tsconfig.tsbuildinfo
build/

View file

@ -0,0 +1,37 @@
#
# Keyman Developer - LDML Keyboard Compiler Makefile
#
!include ..\Defines.mak
configure: .virtual
$(GIT_BASH_FOR_KEYMAN) build.sh configure
build: .virtual
$(GIT_BASH_FOR_KEYMAN) build.sh build
clean: .virtual
$(GIT_BASH_FOR_KEYMAN) build.sh clean
test: .virtual
$(GIT_BASH_FOR_KEYMAN) build.sh test
bundle: .virtual
$(GIT_BASH_FOR_KEYMAN) build.sh bundle
publish: .virtual
$(GIT_BASH_FOR_KEYMAN) build.sh publish
signcode:
@rem nothing to do
wrap-symbols:
@rem nothing to do
test-manifest:
@rem nothing to do
install:
@rem nothing to do
!include ..\Target.mak

View file

@ -0,0 +1,44 @@
Keyman Developer - LDML Keyboard Compiler
================
This package provides the following Keyman **command line tool**:
- `kmldmlc` — takes **LDML Keyboard .xml sources** and compiles them in to a
KMXPlus **.kmx** file.
Install
-------
Install `kmlmdlc` globally:
npm install -g @keymanapp/ldml-keyboard-compiler
Usage
-----
To compile a lexical model from its `.xml` source, use `kmldmlc`:
kmldmlc my-keyboard.xml --outFile my-keyboard.kmx
To see more command line options by using the `--help` option:
kmldmlc --help
How to build from source
------------------------
Run `build.sh`:
./build.sh configure build
How to run the tests
--------------------
./build.sh test
How to prepare a bundle
-----------------------
./build.sh bundle

View file

@ -0,0 +1,93 @@
#!/usr/bin/env bash
#
# Compiles the developer tools, including the language model compilers.
#
# Exit on command failure and when using unset variables:
set -eu
## START STANDARD BUILD SCRIPT INCLUDE
# adjust relative paths as necessary
THIS_SCRIPT="$(greadlink -f "${BASH_SOURCE[0]}" 2>/dev/null || readlink -f "${BASH_SOURCE[0]}")"
. "$(dirname "$THIS_SCRIPT")/../../../resources/build/build-utils.sh"
## END STANDARD BUILD SCRIPT INCLUDE
cd "$THIS_SCRIPT_PATH"
. "$KEYMAN_ROOT/resources/shellHelperFunctions.sh"
builder_describe "Build Keyman LDML Keyboard Compiler kmldmlc" \
"configure runs 'npm ci' on root folder" \
"build (default) builds kmldmlc to build/" \
"clean cleans build/ folder" \
"bundle creates a bundled version of kmldmlc" \
"test run automated tests for kmldmlc" \
"publish publish to npm" \
"--dry-run ???"
builder_parse "$@"
#-------------------------------------------------------------------------------------------------------------------
if builder_has_action configure; then
verify_npm_setup
builder_report success configure
fi
#-------------------------------------------------------------------------------------------------------------------
if builder_has_action clean; then
rm -rf ./build/ ./tsconfig.tsbuildinfo
builder_report success clean
fi
#-------------------------------------------------------------------------------------------------------------------
if builder_has_action build; then
npm run build
builder_report success build
fi
#-------------------------------------------------------------------------------------------------------------------
if builder_has_action test; then
npm test
builder_report success test
fi
#-------------------------------------------------------------------------------------------------------------------
if builder_has_action bundle; then
echo TODO: Bundle
builder_report success bundle
fi
#-------------------------------------------------------------------------------------------------------------------
if builder_has_action publish; then
if [[ $TIER == stable ]]; then
npm_dist_tag=latest
else
npm_dist_tag=$TIER
fi
set_npm_version
if build_has_option --dry-run; then
DRY_RUN=--dry-run
else
DRY_RUN=
fi
#TEMP: we don't want to publish at this point!
DRY_RUN=--dry-run
# Note: In either case, npm publish MUST be given --access public to publish
# a package in the @keymanapp scope on the public npm package index.
#
# See `npm help publish` for more details.
echo "Publishing $DRY_RUN npm package with tag $npm_dist_tag"
npm publish $DRY_RUN --access public --tag $npm_dist_tag || fail "Could not publish $npm_dist_tag release."
builder_report success publish
fi

View file

@ -0,0 +1,40 @@
{
"name": "@keymanapp/ldml-keyboard-compiler",
"description": "Keyman Developer LDML keyboard compiler",
"keywords": [
"keyboard",
"keyman",
"ldml",
"unicode"
],
"scripts": {
"build": "tsc -b",
"test": "cd src/test && tsc -b && cd .. && mocha",
"prepublishOnly": "npm run build"
},
"author": "Marc Durdin <marc@keyman.com> (https://github.com/mcdurdin)",
"license": "MIT",
"main": "build/kmldmlc.js",
"bin": {
"kmldmlc": "build/kmldmlc.js"
},
"dependencies": {
"commander": "^3.0.0",
"typescript": "^4.5.4",
"xml2js": "^0.4.19"
},
"devDependencies": {
"@keymanapp/keyman-version": "*",
"@types/chai": "^4.1.7",
"@types/mocha": "^5.2.7",
"@types/node": "^10.14.6",
"@types/xml2js": "^0.4.5",
"chai": "^4.3.4",
"chalk": "^2.4.2",
"mocha": "^8.4.0",
"ts-node": "^9.1.1"
},
"mocha": {
"spec": "build-tests/**/test-*.js"
}
}

View file

@ -0,0 +1,20 @@
interface CompilerCallbacks {
loadFile(baseFilename:string, filename: string): Buffer;
reportMessage(severity: number, message: string): void;
};
export default class Compiler {
private callbacks: CompilerCallbacks;
constructor (callbacks: CompilerCallbacks) {
this.callbacks = callbacks;
//TEMP
this.callbacks.reportMessage(0, "Instantiated compiler successfully");
}
public compile(filename: string): Buffer {
// TODO
return Buffer.from("KXTS..." + filename, 'utf8');
}
}

View file

@ -0,0 +1,62 @@
#!/usr/bin/env node
/**
* kmldmlc - Keyman LDML Keyboard Compiler
*/
import * as fs from 'fs';
import * as path from 'path';
import * as program from 'commander';
import Compiler from './keyman/ldmlkeyboard/compiler';
let inputFilename: string;
const KEYMAN_VERSION = require("@keymanapp/keyman-version").KEYMAN_VERSION;
/* Arguments */
program
.description('Compiles Keyman LDML keyboards')
.version(KEYMAN_VERSION.VERSION_WITH_TAG)
.arguments('<infile>')
.action(infile => inputFilename = infile)
.option('-o, --outFile <filename>', 'where to save the resulting .kmx file');
program.parse(process.argv);
// Deal with input arguments:
if (!inputFilename) {
exitDueToUsageError('Must provide a LDML keyboard .xml source file.');
}
function exitDueToUsageError(message: string): never {
console.error(`${program._name}: ${message}`);
console.error();
program.outputHelp();
return process.exit(64); // TODO: SysExits.EX_USAGE
}
class CompilerCallbacks {
loadFile(baseFilename: string, filename:string): Buffer {
// TODO: translate filename based on the baseFilename
return fs.readFileSync(filename);
}
reportMessage(severity: number, message: string): void {
console.log(message);
}
}
function compileKeyboard(inputFilename: string): Buffer {
const c = new CompilerCallbacks();
const k = new Compiler(c);
return k.compile(inputFilename);
}
// Compile:
let code = compileKeyboard(inputFilename);
// Output:
if(code) {
const outFile = program.outFile ?? path.join(path.dirname(inputFilename), path.basename(inputFilename, '.xml') + '.kmx');
fs.writeFileSync(outFile, code);
}

View file

@ -0,0 +1,26 @@
{
"extends": "../../../tsconfig-base.json",
"compilerOptions": {
"module": "commonjs",
"target": "es2017",
"moduleResolution": "node",
"sourceMap": true,
"outDir": "build/",
"rootDir": "src/",
"declaration": true,
"alwaysStrict": true,
"noImplicitThis": true,
"noImplicitReturns": true,
"noImplicitAny": true,
"strictBindCallApply": true,
"strictFunctionTypes": true,
"noUnusedLocals": true
},
"include": [
"src/**/*.ts"
],
"references": [
{ "path": "../../../common/web/keyman-version" },
]
}