From a2015560d893673aa5822af16923ae0f807930ac Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Thu, 15 Aug 2024 14:38:57 +0200 Subject: [PATCH 1/9] chore(developer): establish kmc-convert epic --- developer/src/kmc-convert/README.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 developer/src/kmc-convert/README.md diff --git a/developer/src/kmc-convert/README.md b/developer/src/kmc-convert/README.md new file mode 100644 index 0000000000..e938e3b8f8 --- /dev/null +++ b/developer/src/kmc-convert/README.md @@ -0,0 +1,6 @@ +# Keyman Developer - kmc-convert + +This package provides keyboard conversion tools. It can be used from the +command line with [@keymanapp/kmc](https://npmjs.com/package/@keymanapp/kmc). + +* [API Reference](https://help.keyman.com/developer/current-version/reference/api/kmc-convert) From c600b7372e2fb245f485171d35695897481bf7c3 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Thu, 15 Aug 2024 16:52:29 +0200 Subject: [PATCH 2/9] feat(developer): introduce kmc-convert kmc-convert is a new module that will provide keyboard source file conversion classes. --- developer/src/README.md | 4 + developer/src/build.sh | 1 + .../web/utils/src/compiler-interfaces.ts | 4 + developer/src/kmc-convert/.eslintrc.cjs | 11 + developer/src/kmc-convert/build.sh | 51 +++++ developer/src/kmc-convert/package.json | 68 ++++++ .../kmc-convert/src/converter-artifacts.ts | 27 +++ .../src/converter-class-factory.ts | 22 ++ .../src/kmc-convert/src/converter-messages.ts | 30 +++ .../src/kmc-convert/src/converter-options.ts | 17 ++ developer/src/kmc-convert/src/converter.ts | 111 ++++++++++ .../keylayout-to-kmn-converter.ts | 27 +++ developer/src/kmc-convert/src/main.ts | 9 + .../src/kmc-convert/test/helpers/index.ts | 44 ++++ .../test/test-converter-messages.ts | 13 ++ .../test/test-keylayout-to-kmn-converter.ts | 28 +++ developer/src/kmc-convert/test/tsconfig.json | 19 ++ developer/src/kmc-convert/tsconfig.json | 16 ++ developer/src/kmc/build.sh | 1 + developer/src/kmc/package.json | 1 + developer/src/kmc/src/commands/convert.ts | 73 ++++++ developer/src/kmc/src/kmc.ts | 2 + .../src/kmc/src/messages/messageNamespaces.ts | 3 + developer/src/kmc/tsconfig.json | 1 + developer/src/packages.inc.sh | 1 + developer/src/tools/sentry-upload-difs.sh | 1 + package-lock.json | 208 +++++++++++++++++- package.json | 1 + tsconfig.json | 2 + 29 files changed, 795 insertions(+), 1 deletion(-) create mode 100644 developer/src/kmc-convert/.eslintrc.cjs create mode 100755 developer/src/kmc-convert/build.sh create mode 100644 developer/src/kmc-convert/package.json create mode 100644 developer/src/kmc-convert/src/converter-artifacts.ts create mode 100644 developer/src/kmc-convert/src/converter-class-factory.ts create mode 100644 developer/src/kmc-convert/src/converter-messages.ts create mode 100644 developer/src/kmc-convert/src/converter-options.ts create mode 100644 developer/src/kmc-convert/src/converter.ts create mode 100644 developer/src/kmc-convert/src/keylayout-to-kmn/keylayout-to-kmn-converter.ts create mode 100644 developer/src/kmc-convert/src/main.ts create mode 100644 developer/src/kmc-convert/test/helpers/index.ts create mode 100644 developer/src/kmc-convert/test/test-converter-messages.ts create mode 100644 developer/src/kmc-convert/test/test-keylayout-to-kmn-converter.ts create mode 100644 developer/src/kmc-convert/test/tsconfig.json create mode 100644 developer/src/kmc-convert/tsconfig.json create mode 100644 developer/src/kmc/src/commands/convert.ts diff --git a/developer/src/README.md b/developer/src/README.md index 7e7ea9d336..984d0f103a 100644 --- a/developer/src/README.md +++ b/developer/src/README.md @@ -54,6 +54,10 @@ node-based next generation compiler, hosts kmc, (and legacy kmlmc, kmlmp) File analysis tools for Keyman files. +### kmc-convert - Keyboard conversion tools + +Tools for converting keyboard source files between various formats. + ### kmc-keyboard-info - Keyboard Info Compiler Builds .keyboard_info files for use on the Keyman Cloud keyboard repository diff --git a/developer/src/build.sh b/developer/src/build.sh index b45dea38f5..d257647ac6 100755 --- a/developer/src/build.sh +++ b/developer/src/build.sh @@ -22,6 +22,7 @@ builder_describe \ ":ext Third party components" \ ":kmcmplib Compiler - .kmn compiler" \ ":kmc-analyze Compiler - Analysis Tools" \ + ":kmc-convert Compiler - Keyboard Conversion Tools" \ ":kmc-keyboard-info Compiler - .keyboard_info Module" \ ":kmc-kmn Compiler - .kmn to .kmx and .js Keyboard Module" \ ":kmc-ldml Compiler - LDML Keyboard Module" \ diff --git a/developer/src/common/web/utils/src/compiler-interfaces.ts b/developer/src/common/web/utils/src/compiler-interfaces.ts index e4ed62d750..44792311ef 100644 --- a/developer/src/common/web/utils/src/compiler-interfaces.ts +++ b/developer/src/common/web/utils/src/compiler-interfaces.ts @@ -263,6 +263,10 @@ export enum CompilerErrorNamespace { * kmc-keyboard-info 0x9000…0x9FFF */ KeyboardInfoCompiler = 0x9000, + /** + * kmc-convert 0xA000…0xAFFF + */ + Converter = 0xA000, }; /** diff --git a/developer/src/kmc-convert/.eslintrc.cjs b/developer/src/kmc-convert/.eslintrc.cjs new file mode 100644 index 0000000000..7dc652a7c4 --- /dev/null +++ b/developer/src/kmc-convert/.eslintrc.cjs @@ -0,0 +1,11 @@ +module.exports = { + parserOptions: { + project: ["./tsconfig.json", "./test/tsconfig.json"], + }, + ignorePatterns: ["test/fixtures/**/*"], + overrides: [ + { + files:"src/**/*.ts", + } + ], +}; diff --git a/developer/src/kmc-convert/build.sh b/developer/src/kmc-convert/build.sh new file mode 100755 index 0000000000..962c9ad035 --- /dev/null +++ b/developer/src/kmc-convert/build.sh @@ -0,0 +1,51 @@ +#!/usr/bin/env bash +## START STANDARD BUILD SCRIPT INCLUDE +# adjust relative paths as necessary +THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")" +. "${THIS_SCRIPT%/*}/../../../resources/build/builder.inc.sh" +## END STANDARD BUILD SCRIPT INCLUDE + +. "$KEYMAN_ROOT/resources/build/build-utils-ci.inc.sh" +. "$KEYMAN_ROOT/resources/shellHelperFunctions.sh" + +builder_describe "Keyman kmc-convert keyboard conversion tools module" \ + "@/common/web/types" \ + "@/developer/src/kmc-kmn" \ + "@/developer/src/common/web/utils" \ + "@/developer/src/common/web/test-helpers" \ + "configure" \ + "build" \ + "api analyze API and prepare API documentation" \ + "clean" \ + "test" \ + "publish publish to npm" \ + "--npm-publish+ For publish, do a npm publish, not npm pack (only for CI)" \ + "--dry-run,-n don't actually publish, just dry run" + +builder_describe_outputs \ + configure /node_modules \ + build /developer/src/kmc-convert/build/src/main.js \ + api /developer/build/api/kmc-convert.api.json + +builder_parse "$@" + +#------------------------------------------------------------------------------------------------------------------- + +builder_run_action clean rm -rf ./build/ ./tsconfig.tsbuildinfo +builder_run_action configure verify_npm_setup +builder_run_action build tsc --build +builder_run_action api api-extractor run --local --verbose + +do_test() { + eslint . + cd test + tsc -b + cd .. + readonly C8_THRESHOLD=20 + c8 -skip-full --reporter=lcov --reporter=text --lines $C8_THRESHOLD --statements $C8_THRESHOLD --branches $C8_THRESHOLD --functions $C8_THRESHOLD mocha "${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." +} + +builder_run_action test do_test +builder_run_action publish builder_publish_npm diff --git a/developer/src/kmc-convert/package.json b/developer/src/kmc-convert/package.json new file mode 100644 index 0000000000..78a0d457fd --- /dev/null +++ b/developer/src/kmc-convert/package.json @@ -0,0 +1,68 @@ +{ + "name": "@keymanapp/kmc-convert", + "description": "Keyman Developer keyboard conversion tools", + "keywords": [ + "keyboard", + "keyman", + "ldml", + "unicode", + "xkb", + "keylayout", + "inkey", + "kmn", + "msklc" + ], + "type": "module", + "exports": { + ".": "./build/src/main.js" + }, + "files": [ + "/build/src/" + ], + "scripts": { + "build": "gosh ./build.sh build", + "test": "gosh ./build.sh test" + }, + "author": "Sabine Schmitt", + "license": "MIT", + "bugs": { + "url": "https://github.com/keymanapp/keyman/issues" + }, + "dependencies": { + "@keymanapp/developer-utils": "*", + "@keymanapp/kmc-kmn": "*" + }, + "devDependencies": { + "@keymanapp/developer-test-helpers": "*", + "@keymanapp/resources-gosh": "*", + "@types/mocha": "^5.2.7", + "@types/node": "^20.4.1", + "@types/semver": "^7.3.12", + "c8": "^7.12.0", + "chalk": "^2.4.2", + "mocha": "^8.4.0", + "typescript": "^5.4.5" + }, + "mocha": { + "spec": "build/test/**/test-*.js", + "require": [ + "source-map-support/register" + ] + }, + "c8": { + "all": true, + "src": [ + "src/" + ], + "exclude-after-remap": true, + "exclude": [ + "test/", + "src/converter-options.ts", + "src/converter-artifacts.ts" + ] + }, + "repository": { + "type": "git", + "url": "git+https://github.com/keymanapp/keyman.git" + } +} diff --git a/developer/src/kmc-convert/src/converter-artifacts.ts b/developer/src/kmc-convert/src/converter-artifacts.ts new file mode 100644 index 0000000000..49b454cca1 --- /dev/null +++ b/developer/src/kmc-convert/src/converter-artifacts.ts @@ -0,0 +1,27 @@ +/* + * Keyman is copyright (C) SIL International. MIT License. + * + * Output artifacts available from kmc-convert + */ +import { KeymanCompilerArtifactOptional, KeymanCompilerArtifacts } from '@keymanapp/developer-utils'; + +export interface ConverterArtifacts extends KeymanCompilerArtifacts { } + +/** + * @public + * Internal in-memory build artifacts from a successful compilation + */ +export interface ConverterToKmnArtifacts extends ConverterArtifacts { + /** + * Source keyboard filedata and filename + */ + kmn?: KeymanCompilerArtifactOptional; + /** + * Source on screen keyboard filedata and filename + */ + kvks?: KeymanCompilerArtifactOptional; + /** + * Source touch keyboard filedata and filename + */ + keymanTouchLayout?: KeymanCompilerArtifactOptional; +}; diff --git a/developer/src/kmc-convert/src/converter-class-factory.ts b/developer/src/kmc-convert/src/converter-class-factory.ts new file mode 100644 index 0000000000..2176b3df00 --- /dev/null +++ b/developer/src/kmc-convert/src/converter-class-factory.ts @@ -0,0 +1,22 @@ +/* + * Keyman is copyright (C) SIL International. MIT License. + * + * Lists all the available converters and finds matching converter + */ +import { KeylayoutToKmnConverter } from './keylayout-to-kmn/keylayout-to-kmn-converter.js'; + +const converters = [ + KeylayoutToKmnConverter, +]; + +export class ConverterClassFactory { + static find(inputFilename: string, outputFilename: string) { + + const converter = converters.find(c => + inputFilename.endsWith(c.INPUT_FILE_EXTENSION) && + outputFilename.endsWith(c.OUTPUT_FILE_EXTENSION) + ); + + return converter; + } +} diff --git a/developer/src/kmc-convert/src/converter-messages.ts b/developer/src/kmc-convert/src/converter-messages.ts new file mode 100644 index 0000000000..c270464f21 --- /dev/null +++ b/developer/src/kmc-convert/src/converter-messages.ts @@ -0,0 +1,30 @@ +/* + * Keyman is copyright (C) SIL International. MIT License. + * + * Converter messages + */ +import { CompilerErrorNamespace, CompilerErrorSeverity, CompilerMessageSpec as m, CompilerMessageDef as def } from '@keymanapp/developer-utils'; + +const Namespace = CompilerErrorNamespace.Converter; +// const SevInfo = CompilerErrorSeverity.Info | Namespace; +// const SevHint = CompilerErrorSeverity.Hint | Namespace; +// const SevWarn = CompilerErrorSeverity.Warn | Namespace; +const SevError = CompilerErrorSeverity.Error | Namespace; +// const SevFatal = CompilerErrorSeverity.Fatal | Namespace; + +/** + * @internal + */ +export class ConverterMessages { + static ERROR_OutputFilenameIsRequired = SevError | 0x0001; + static Error_OutputFilenameIsRequired = () => + m(this.ERROR_OutputFilenameIsRequired, `An output filename is required for keyboard conversion.`); + + static ERROR_NoConverterFound = SevError | 0x0002; + static Error_NoConverterFound = (o:{inputFilename: string, outputFilename: string}) => + m(this.ERROR_NoConverterFound, `No converter is available that can convert from '${def(o.inputFilename)}' to '${def(o.outputFilename)}'.`); + + static ERROR_FileNotFound = SevError | 0x0003; + static Error_FileNotFound = (o:{inputFilename: string}) => + m(this.ERROR_FileNotFound, `Input filename '${def(o.inputFilename)}' does not exist or could not be loaded.`); +} diff --git a/developer/src/kmc-convert/src/converter-options.ts b/developer/src/kmc-convert/src/converter-options.ts new file mode 100644 index 0000000000..9fdaa109f9 --- /dev/null +++ b/developer/src/kmc-convert/src/converter-options.ts @@ -0,0 +1,17 @@ +/* + * Keyman is copyright (C) SIL International. MIT License. + * + * Converter options + */ +import { CompilerOptions } from "@keymanapp/developer-utils"; + +/** + * @public + * Options for the keyboard converter + */ +export interface ConverterOptions extends CompilerOptions { + /** + * Fail if the keyboard conversion is not 100% complete + */ + failIfIncomplete?: boolean; +}; diff --git a/developer/src/kmc-convert/src/converter.ts b/developer/src/kmc-convert/src/converter.ts new file mode 100644 index 0000000000..0a35bb3bc8 --- /dev/null +++ b/developer/src/kmc-convert/src/converter.ts @@ -0,0 +1,111 @@ +/* + * Keyman is copyright (C) SIL International. MIT License. + * + * Infrastructure for keyboard source file conversion tools + */ +import { + CompilerCallbacks, + CompilerOptions, + defaultCompilerOptions, + KeymanCompiler, + KeymanCompilerResult, +} from "@keymanapp/developer-utils"; +import { ConverterClassFactory } from './converter-class-factory.js'; +import { ConverterArtifacts } from "./converter-artifacts.js"; +import { ConverterMessages } from "./converter-messages.js"; + +export interface ConverterResult extends KeymanCompilerResult { + /** + * Internal in-memory build artifacts from a successful compilation. Caller + * can write these to disk with {@link Converter.write} + */ + artifacts: ConverterArtifacts; +}; + +/** + * @public + * Converts keyboards between different source file formats. The + * compiler does not read or write from filesystem or network directly, but + * relies on callbacks for all external IO. + */ +export class Converter implements KeymanCompiler { + private callbacks: CompilerCallbacks; + private options: CompilerOptions; + + /** + * Initialize the converter. Copies options. + * @param callbacks - Callbacks for external interfaces, including message + * reporting and file io + * @param options - Compiler options + * @returns false if initialization fails + */ + async init(callbacks: CompilerCallbacks, options: CompilerOptions): Promise { + this.options = { ...options }; + this.callbacks = callbacks; + return true; + } + + /** + * Converts a keyboard source file to another format. Returns an object + * containing source artifacts on success. The files are passed in by name, + * and the compiler will use callbacks as passed to the {@link Converter.init} + * function to read any input files by disk. + * @param infile - Path to source file. + * @param outfile - Path to output file. The file will not be written to, but + * will be included in the result for use by + * {@link Converter.write}. + * @returns Source artifacts on success, null on failure. + */ + async run(inputFilename: string, outputFilename?: string): Promise { + + const converterOptions: CompilerOptions = { + ...defaultCompilerOptions, + ...this.options, + }; + + if(!outputFilename) { + this.callbacks.reportMessage(ConverterMessages.Error_OutputFilenameIsRequired()); + return null; + } + + const ConverterClass = ConverterClassFactory.find(inputFilename, outputFilename); + if(!ConverterClass) { + this.callbacks.reportMessage(ConverterMessages.Error_NoConverterFound({inputFilename, outputFilename})); + return null; + } + + const binaryData = this.callbacks.loadFile(inputFilename); + if(!binaryData) { + this.callbacks.reportMessage(ConverterMessages.Error_FileNotFound({inputFilename})); + return null; + } + + const converter = new ConverterClass(this.callbacks, converterOptions); + const artifacts = await converter.run(inputFilename, outputFilename, binaryData); + // Note: any subsequent errors in conversion will have been reported by the converter + return artifacts ? { artifacts } : null; + } + + /** + * Write artifacts from a successful compile to disk, via callbacks methods. + * The artifacts written may include: + * + * - .kmn file - source keyboard used by Keyman on desktop platforms + * - .kvks file - source on screen keyboard used by Keyman on desktop platforms + * - .keyman-touch-layout file - source touch layout keyboard for touch platforms + * - other keyboard source files as implemented + * + * @param artifacts - object containing artifact data to write out + * @returns true on success + */ + async write(artifacts: ConverterArtifacts): Promise { + for(const key of Object.keys(artifacts)) { + if(artifacts[key]) { + this.callbacks.fs.writeFileSync(artifacts[key].filename, artifacts[key].data); + } + } + + return true; + } +} + diff --git a/developer/src/kmc-convert/src/keylayout-to-kmn/keylayout-to-kmn-converter.ts b/developer/src/kmc-convert/src/keylayout-to-kmn/keylayout-to-kmn-converter.ts new file mode 100644 index 0000000000..7b0c1d29e0 --- /dev/null +++ b/developer/src/kmc-convert/src/keylayout-to-kmn/keylayout-to-kmn-converter.ts @@ -0,0 +1,27 @@ +/* + * Keyman is copyright (C) SIL International. MIT License. + * + * Converts macOS/Ukelele .keylayout files to Keyman .kmn + */ +import { CompilerCallbacks, CompilerOptions } from "@keymanapp/developer-utils"; +import { ConverterToKmnArtifacts } from "../converter-artifacts.js"; + +export class KeylayoutToKmnConverter { + static readonly INPUT_FILE_EXTENSION = '.keylayout'; + static readonly OUTPUT_FILE_EXTENSION = '.kmn'; + + constructor(/*private*/ _callbacks: CompilerCallbacks, /*private*/ _options: CompilerOptions) { + // TODO: if these are needed, uncomment /*private*/ and remove _, and they will then + // be available as class properties + } + + async run(inputFilename: string, outputFilename: string, binaryData: Uint8Array): Promise { + if(!inputFilename || !outputFilename || !binaryData) { + throw new Error('Invalid parameters'); + } + + console.error('TODO: implement KeylayoutToKmnConverter'); + + return null; + } +} \ No newline at end of file diff --git a/developer/src/kmc-convert/src/main.ts b/developer/src/kmc-convert/src/main.ts new file mode 100644 index 0000000000..4719c0a6c9 --- /dev/null +++ b/developer/src/kmc-convert/src/main.ts @@ -0,0 +1,9 @@ +/* + * Keyman is copyright (C) SIL International. MIT License. + * + * Keyboard source file conversion tools + */ + +export { Converter } from './converter.js'; +export { ConverterOptions } from './converter-options.js'; +export { ConverterMessages } from './converter-messages.js'; diff --git a/developer/src/kmc-convert/test/helpers/index.ts b/developer/src/kmc-convert/test/helpers/index.ts new file mode 100644 index 0000000000..ea6d9d0e3d --- /dev/null +++ b/developer/src/kmc-convert/test/helpers/index.ts @@ -0,0 +1,44 @@ +/* + * Keyman is copyright (C) SIL International. MIT License. + * + * Helpers and utilities for the Mocha tests. + */ +import * as path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import 'mocha'; +import { assert } from 'chai'; +import { compilerEventFormat, CompilerOptions, } from "@keymanapp/developer-utils"; +import { TestCompilerCallbacks } from '@keymanapp/developer-test-helpers'; + + +/** + * Builds a path to the fixture with the given path components. + * + * e.g., makePathToFixture('basic.xml') + * + * @param components One or more path components. + */ +export function makePathToFixture(...components: string[]): string { + return fileURLToPath(new URL(path.join('..', '..', '..', 'test', 'fixtures', ...components), import.meta.url)); +} + +export const compilerTestCallbacks = new TestCompilerCallbacks(); + +export const compilerTestOptions: CompilerOptions = {}; + +beforeEach(function() { + compilerTestCallbacks.clear(); +}); + +afterEach(function() { + if (this.currentTest.state !== 'passed') { + compilerTestCallbacks.messages.forEach(message => console.log(message.message)); + } +}); + +export function checkMessages() { + if(compilerTestCallbacks.messages.length > 0) { + console.log(compilerTestCallbacks.messages); + } + assert.isEmpty(compilerTestCallbacks.messages, compilerEventFormat(compilerTestCallbacks.messages)); +} diff --git a/developer/src/kmc-convert/test/test-converter-messages.ts b/developer/src/kmc-convert/test/test-converter-messages.ts new file mode 100644 index 0000000000..3eb2a16618 --- /dev/null +++ b/developer/src/kmc-convert/test/test-converter-messages.ts @@ -0,0 +1,13 @@ +/* + * Keyman is copyright (C) SIL International. MIT License. + */ +import 'mocha'; +import { ConverterMessages } from './converter-messages.js'; +import { verifyCompilerMessagesObject } from '@keymanapp/developer-test-helpers'; +import { CompilerErrorNamespace } from '@keymanapp/developer-utils'; + +describe('ConverterMessages', function () { + it('should have a valid ConverterMessages object', function() { + return verifyCompilerMessagesObject(ConverterMessages, CompilerErrorNamespace.Converter); + }); +}); diff --git a/developer/src/kmc-convert/test/test-keylayout-to-kmn-converter.ts b/developer/src/kmc-convert/test/test-keylayout-to-kmn-converter.ts new file mode 100644 index 0000000000..449dba9afc --- /dev/null +++ b/developer/src/kmc-convert/test/test-keylayout-to-kmn-converter.ts @@ -0,0 +1,28 @@ +/* + * Keyman is copyright (C) SIL International. MIT License. + */ +import 'mocha'; +import {assert} from 'chai'; +import {compilerTestCallbacks, compilerTestOptions} from './helpers/index.js'; +import {KeylayoutToKmnConverter} from '../src/keylayout-to-kmn/keylayout-to-kmn-converter.js'; + +describe('KeylayoutToKmnConverter', function() { + + before(function() { + compilerTestCallbacks.clear(); + }); + + it('should throw on null inputs', async function () { + // const inputFilename = makePathToFixture('file.keylayout'); + const converter = new KeylayoutToKmnConverter(compilerTestCallbacks, compilerTestOptions); + // note, could use 'chai as promised' library to make this more fluent: + let threw = false; + try { + await converter.run(null, null, null); + } catch { + threw = true; + } + assert.isTrue(threw); + }); + + }); diff --git a/developer/src/kmc-convert/test/tsconfig.json b/developer/src/kmc-convert/test/tsconfig.json new file mode 100644 index 0000000000..0b380f93a7 --- /dev/null +++ b/developer/src/kmc-convert/test/tsconfig.json @@ -0,0 +1,19 @@ +{ + "extends": "../../kmc/tsconfig.kmc-base.json", + + "compilerOptions": { + "rootDir": ".", + "rootDirs": ["./", "../src/"], + "outDir": "../build/test", + "baseUrl": ".", + }, + "include": [ + "**/test-*.ts", + "./helpers/index.ts", + ], + "references": [ + { "path": "../../../../common/web/types/" }, + { "path": "../../common/web/test-helpers/" }, + { "path": "../" } + ] +} \ No newline at end of file diff --git a/developer/src/kmc-convert/tsconfig.json b/developer/src/kmc-convert/tsconfig.json new file mode 100644 index 0000000000..825efda721 --- /dev/null +++ b/developer/src/kmc-convert/tsconfig.json @@ -0,0 +1,16 @@ +{ + "extends": "../../../tsconfig.base.json", + + "compilerOptions": { + "outDir": "build/src/", + "rootDir": "src/", + "baseUrl": ".", + }, + "include": [ + "src/**/*.ts" + ], + "references": [ + { "path": "../../../common/web/types/" }, + { "path": "../kmc-kmn/" }, + ] +} diff --git a/developer/src/kmc/build.sh b/developer/src/kmc/build.sh index a3bf11774a..f10a4500f9 100755 --- a/developer/src/kmc/build.sh +++ b/developer/src/kmc/build.sh @@ -18,6 +18,7 @@ builder_describe "Build Keyman Keyboard Compiler kmc" \ "@/common/web/types" \ "@/developer/src/common/web/utils" \ "@/developer/src/kmc-analyze" \ + "@/developer/src/kmc-convert" \ "@/developer/src/kmc-keyboard-info" \ "@/developer/src/kmc-kmn" \ "@/developer/src/kmc-ldml" \ diff --git a/developer/src/kmc/package.json b/developer/src/kmc/package.json index d6486e1685..1355014a53 100644 --- a/developer/src/kmc/package.json +++ b/developer/src/kmc/package.json @@ -38,6 +38,7 @@ "@keymanapp/developer-utils": "*", "@keymanapp/keyman-version": "*", "@keymanapp/kmc-analyze": "*", + "@keymanapp/kmc-convert": "*", "@keymanapp/kmc-keyboard-info": "*", "@keymanapp/kmc-kmn": "*", "@keymanapp/kmc-ldml": "*", diff --git a/developer/src/kmc/src/commands/convert.ts b/developer/src/kmc/src/commands/convert.ts new file mode 100644 index 0000000000..c03b0c5427 --- /dev/null +++ b/developer/src/kmc/src/commands/convert.ts @@ -0,0 +1,73 @@ +/* + * Keyman is copyright (C) SIL International. MIT License. + * + * Declares the 'convert' command line action + */ +import * as path from 'path'; +import { Command } from 'commander'; +import { NodeCompilerCallbacks } from '../util/NodeCompilerCallbacks.js'; +import { InfrastructureMessages } from '../messages/infrastructureMessages.js'; +import { BaseOptions } from '../util/baseOptions.js'; +import { exitProcess } from '../util/sysexits.js'; +import { Converter, ConverterOptions } from '@keymanapp/kmc-convert'; +import { CompilerCallbacks } from '@keymanapp/developer-utils'; + +export function declareConvert(program: Command) { + let command = program.command('convert '); + BaseOptions.addLogLevel(command); + BaseOptions.addLogFormat(command); + command + .description('Convert keyboard source files between formats') + .option('-p, --out-path ', 'Path for output files') + .requiredOption('-t, --out-type ', 'File extension for output files, e.g. .kmn, required') + .action(async (filenames: string[], _options: any, commander: any): Promise => { + const options = commander.optsWithGlobals(); + const callbacks = new NodeCompilerCallbacks({logLevel: options.logLevel}); + + for(const filename of filenames) { + const outputFilename = path.join( + options.outPath ?? path.dirname(filename), + path.basename(filename, path.extname(filename)) + options.outType + ); + + if(!await convert(callbacks, options, filename, outputFilename)) { + return await exitProcess(1); + } + } + }); +} + +async function convert( + callbacks: CompilerCallbacks, + options: ConverterOptions, + inputFilename: string, + outputFilename: string, +): Promise { + try { + const converter = new Converter(); + if(!await converter.init(callbacks, options)) { + return false; + } + + const result = await converter.run(inputFilename, outputFilename); + if(!result) { + return false; + } + + if(!await converter.write(result.artifacts)) { + return false; + } + } catch(e) { + callbacks.reportMessage(InfrastructureMessages.Fatal_UnexpectedException({e})); + return false; + } + + return true; +} + +/** + * these are exported only for unit tests, do not use + */ +export const convertUnitTestEndpoints = { + convert +}; \ No newline at end of file diff --git a/developer/src/kmc/src/kmc.ts b/developer/src/kmc/src/kmc.ts index 726807dbae..504d456140 100644 --- a/developer/src/kmc/src/kmc.ts +++ b/developer/src/kmc/src/kmc.ts @@ -12,6 +12,7 @@ import { TestKeymanSentry } from './util/TestKeymanSentry.js'; import { exitProcess } from './util/sysexits.js'; import { declareMessage } from './commands/messageCommand.js'; import { kmcSentryOptions } from './util/kmcSentryOptions.js'; +import { declareConvert } from './commands/convert.js'; await TestKeymanSentry.runTestIfCLRequested(kmcSentryOptions); if(KeymanSentry.isEnabled()) { @@ -49,6 +50,7 @@ async function run() { declareBuild(program); declareAnalyze(program); + declareConvert(program); declareMessage(program); /* Future commands: diff --git a/developer/src/kmc/src/messages/messageNamespaces.ts b/developer/src/kmc/src/messages/messageNamespaces.ts index fc0e7e4d27..771043b3ee 100644 --- a/developer/src/kmc/src/messages/messageNamespaces.ts +++ b/developer/src/kmc/src/messages/messageNamespaces.ts @@ -7,6 +7,7 @@ import { ModelCompilerMessages } from '@keymanapp/kmc-model'; import { ModelInfoCompilerMessages } from '@keymanapp/kmc-model-info'; import { PackageCompilerMessages } from '@keymanapp/kmc-package'; import { InfrastructureMessages } from './infrastructureMessages.js'; +import { ConverterMessages } from '@keymanapp/kmc-convert'; // Maps every compiler error namespace to the corresponding implementation const messageNamespaces: Record = { @@ -20,6 +21,7 @@ const messageNamespaces: Record = { [CompilerErrorNamespace.KmwCompiler]: KmwCompilerMessages, [CompilerErrorNamespace.ModelInfoCompiler]: ModelInfoCompilerMessages, [CompilerErrorNamespace.KeyboardInfoCompiler]: KeyboardInfoCompilerMessages, + [CompilerErrorNamespace.Converter]: ConverterMessages, }; // This works around pain points in enumerating enum members in Typescript @@ -43,4 +45,5 @@ export const messageSources: Record=4" } }, + "developer/src/kmc-convert": { + "name": "@keymanapp/kmc-convert", + "license": "MIT", + "dependencies": { + "@keymanapp/developer-utils": "*", + "@keymanapp/kmc-kmn": "*" + }, + "devDependencies": { + "@keymanapp/developer-test-helpers": "*", + "@keymanapp/resources-gosh": "*", + "@types/mocha": "^5.2.7", + "@types/node": "^20.4.1", + "@types/semver": "^7.3.12", + "c8": "^7.12.0", + "chalk": "^2.4.2", + "mocha": "^8.4.0", + "typescript": "^5.4.5" + } + }, + "developer/src/kmc-convert/node_modules/@types/mocha": { + "version": "5.2.7", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.7.tgz", + "integrity": "sha512-NYrtPht0wGzhwe9+/idPaBB+TqkY9AhTvOLMkThm0IoEfLaiVQZwBwyJ5puCkO3AUCWrmcoePjp2mbFocKy4SQ==", + "dev": true, + "license": "MIT" + }, + "developer/src/kmc-convert/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "developer/src/kmc-convert/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "developer/src/kmc-convert/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "developer/src/kmc-convert/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true, + "license": "MIT" + }, + "developer/src/kmc-convert/node_modules/js-yaml": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.0.0.tgz", + "integrity": "sha512-pqon0s+4ScYUvX30wxQi3PogGFAlUyH0awepWvwkj4jD4v+ova3RiYw8bmA6x2rDrEaj8i/oWKoRxpVNW+Re8Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "developer/src/kmc-convert/node_modules/minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "developer/src/kmc-convert/node_modules/mocha": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-8.4.0.tgz", + "integrity": "sha512-hJaO0mwDXmZS4ghXsvPVriOhsxQ7ofcpQdm8dE+jISUOKopitvnXFQmpRR7jd2K6VBG6E26gU3IAbXXGIbu4sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ungap/promise-all-settled": "1.1.2", + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.1", + "debug": "4.3.1", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.1.6", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "4.0.0", + "log-symbols": "4.0.0", + "minimatch": "3.0.4", + "ms": "2.1.3", + "nanoid": "3.1.20", + "serialize-javascript": "5.0.1", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "which": "2.0.2", + "wide-align": "1.1.3", + "workerpool": "6.1.0", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha" + }, + "engines": { + "node": ">= 10.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mochajs" + } + }, + "developer/src/kmc-convert/node_modules/mocha/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "developer/src/kmc-convert/node_modules/mocha/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "developer/src/kmc-convert/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "developer/src/kmc-convert/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "developer/src/kmc-convert/node_modules/supports-color/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "developer/src/kmc-keyboard": { "name": "@keymanapp/kmc-keyboard", "extraneous": true, @@ -2863,6 +3066,10 @@ "resolved": "developer/src/kmc-analyze", "link": true }, + "node_modules/@keymanapp/kmc-convert": { + "resolved": "developer/src/kmc-convert", + "link": true + }, "node_modules/@keymanapp/kmc-keyboard-info": { "resolved": "developer/src/kmc-keyboard-info", "link": true @@ -14823,7 +15030,6 @@ "name": "@keymanapp/recorder-core", "license": "MIT", "dependencies": { - "@keymanapp/keyboard-processor": "*", "@keymanapp/keyman-version": "*", "@keymanapp/models-types": "*", "@keymanapp/web-utils": "*" diff --git a/package.json b/package.json index 638f2b2fad..18aaf60c5c 100644 --- a/package.json +++ b/package.json @@ -38,6 +38,7 @@ "developer/src/common/web/test-helpers", "developer/src/common/web/utils", "developer/src/kmc-analyze", + "developer/src/kmc-convert", "developer/src/kmc-keyboard-info", "developer/src/kmc-kmn", "developer/src/kmc-ldml", diff --git a/tsconfig.json b/tsconfig.json index 8e6596a231..b21218fcbe 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -26,6 +26,8 @@ { "path": "./developer/src/kmc/test/tsconfig.json" }, { "path": "./developer/src/kmc-analyze/tsconfig.json" }, // { "path": "./developer/src/kmc-analyze/test/tsconfig.json" }, + { "path": "./developer/src/kmc-convert/tsconfig.json" }, + { "path": "./developer/src/kmc-convert/test/tsconfig.json" }, { "path": "./developer/src/kmc-kmn/test/tsconfig.json" }, { "path": "./developer/src/kmc-kmn/tsconfig.json" }, { "path": "./developer/src/kmc-keyboard-info/test/tsconfig.json" }, From 0c18ca0ef5b0e81d24b5192f8b2833d438e56d49 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Thu, 15 Aug 2024 17:12:44 +0200 Subject: [PATCH 3/9] chore(developer): cleanup dependencies in kmc-convert --- developer/src/kmc-convert/build.sh | 2 -- developer/src/kmc-convert/package.json | 3 +-- developer/src/kmc-convert/test/test-converter-messages.ts | 2 +- developer/src/kmc-convert/test/tsconfig.json | 2 +- developer/src/kmc-convert/tsconfig.json | 3 +-- package-lock.json | 3 +-- 6 files changed, 5 insertions(+), 10 deletions(-) diff --git a/developer/src/kmc-convert/build.sh b/developer/src/kmc-convert/build.sh index 962c9ad035..0ebfa2adca 100755 --- a/developer/src/kmc-convert/build.sh +++ b/developer/src/kmc-convert/build.sh @@ -9,8 +9,6 @@ THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")" . "$KEYMAN_ROOT/resources/shellHelperFunctions.sh" builder_describe "Keyman kmc-convert keyboard conversion tools module" \ - "@/common/web/types" \ - "@/developer/src/kmc-kmn" \ "@/developer/src/common/web/utils" \ "@/developer/src/common/web/test-helpers" \ "configure" \ diff --git a/developer/src/kmc-convert/package.json b/developer/src/kmc-convert/package.json index 78a0d457fd..1a46fb63b1 100644 --- a/developer/src/kmc-convert/package.json +++ b/developer/src/kmc-convert/package.json @@ -29,8 +29,7 @@ "url": "https://github.com/keymanapp/keyman/issues" }, "dependencies": { - "@keymanapp/developer-utils": "*", - "@keymanapp/kmc-kmn": "*" + "@keymanapp/developer-utils": "*" }, "devDependencies": { "@keymanapp/developer-test-helpers": "*", diff --git a/developer/src/kmc-convert/test/test-converter-messages.ts b/developer/src/kmc-convert/test/test-converter-messages.ts index 3eb2a16618..3519ddbb10 100644 --- a/developer/src/kmc-convert/test/test-converter-messages.ts +++ b/developer/src/kmc-convert/test/test-converter-messages.ts @@ -2,7 +2,7 @@ * Keyman is copyright (C) SIL International. MIT License. */ import 'mocha'; -import { ConverterMessages } from './converter-messages.js'; +import { ConverterMessages } from '../src/converter-messages.js'; import { verifyCompilerMessagesObject } from '@keymanapp/developer-test-helpers'; import { CompilerErrorNamespace } from '@keymanapp/developer-utils'; diff --git a/developer/src/kmc-convert/test/tsconfig.json b/developer/src/kmc-convert/test/tsconfig.json index 0b380f93a7..ae9de6c9a5 100644 --- a/developer/src/kmc-convert/test/tsconfig.json +++ b/developer/src/kmc-convert/test/tsconfig.json @@ -12,8 +12,8 @@ "./helpers/index.ts", ], "references": [ - { "path": "../../../../common/web/types/" }, { "path": "../../common/web/test-helpers/" }, + { "path": "../../common/web/utils/" }, { "path": "../" } ] } \ No newline at end of file diff --git a/developer/src/kmc-convert/tsconfig.json b/developer/src/kmc-convert/tsconfig.json index 825efda721..32235e2468 100644 --- a/developer/src/kmc-convert/tsconfig.json +++ b/developer/src/kmc-convert/tsconfig.json @@ -10,7 +10,6 @@ "src/**/*.ts" ], "references": [ - { "path": "../../../common/web/types/" }, - { "path": "../kmc-kmn/" }, + { "path": "../common/web/utils/" }, ] } diff --git a/package-lock.json b/package-lock.json index 9043768415..72ad5c04f4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -796,8 +796,7 @@ "name": "@keymanapp/kmc-convert", "license": "MIT", "dependencies": { - "@keymanapp/developer-utils": "*", - "@keymanapp/kmc-kmn": "*" + "@keymanapp/developer-utils": "*" }, "devDependencies": { "@keymanapp/developer-test-helpers": "*", From a766e4460e80a4ec9abffe4581f6e6d2884fc3a0 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Thu, 15 Aug 2024 17:20:33 +0200 Subject: [PATCH 4/9] chore(developer): reduce kmc coverage threshold to 45% --- developer/src/kmc/build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/developer/src/kmc/build.sh b/developer/src/kmc/build.sh index f10a4500f9..5cef97df49 100755 --- a/developer/src/kmc/build.sh +++ b/developer/src/kmc/build.sh @@ -62,7 +62,7 @@ function do_api() { function do_test() { eslint . tsc --build test/ - readonly C8_THRESHOLD=50 + readonly C8_THRESHOLD=45 c8 --reporter=lcov --reporter=text --lines $C8_THRESHOLD --statements $C8_THRESHOLD --branches $C8_THRESHOLD --functions $C8_THRESHOLD mocha 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." From d96843928cc749b34327ed72faca3a484092bac6 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Fri, 16 Aug 2024 04:15:27 +0200 Subject: [PATCH 5/9] chore(developer): add api-extractor config for kmc-convert --- developer/src/kmc-convert/config/api-extractor.json | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 developer/src/kmc-convert/config/api-extractor.json diff --git a/developer/src/kmc-convert/config/api-extractor.json b/developer/src/kmc-convert/config/api-extractor.json new file mode 100644 index 0000000000..53492e6d13 --- /dev/null +++ b/developer/src/kmc-convert/config/api-extractor.json @@ -0,0 +1,12 @@ +/** + * Config file for API Extractor. For more info, please visit: https://api-extractor.com + */ +{ + "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", + "extends": "../../../config/api-extractor.base.json", + "mainEntryPointFilePath": "/build/src/index.d.ts", + "docModel": { + "enabled": true, + "projectFolderUrl": "http://github.com/keymanapp/keyman/tree/master/developer/src/kmc-convert" + } +} From 45862d2b880e187796c04a35f5019cb46f3eedfd Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Fri, 16 Aug 2024 08:34:37 +0200 Subject: [PATCH 6/9] chore(developer): fixup api-extractor config --- developer/src/kmc-convert/config/api-extractor.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/developer/src/kmc-convert/config/api-extractor.json b/developer/src/kmc-convert/config/api-extractor.json index 53492e6d13..318278f5d5 100644 --- a/developer/src/kmc-convert/config/api-extractor.json +++ b/developer/src/kmc-convert/config/api-extractor.json @@ -4,7 +4,7 @@ { "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", "extends": "../../../config/api-extractor.base.json", - "mainEntryPointFilePath": "/build/src/index.d.ts", + "mainEntryPointFilePath": "/build/src/main.d.ts", "docModel": { "enabled": true, "projectFolderUrl": "http://github.com/keymanapp/keyman/tree/master/developer/src/kmc-convert" From ecbe2f01fe662a8cb1b43d7cbd2e395bd46e6059 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Mon, 11 Nov 2024 06:18:02 +0700 Subject: [PATCH 7/9] chore: npm install --- package-lock.json | 119 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 118 insertions(+), 1 deletion(-) diff --git a/package-lock.json b/package-lock.json index 7f17592cf5..dacb737a4c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -688,7 +688,7 @@ "@types/semver": "^7.3.12", "c8": "^7.12.0", "chalk": "^2.4.2", - "mocha": "^10.0.0", + "mocha": "^8.4.0", "typescript": "^5.4.5" } }, @@ -754,6 +754,123 @@ "node": ">=4" } }, + "developer/src/kmc-convert/node_modules/js-yaml": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.0.0.tgz", + "integrity": "sha512-pqon0s+4ScYUvX30wxQi3PogGFAlUyH0awepWvwkj4jD4v+ova3RiYw8bmA6x2rDrEaj8i/oWKoRxpVNW+Re8Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "developer/src/kmc-convert/node_modules/minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "developer/src/kmc-convert/node_modules/mocha": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-8.4.0.tgz", + "integrity": "sha512-hJaO0mwDXmZS4ghXsvPVriOhsxQ7ofcpQdm8dE+jISUOKopitvnXFQmpRR7jd2K6VBG6E26gU3IAbXXGIbu4sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ungap/promise-all-settled": "1.1.2", + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.1", + "debug": "4.3.1", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.1.6", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "4.0.0", + "log-symbols": "4.0.0", + "minimatch": "3.0.4", + "ms": "2.1.3", + "nanoid": "3.1.20", + "serialize-javascript": "5.0.1", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "which": "2.0.2", + "wide-align": "1.1.3", + "workerpool": "6.1.0", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha" + }, + "engines": { + "node": ">= 10.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mochajs" + } + }, + "developer/src/kmc-convert/node_modules/mocha/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "developer/src/kmc-convert/node_modules/mocha/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "developer/src/kmc-convert/node_modules/mocha/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "developer/src/kmc-convert/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, "developer/src/kmc-convert/node_modules/supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", From 7b33aed94d1b46a5ab513fc2503c1a284b212319 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Sat, 15 Mar 2025 15:09:18 +0700 Subject: [PATCH 8/9] chore(developer): reduce kmc coverage to 45% This was due to platform-specific checks in NodeCompilerCallbacks, around filename case and drive letters in paths (search terms: HINT_FilenameHasDifferingCase, verifyFilenameConsistency): - Linux: 59.01% - macOS: 60.46% - Windows: 63.08% Mitigation: reduce threshold to 45%. More tests will be needed for kmc-convert before epic merge. --- developer/src/kmc/build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/developer/src/kmc/build.sh b/developer/src/kmc/build.sh index f61b8e7585..274787cdad 100755 --- a/developer/src/kmc/build.sh +++ b/developer/src/kmc/build.sh @@ -55,7 +55,7 @@ function do_build() { #------------------------------------------------------------------------------------------------------------------- function do_test() { - builder_do_typescript_tests 50 + builder_do_typescript_tests 45 ./test/command-line-tests.sh test } From c300c9bbd9bd4bb5368906e8f8efdb90513eb953 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Fri, 16 May 2025 08:51:27 +0200 Subject: [PATCH 9/9] chore(developer): use const instead of let --- developer/src/kmc/src/commands/convert.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/developer/src/kmc/src/commands/convert.ts b/developer/src/kmc/src/commands/convert.ts index c03b0c5427..2dbbf71c31 100644 --- a/developer/src/kmc/src/commands/convert.ts +++ b/developer/src/kmc/src/commands/convert.ts @@ -13,7 +13,7 @@ import { Converter, ConverterOptions } from '@keymanapp/kmc-convert'; import { CompilerCallbacks } from '@keymanapp/developer-utils'; export function declareConvert(program: Command) { - let command = program.command('convert '); + const command = program.command('convert '); BaseOptions.addLogLevel(command); BaseOptions.addLogFormat(command); command