Merge branch 'epic/kmc-convert' into chore/merge-master-into-kmc-convert

This commit is contained in:
Marc Durdin 2025-05-30 08:24:00 +07:00 committed by GitHub
commit b9f8e8eb85
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
31 changed files with 819 additions and 1 deletions

View file

@ -90,6 +90,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-copy - Project copying and renaming tools
Tools to copy and rename Keyman keyboard files and projects

View file

@ -25,6 +25,7 @@ builder_describe \
":kmcmplib Compiler - .kmn compiler" \
":kmc-analyze Compiler - Analysis Tools" \
":kmc-copy Compiler - Project Copying and Renaming Tools" \
":kmc-convert Compiler - Keyboard Conversion Tools" \
":kmc-generate Compiler - Generation Tools" \
":kmc-keyboard-info Compiler - .keyboard_info Module" \
":kmc-kmn Compiler - .kmn to .kmx and .js Keyboard Module" \

View file

@ -290,6 +290,10 @@ export enum CompilerErrorNamespace {
* kmc-copy 0xB0000xBFFF
*/
Copier = 0xB000,
/**
* kmc-convert 0xC0000xCFFF
*/
Converter = 0xC000,
};
type CompilerErrorSeverityOverride = CompilerErrorSeverity | 'disable';

View file

@ -0,0 +1,11 @@
module.exports = {
parserOptions: {
project: ["./tsconfig.json", "./test/tsconfig.json"],
},
ignorePatterns: ["test/fixtures/**/*"],
overrides: [
{
files:"src/**/*.ts",
}
],
};

View file

@ -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)

View file

@ -0,0 +1,49 @@
#!/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" \
"@/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

View file

@ -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": "<projectFolder>/build/src/main.d.ts",
"docModel": {
"enabled": true,
"projectFolderUrl": "http://github.com/keymanapp/keyman/tree/master/developer/src/kmc-convert"
}
}

View file

@ -0,0 +1,67 @@
{
"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": "*"
},
"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"
}
}

View file

@ -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;
};

View file

@ -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;
}
}

View file

@ -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.`);
}

View file

@ -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;
};

View file

@ -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<boolean> {
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<ConverterResult> {
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<boolean> {
for(const key of Object.keys(artifacts)) {
if(artifacts[key]) {
this.callbacks.fs.writeFileSync(artifacts[key].filename, artifacts[key].data);
}
}
return true;
}
}

View file

@ -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<ConverterToKmnArtifacts> {
if(!inputFilename || !outputFilename || !binaryData) {
throw new Error('Invalid parameters');
}
console.error('TODO: implement KeylayoutToKmnConverter');
return null;
}
}

View file

@ -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';

View file

@ -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));
}

View file

@ -0,0 +1,13 @@
/*
* Keyman is copyright (C) SIL International. MIT License.
*/
import 'mocha';
import { ConverterMessages } from '../src/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);
});
});

View file

@ -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);
});
});

View file

@ -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/test-helpers/" },
{ "path": "../../common/web/utils/" },
{ "path": "../" }
]
}

View file

@ -0,0 +1,15 @@
{
"extends": "../../../tsconfig.base.json",
"compilerOptions": {
"outDir": "build/src/",
"rootDir": "src/",
"baseUrl": ".",
},
"include": [
"src/**/*.ts"
],
"references": [
{ "path": "../common/web/utils/" },
]
}

View file

@ -20,6 +20,7 @@ builder_describe "Build Keyman Keyboard Compiler kmc" \
"@/developer/src/common/web/utils" \
"@/developer/src/kmc-analyze" \
"@/developer/src/kmc-copy" \
"@/developer/src/kmc-convert" \
"@/developer/src/kmc-generate" \
"@/developer/src/kmc-keyboard-info" \
"@/developer/src/kmc-kmn" \
@ -54,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
}

View file

@ -39,6 +39,7 @@
"@keymanapp/keyman-version": "*",
"@keymanapp/kmc-analyze": "*",
"@keymanapp/kmc-copy": "*",
"@keymanapp/kmc-convert": "*",
"@keymanapp/kmc-generate": "*",
"@keymanapp/kmc-keyboard-info": "*",
"@keymanapp/kmc-kmn": "*",

View file

@ -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) {
const command = program.command('convert <infile...>');
BaseOptions.addLogLevel(command);
BaseOptions.addLogFormat(command);
command
.description('Convert keyboard source files between formats')
.option('-p, --out-path <path>', 'Path for output files')
.requiredOption('-t, --out-type <type>', 'File extension for output files, e.g. .kmn, required')
.action(async (filenames: string[], _options: any, commander: any): Promise<never|void> => {
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<boolean> {
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
};

View file

@ -15,6 +15,7 @@ import { declareMessage } from './commands/messageCommand.js';
import { kmcSentryOptions } from './util/kmcSentryOptions.js';
import { declareGenerate } from './commands/generate.js';
import { declareCopy } from './commands/copy.js';
import { declareConvert } from './commands/convert.js';
await TestKeymanSentry.runTestIfCLRequested(kmcSentryOptions);
if(KeymanSentry.isEnabled()) {
@ -60,6 +61,7 @@ async function run() {
declareBuild(program);
declareAnalyze(program);
declareConvert(program);
declareMessage(program);
declareGenerate(program);
declareCopy(program);

View file

@ -9,6 +9,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<CompilerErrorNamespace, any> = {
@ -24,6 +25,7 @@ const messageNamespaces: Record<CompilerErrorNamespace, any> = {
[CompilerErrorNamespace.KeyboardInfoCompiler]: KeyboardInfoCompilerMessages,
[CompilerErrorNamespace.Copier]: CopierMessages,
[CompilerErrorNamespace.Generator]: GeneratorMessages,
[CompilerErrorNamespace.Converter]: ConverterMessages,
};
// This works around pain points in enumerating enum members in Typescript
@ -49,4 +51,5 @@ export const messageSources: Record<CompilerErrorNamespace, CompilerMessageSourc
[CompilerErrorNamespace.KmwCompiler]: { module: 'kmc-kmn', class: KmwCompilerMessages },
[CompilerErrorNamespace.ModelInfoCompiler]: { module: 'kmc-model-info', class: ModelInfoCompilerMessages },
[CompilerErrorNamespace.KeyboardInfoCompiler]: { module: 'kmc-keyboard-info', class: KeyboardInfoCompilerMessages },
[CompilerErrorNamespace.Converter]: { module: 'kmc-convert', class: ConverterMessages },
};

View file

@ -14,6 +14,7 @@
{ "path": "../../../common/web/types" },
{ "path": "../kmc-analyze" },
{ "path": "../kmc-copy" },
{ "path": "../kmc-convert" },
{ "path": "../kmc-generate" },
{ "path": "../kmc-keyboard-info" },
{ "path": "../kmc-kmn" },

View file

@ -11,6 +11,7 @@ readonly PACKAGES=(
developer/src/common/web/utils
developer/src/kmc-analyze
developer/src/kmc-copy
developer/src/kmc-convert
developer/src/kmc-generate
developer/src/kmc-keyboard-info
developer/src/kmc-kmn

View file

@ -57,6 +57,7 @@ sourcemap_paths=(
./src/kmc/build
./src/kmc-analyze/build
./src/kmc-copy/build
./src/kmc-convert/build
./src/kmc-generate/build
./src/kmc-keyboard-info/build
./src/kmc-kmn/build

216
package-lock.json generated
View file

@ -15,6 +15,7 @@
"developer/src/common/web/utils",
"developer/src/kmc-analyze",
"developer/src/kmc-copy",
"developer/src/kmc-convert",
"developer/src/kmc-generate",
"developer/src/kmc-keyboard-info",
"developer/src/kmc-kmn",
@ -269,6 +270,7 @@
"@keymanapp/developer-utils": "*",
"@keymanapp/keyman-version": "*",
"@keymanapp/kmc-analyze": "*",
"@keymanapp/kmc-convert": "*",
"@keymanapp/kmc-copy": "*",
"@keymanapp/kmc-generate": "*",
"@keymanapp/kmc-keyboard-info": "*",
@ -381,6 +383,216 @@
"node": ">=4"
}
},
"developer/src/kmc-convert": {
"name": "@keymanapp/kmc-convert",
"license": "MIT",
"dependencies": {
"@keymanapp/developer-utils": "*"
},
"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/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-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",
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"dev": true,
"license": "MIT",
"dependencies": {
"has-flag": "^3.0.0"
},
"engines": {
"node": ">=4"
}
},
"developer/src/kmc-copy": {
"name": "@keymanapp/kmc-copy",
"license": "MIT",
@ -1700,6 +1912,10 @@
"resolved": "developer/src/kmc-analyze",
"link": true
},
"node_modules/@keymanapp/kmc-convert": {
"resolved": "developer/src/kmc-convert",
"link": true
},
"node_modules/@keymanapp/kmc-copy": {
"resolved": "developer/src/kmc-copy",
"link": true

View file

@ -40,6 +40,7 @@
"developer/src/common/web/utils",
"developer/src/kmc-analyze",
"developer/src/kmc-copy",
"developer/src/kmc-convert",
"developer/src/kmc-generate",
"developer/src/kmc-keyboard-info",
"developer/src/kmc-kmn",

View file

@ -20,6 +20,8 @@
{ "path": "./developer/src/kmc-copy/test/tsconfig.json" },
{ "path": "./developer/src/kmc-generate/tsconfig.json" },
{ "path": "./developer/src/kmc-generate/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" },