mirror of
https://github.com/keymanapp/keyman.git
synced 2026-10-07 22:47:29 +00:00
feat(developer): use CompilerEvent for messages in all of kmc
Cleans up majority of remaining kmc-* modules to use CompilerEvent messages instead of console.log and friends, adding InfrastructureMessages class for kmc CLI messages. Consolidates schema loading functions into a single `loadSchema` function in the CompilerCallbacks interface and implementations. Moves responsibility for instantiating NodeCompilerCallbacks out of each individual BuildActivity and into higher level modules. Fixes return value for failing builds.
This commit is contained in:
parent
34ae4a1397
commit
cf4022ac8a
20 changed files with 171 additions and 128 deletions
|
|
@ -18,7 +18,7 @@ export { default as LDMLKeyboardXMLSourceFileReader } from './ldml-keyboard/ldml
|
|||
|
||||
export * as Constants from './consts/virtual-key-constants.js';
|
||||
|
||||
export { CompilerCallbacks, CompilerEvent, CompilerErrorNamespace, CompilerErrorSeverity, CompilerMessageSpec, compilerErrorSeverityName } from './util/compiler-interfaces.js';
|
||||
export { CompilerCallbacks, CompilerSchema, CompilerEvent, CompilerErrorNamespace, CompilerErrorSeverity, CompilerMessageSpec, compilerErrorSeverityName } from './util/compiler-interfaces.js';
|
||||
export { CommonTypesMessages } from './util/common-events.js';
|
||||
|
||||
export * as TouchLayout from './keyman-touch-layout/keyman-touch-layout-file.js';
|
||||
|
|
|
|||
|
|
@ -66,6 +66,13 @@ export enum CompilerErrorNamespace {
|
|||
Infrastructure = 0x5000,
|
||||
};
|
||||
|
||||
export type CompilerSchema =
|
||||
'ldml-keyboard' |
|
||||
'ldml-keyboardtest' |
|
||||
'kvks' |
|
||||
'kpj';
|
||||
// | 'keyman-touch-layout.clean'; TODO this has the wrong name pattern, .spec.json instead of .schema.json
|
||||
|
||||
/**
|
||||
* Abstract interface for callbacks, to abstract out file i/o
|
||||
*/
|
||||
|
|
@ -76,11 +83,9 @@ export interface CompilerCallbacks {
|
|||
* @param filename
|
||||
*/
|
||||
loadFile(baseFilename: string, filename: string | URL): Buffer;
|
||||
loadLdmlKeyboardSchema(): Buffer;
|
||||
loadLdmlKeyboardTestSchema(): Buffer;
|
||||
loadSchema(schema: CompilerSchema): Buffer;
|
||||
reportMessage(event: CompilerEvent): void;
|
||||
loadKvksJsonSchema(): Buffer;
|
||||
loadKpjJsonSchema(): Buffer;
|
||||
debug(msg: string): void;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import path from "path";
|
||||
import fs from "fs";
|
||||
import { fileURLToPath } from "url";
|
||||
import { CompilerSchema } from "../../src/util/compiler-interfaces.js";
|
||||
|
||||
/**
|
||||
* Builds a path to the fixture with the given path components.
|
||||
|
|
@ -13,11 +14,8 @@ export function makePathToFixture(...components: string[]): string {
|
|||
return fileURLToPath(new URL(path.join('..', '..', '..', 'test', 'fixtures', ...components), import.meta.url));
|
||||
}
|
||||
|
||||
export function loadKvksJsonSchema(): Buffer {
|
||||
return fs.readFileSync(new URL(path.join('..', '..', 'src', 'kvks.schema.json'), import.meta.url));
|
||||
}
|
||||
|
||||
export function loadKeymanTouchLayoutCleanJsonSchema(): Buffer {
|
||||
// TODO: this has the Wrong Name Pattern!
|
||||
return fs.readFileSync(new URL(path.join('..', '..', 'src', 'keyman-touch-layout.clean.spec.json'), import.meta.url));
|
||||
}
|
||||
|
||||
|
|
@ -26,14 +24,6 @@ export function loadFile(baseFilename: string, filename: string | URL): Buffer {
|
|||
return fs.readFileSync(filename);
|
||||
}
|
||||
|
||||
export function loadLdmlKeyboardSchema(): Buffer {
|
||||
return fs.readFileSync(new URL(path.join('..', '..', 'src', 'ldml-keyboard.schema.json'), import.meta.url));
|
||||
}
|
||||
|
||||
export function loadLdmlKeyboardTestDataSchema(): Buffer {
|
||||
return fs.readFileSync(new URL(path.join('..', '..', 'src', 'ldml-keyboardtest.schema.json'), import.meta.url));
|
||||
}
|
||||
|
||||
export function loadKpjJsonSchema(): Buffer {
|
||||
return fs.readFileSync(new URL(path.join('..', '..', 'src', 'kpj.schema.json'), import.meta.url));
|
||||
export function loadSchema(schema: CompilerSchema): Buffer {
|
||||
return fs.readFileSync(new URL(path.join('..', '..', 'src', schema + '.schema.json'), import.meta.url));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import 'mocha';
|
||||
import {assert} from 'chai';
|
||||
import {loadLdmlKeyboardSchema, loadFile, makePathToFixture, loadLdmlKeyboardTestDataSchema} from '../helpers/index.js';
|
||||
import { loadFile, makePathToFixture, loadSchema } from '../helpers/index.js';
|
||||
import LDMLKeyboardXMLSourceFileReader from '../../src/ldml-keyboard/ldml-keyboard-xml-reader.js';
|
||||
import { CompilerCallbacks, CompilerEvent } from '../../src/util/compiler-interfaces.js';
|
||||
import { CompilerCallbacks, CompilerEvent, CompilerSchema } from '../../src/util/compiler-interfaces.js';
|
||||
import { LDMLKeyboardXMLSourceFile } from '../../src/ldml-keyboard/ldml-keyboard-xml.js';
|
||||
import { LDMLKeyboardTestDataXMLSourceFile } from '../ldml-keyboard/ldml-keyboard-testdata-xml.js';
|
||||
|
||||
|
|
@ -13,21 +13,24 @@ import { LDMLKeyboardTestDataXMLSourceFile } from '../ldml-keyboard/ldml-keyboar
|
|||
* A CompilerCallbacks implementation for testing
|
||||
*/
|
||||
class TestCompilerCallbacks implements CompilerCallbacks {
|
||||
loadKpjJsonSchema(): Buffer {
|
||||
throw new Error('loadKpjJsonSchema not implemented.'); // not needed for this test
|
||||
}
|
||||
loadLdmlKeyboardTestSchema(): Buffer {
|
||||
return loadLdmlKeyboardTestDataSchema();
|
||||
}
|
||||
loadLdmlKeyboardSchema(): Buffer {
|
||||
return loadLdmlKeyboardSchema();
|
||||
}
|
||||
loadKvksJsonSchema(): Buffer {
|
||||
throw new Error('loadKvksJsonSchema not implemented.');
|
||||
loadSchema(schema: CompilerSchema): Buffer {
|
||||
switch(schema) {
|
||||
case 'kpj':
|
||||
throw new Error('loadKpjJsonSchema not implemented.'); // not needed for this test
|
||||
case 'kvks':
|
||||
throw new Error('loadKvksJsonSchema not implemented.');
|
||||
case 'ldml-keyboard':
|
||||
return loadSchema(schema);
|
||||
case 'ldml-keyboardtest':
|
||||
return loadSchema(schema);
|
||||
}
|
||||
}
|
||||
clear() {
|
||||
this.messages = [];
|
||||
}
|
||||
debug(msg: string): void {
|
||||
console.debug(msg);
|
||||
}
|
||||
messages: CompilerEvent[] = [];
|
||||
loadFile(baseFilename: string, filename: string | URL): Buffer {
|
||||
try {
|
||||
|
|
@ -128,9 +131,9 @@ export function testReaderCases(cases : CompilationCase[]) {
|
|||
}
|
||||
// special case for an expected exception
|
||||
if (testcase.throws) {
|
||||
assert.throws(() => reader.validate(source, loadLdmlKeyboardSchema()), testcase.throws);
|
||||
assert.throws(() => reader.validate(source, loadSchema('ldml-keyboard')), testcase.throws);
|
||||
} else {
|
||||
assert.doesNotThrow(() => reader.validate(source, loadLdmlKeyboardSchema()), `validating ${testcase.subpath}`);
|
||||
assert.doesNotThrow(() => reader.validate(source, loadSchema('ldml-keyboard')), `validating ${testcase.subpath}`);
|
||||
// if we expected errors or warnings, show them
|
||||
if (testcase.errors) {
|
||||
assert.includeDeepMembers(callbacks.messages, testcase.errors, 'expected errors to be included');
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import * as fs from 'fs';
|
||||
import { CompilerEvent, CompilerCallbacks } from '@keymanapp/common-types';
|
||||
import { CompilerEvent, CompilerCallbacks, CompilerSchema } from '@keymanapp/common-types';
|
||||
|
||||
// TODO: schemas are only used by kmc-keyboard for now, so this works at this
|
||||
// time, but it's a little fragile if we need them elsewhere in the future
|
||||
|
|
@ -9,10 +9,20 @@ const SCHEMA_BASE = '../../../../kmc-keyboard/build/src/';
|
|||
* A CompilerCallbacks implementation for testing
|
||||
*/
|
||||
export class TestCompilerCallbacks implements CompilerCallbacks {
|
||||
/* TestCompilerCallbacks */
|
||||
|
||||
messages: CompilerEvent[] = [];
|
||||
|
||||
clear() {
|
||||
this.messages = [];
|
||||
}
|
||||
messages: CompilerEvent[] = [];
|
||||
|
||||
hasMessage(code: number): boolean {
|
||||
return this.messages.find((item) => item.code == code) === undefined ? false : true;
|
||||
}
|
||||
|
||||
/* CompilerCallbacks */
|
||||
|
||||
loadFile(baseFilename: string, filename: string | URL): Buffer {
|
||||
// TODO: translate filename based on the baseFilename
|
||||
try {
|
||||
|
|
@ -25,23 +35,16 @@ export class TestCompilerCallbacks implements CompilerCallbacks {
|
|||
}
|
||||
}
|
||||
}
|
||||
hasMessage(code: number): boolean {
|
||||
return this.messages.find((item) => item.code == code) === undefined ? false : true;
|
||||
}
|
||||
reportMessage(event: CompilerEvent): void {
|
||||
// console.log(event.message);
|
||||
this.messages.push(event);
|
||||
}
|
||||
loadLdmlKeyboardSchema(): Buffer {
|
||||
return fs.readFileSync(new URL(SCHEMA_BASE + 'ldml-keyboard.schema.json', import.meta.url));
|
||||
|
||||
loadSchema(schema: CompilerSchema): Buffer {
|
||||
return fs.readFileSync(new URL(SCHEMA_BASE + schema + '.schema.json', import.meta.url));
|
||||
}
|
||||
loadKvksJsonSchema(): Buffer {
|
||||
return fs.readFileSync(new URL(SCHEMA_BASE + 'kvks.schema.json', import.meta.url));
|
||||
}
|
||||
loadKpjJsonSchema(): Buffer {
|
||||
return fs.readFileSync(new URL(SCHEMA_BASE + 'kpj.schema.json', import.meta.url));
|
||||
}
|
||||
loadLdmlKeyboardTestSchema(): Buffer {
|
||||
return fs.readFileSync(new URL(SCHEMA_BASE + 'ldml-keyboardtest.schema.json', import.meta.url));
|
||||
|
||||
debug(msg: string) {
|
||||
console.debug(msg);
|
||||
}
|
||||
};
|
||||
|
|
@ -66,7 +66,7 @@ export default class Compiler {
|
|||
return null;
|
||||
}
|
||||
try {
|
||||
if (!reader.validate(source, this.callbacks.loadLdmlKeyboardSchema())) {
|
||||
if (!reader.validate(source, this.callbacks.loadSchema('ldml-keyboard'))) {
|
||||
return null;
|
||||
}
|
||||
} catch(e) {
|
||||
|
|
@ -98,7 +98,7 @@ export default class Compiler {
|
|||
// TODO-LDML: The unboxed data doesn't match the schema anymore. Skipping validation, for now.
|
||||
|
||||
// try {
|
||||
// if (!reader.validate(source, this.callbacks.loadLdmlKeyboardTestSchema())) {
|
||||
// if (!reader.validate(source, this.callbacks.loadSchema('ldml-keyboard-test'))) {
|
||||
// return null;
|
||||
// }
|
||||
// } catch(e) {
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ export function loadSectionFixture(compilerClass: typeof SectionCompiler, filena
|
|||
const source = reader.load(data);
|
||||
assert.isNotNull(source);
|
||||
|
||||
if (!reader.validate(source, callbacks.loadLdmlKeyboardSchema())) {
|
||||
if (!reader.validate(source, callbacks.loadSchema('ldml-keyboard'))) {
|
||||
return null; // mimic kmc behavior - bail if validate fails
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@ import { Command } from 'commander';
|
|||
import { BuildActivityOptions } from './build/BuildActivity.js';
|
||||
import { buildActivities } from './build/buildActivities.js';
|
||||
import { BuildProject } from './build/BuildProject.js';
|
||||
import { NodeCompilerCallbacks } from 'src/messages/NodeCompilerCallbacks.js';
|
||||
import { InfrastructureMessages } from 'src/messages/messages.js';
|
||||
|
||||
export function declareBuild(program: Command) {
|
||||
program
|
||||
|
|
@ -13,43 +15,59 @@ export function declareBuild(program: Command) {
|
|||
.option('--no-compiler-version', 'Exclude compiler version metadata from output')
|
||||
.option('-w, --compiler-warnings-as-errors', 'Causes warnings to fail the build')
|
||||
.option('--no-warn-deprecated-code', 'Turn off warnings for deprecated code styles')
|
||||
.action((infiles: string[], options: any) => {
|
||||
let p = [];
|
||||
if(!infiles.length) {
|
||||
console.debug('Assuming infile == .');
|
||||
p.push(build('.', options));
|
||||
.action(async (filenames: string[], options: any) => {
|
||||
if(!filenames.length) {
|
||||
// If there are no filenames provided, then we are building the current
|
||||
// folder ('.') as a project-style build
|
||||
filenames.push('.');
|
||||
}
|
||||
for(let infile of infiles) {
|
||||
p.push(build(infile, options));
|
||||
|
||||
for(let filename of filenames) {
|
||||
if(!await build(filename, options)) {
|
||||
// Once a file fails to build, we bail on subsequent builds
|
||||
// TODO: is this the most appropriate semantics?
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
return Promise.all(p).then();
|
||||
});
|
||||
}
|
||||
|
||||
async function build(infile: string, options: BuildActivityOptions): Promise<boolean> {
|
||||
console.log(`Building ${infile}`);
|
||||
async function build(filename: string, options: BuildActivityOptions): Promise<boolean> {
|
||||
let callbacks = new NodeCompilerCallbacks();
|
||||
|
||||
if(!fs.existsSync(infile)) {
|
||||
// TODO: consolidate errors
|
||||
console.error(`File ${infile} does not exist`);
|
||||
process.exit(2);
|
||||
}
|
||||
try {
|
||||
callbacks.reportMessage(InfrastructureMessages.Info_BuildingFile({filename}));
|
||||
|
||||
// If infile is a directory, then we treat that as a project and build it
|
||||
if(fs.statSync(infile).isDirectory()) {
|
||||
return (new BuildProject()).build(infile, options);
|
||||
}
|
||||
|
||||
// Otherwise, if it's one of our known file extensions, we build it
|
||||
let extensions: string[] = [];
|
||||
for(let build of buildActivities) {
|
||||
if(infile.toLowerCase().endsWith(build.sourceExtension)) {
|
||||
return build.build(infile, options);
|
||||
if(!fs.existsSync(filename)) {
|
||||
callbacks.reportMessage(InfrastructureMessages.Error_FileDoesNotExist({filename}));
|
||||
return false;
|
||||
}
|
||||
extensions.push(build.sourceExtension);
|
||||
}
|
||||
|
||||
// TODO: consolidate errors
|
||||
console.error(`Unrecognised input file ${infile}, expecting ${extensions.join(', ')}, or project folder`);
|
||||
process.exit(2);
|
||||
let builder = null;
|
||||
|
||||
// If infile is a directory, then we treat that as a project and build it
|
||||
if(fs.statSync(filename).isDirectory()) {
|
||||
builder = new BuildProject();
|
||||
} else {
|
||||
// Otherwise, if it's one of our known file extensions, we build it
|
||||
let extensions: string[] = [];
|
||||
builder = buildActivities.find(build => { extensions.push(build.sourceExtension); return filename.toLowerCase().endsWith(build.sourceExtension) });
|
||||
if(!builder) {
|
||||
callbacks.reportMessage(InfrastructureMessages.Error_FileTypeNotRecognized({filename, extensions: extensions.join(', ')}));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
let result = await builder.build(filename, callbacks, options);
|
||||
if(result) {
|
||||
callbacks.reportMessage(InfrastructureMessages.Info_FileBuiltSuccessfully({filename}));
|
||||
} else {
|
||||
callbacks.reportMessage(InfrastructureMessages.Info_FileNotBuiltSuccessfully({filename}));
|
||||
}
|
||||
|
||||
return result;
|
||||
} catch(e) {
|
||||
callbacks.reportMessage(InfrastructureMessages.Fatal_UnexpectedException({e}));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import { CompilerCallbacks } from "@keymanapp/common-types";
|
||||
import { escapeRegExp } from "../../util/escapeRegExp.js";
|
||||
|
||||
export interface BuildActivityOptions {
|
||||
|
|
@ -13,7 +14,7 @@ export abstract class BuildActivity {
|
|||
public abstract get sourceExtension(): string;
|
||||
public abstract get compiledExtension(): string;
|
||||
public abstract get description(): string;
|
||||
public abstract build(infile: string, options: BuildActivityOptions): Promise<boolean>;
|
||||
public abstract build(infile: string, callbacks: CompilerCallbacks, options: BuildActivityOptions): Promise<boolean>;
|
||||
protected getOutputFilename(infile: string, options: BuildActivityOptions): string {
|
||||
return options.outFile ?
|
||||
options.outFile :
|
||||
|
|
|
|||
|
|
@ -2,21 +2,19 @@ import * as path from 'path';
|
|||
import { BuildActivity, BuildActivityOptions } from './BuildActivity.js';
|
||||
import { Compiler } from '@keymanapp/kmc-kmn';
|
||||
import { platform } from 'os';
|
||||
import { NodeCompilerCallbacks } from '../../util/NodeCompilerCallbacks.js';
|
||||
import { CompilerCallbacks } from '@keymanapp/common-types';
|
||||
|
||||
export class BuildKmnKeyboard extends BuildActivity {
|
||||
public get name(): string { return 'Keyman keyboard'; }
|
||||
public get sourceExtension(): string { return '.kmn'; }
|
||||
public get compiledExtension(): string { return '.kmx'; }
|
||||
public get description(): string { return 'Build a Keyman keyboard'; }
|
||||
public async build(infile: string, options: BuildActivityOptions): Promise<boolean> {
|
||||
public async build(infile: string, callbacks: CompilerCallbacks, options: BuildActivityOptions): Promise<boolean> {
|
||||
let compiler = new Compiler();
|
||||
if(!await compiler.init()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const callbacks = new NodeCompilerCallbacks();
|
||||
|
||||
// We need to resolve paths to absolute paths before calling kmc-kmn
|
||||
let outfile = this.getOutputFilename(infile, options);
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ import * as path from 'path';
|
|||
import * as fs from 'fs';
|
||||
import * as kmc from '@keymanapp/kmc-keyboard';
|
||||
import { KvkFileWriter, CompilerCallbacks } from '@keymanapp/common-types';
|
||||
import { NodeCompilerCallbacks } from '../../util/NodeCompilerCallbacks.js';
|
||||
import { BuildActivity, BuildActivityOptions } from './BuildActivity.js';
|
||||
|
||||
export class BuildLdmlKeyboard extends BuildActivity {
|
||||
|
|
@ -10,10 +9,10 @@ export class BuildLdmlKeyboard extends BuildActivity {
|
|||
public get sourceExtension(): string { return '.xml'; }
|
||||
public get compiledExtension(): string { return '.kmx'; }
|
||||
public get description(): string { return 'Build a LDML keyboard'; }
|
||||
public async build(infile: string, options: BuildActivityOptions): Promise<boolean> {
|
||||
public async build(infile: string, callbacks: CompilerCallbacks, options: BuildActivityOptions): Promise<boolean> {
|
||||
// TODO-LDML: consider hardware vs touch -- touch-only layout will not have a .kvk
|
||||
// Compile:
|
||||
let [kmx,kvk,kmw] = buildLdmlKeyboardToMemory(infile, options);
|
||||
let [kmx,kvk,kmw] = buildLdmlKeyboardToMemory(infile, callbacks, options);
|
||||
// Output:
|
||||
|
||||
const fileBaseName = options.outFile ?? infile;
|
||||
|
|
@ -43,7 +42,7 @@ export class BuildLdmlKeyboard extends BuildActivity {
|
|||
}
|
||||
}
|
||||
|
||||
function buildLdmlKeyboardToMemory(inputFilename: string, options: BuildActivityOptions): [Uint8Array, Uint8Array, Uint8Array] {
|
||||
function buildLdmlKeyboardToMemory(inputFilename: string, callbacks: CompilerCallbacks, options: BuildActivityOptions): [Uint8Array, Uint8Array, Uint8Array] {
|
||||
let compilerOptions: kmc.CompilerOptions = {
|
||||
debug: options.debug ?? false,
|
||||
addCompilerVersion: options.compilerVersion ?? true,
|
||||
|
|
@ -51,8 +50,7 @@ function buildLdmlKeyboardToMemory(inputFilename: string, options: BuildActivity
|
|||
// TODO: treatWarningsAsErrors: options.treatWarningsAsErrors,
|
||||
}
|
||||
|
||||
const c: CompilerCallbacks = new NodeCompilerCallbacks();
|
||||
const k = new kmc.Compiler(c, options);
|
||||
const k = new kmc.Compiler(callbacks, options);
|
||||
let source = k.load(inputFilename);
|
||||
if (!source) {
|
||||
return [null, null, null];
|
||||
|
|
|
|||
|
|
@ -1,19 +1,17 @@
|
|||
import * as fs from 'fs';
|
||||
import { BuildActivity, BuildActivityOptions } from './BuildActivity.js';
|
||||
import { compileModel } from '@keymanapp/kmc-model';
|
||||
import { NodeCompilerCallbacks } from '../../util/NodeCompilerCallbacks.js';
|
||||
import { CompilerCallbacks } from '@keymanapp/common-types';
|
||||
|
||||
export class BuildModel extends BuildActivity {
|
||||
public get name(): string { return 'Lexical model'; }
|
||||
public get sourceExtension(): string { return '.model.ts'; }
|
||||
public get compiledExtension(): string { return '.model.js'; }
|
||||
public get description(): string { return 'Build a lexical model'; }
|
||||
public async build(infile: string, options: BuildActivityOptions): Promise<boolean> {
|
||||
public async build(infile: string, callbacks: CompilerCallbacks, options: BuildActivityOptions): Promise<boolean> {
|
||||
let outputFilename: string = this.getOutputFilename(infile, options);
|
||||
let code = null;
|
||||
|
||||
const callbacks = new NodeCompilerCallbacks();
|
||||
|
||||
// Compile:
|
||||
try {
|
||||
code = compileModel(infile, callbacks);
|
||||
|
|
|
|||
|
|
@ -2,15 +2,13 @@ import * as fs from 'fs';
|
|||
import { BuildActivity, BuildActivityOptions } from './BuildActivity.js';
|
||||
import KmpCompiler from '@keymanapp/kmc-package';
|
||||
import { CompilerCallbacks } from '@keymanapp/common-types';
|
||||
import { NodeCompilerCallbacks } from '../../util/NodeCompilerCallbacks.js';
|
||||
|
||||
export class BuildPackage extends BuildActivity {
|
||||
public get name(): string { return 'Package'; }
|
||||
public get sourceExtension(): string { return '.kps'; }
|
||||
public get compiledExtension(): string { return '.kmp'; }
|
||||
public get description(): string { return 'Build a Keyman package'; }
|
||||
public async build(infile: string, options: BuildActivityOptions): Promise<boolean> {
|
||||
const c: CompilerCallbacks = new NodeCompilerCallbacks();
|
||||
public async build(infile: string, callbacks: CompilerCallbacks, options: BuildActivityOptions): Promise<boolean> {
|
||||
|
||||
const outfile = this.getOutputFilename(infile, options);
|
||||
|
||||
|
|
@ -19,7 +17,7 @@ export class BuildPackage extends BuildActivity {
|
|||
//
|
||||
|
||||
const kpsString: string = fs.readFileSync(infile, 'utf8');
|
||||
const kmpCompiler = new KmpCompiler(c);
|
||||
const kmpCompiler = new KmpCompiler(callbacks);
|
||||
const kmpJsonData = kmpCompiler.transformKpsToKmpObject(kpsString, infile);
|
||||
if(!kmpJsonData) {
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
import * as path from 'path';
|
||||
import * as fs from 'fs';
|
||||
import { CompilerCallbacks, KeymanDeveloperProject, KPJFileReader } from '@keymanapp/common-types';
|
||||
import { NodeCompilerCallbacks } from '../../util/NodeCompilerCallbacks.js';
|
||||
import { KeymanDeveloperProjectFile } from '../../../../../../common/web/types/src/kpj/keyman-developer-project.js';
|
||||
import { BuildActivity, BuildActivityOptions } from './BuildActivity.js';
|
||||
import { buildActivities } from './buildActivities.js';
|
||||
import { InfrastructureMessages } from 'src/messages/messages.js';
|
||||
|
||||
const PROJECT_EXTENSION = '.kpj';
|
||||
|
||||
|
|
@ -13,27 +13,27 @@ export class BuildProject extends BuildActivity {
|
|||
public get sourceExtension(): string { return PROJECT_EXTENSION; }
|
||||
public get compiledExtension(): string { return null; }
|
||||
public get description(): string { return 'Build a keyboard or lexical model project'; }
|
||||
public async build(infile: string, options: BuildActivityOptions): Promise<boolean> {
|
||||
let builder = new ProjectBuilder(infile, options);
|
||||
public async build(infile: string, callbacks: CompilerCallbacks, options: BuildActivityOptions): Promise<boolean> {
|
||||
let builder = new ProjectBuilder(infile, callbacks, options);
|
||||
return builder.run();
|
||||
}
|
||||
}
|
||||
|
||||
class ProjectBuilder {
|
||||
callbacks: CompilerCallbacks = new NodeCompilerCallbacks();
|
||||
callbacks: CompilerCallbacks;
|
||||
infile: string;
|
||||
options: BuildActivityOptions;
|
||||
project: KeymanDeveloperProject;
|
||||
|
||||
constructor(infile: string, options: BuildActivityOptions) {
|
||||
constructor(infile: string, callbacks: CompilerCallbacks, options: BuildActivityOptions) {
|
||||
this.infile = path.resolve(infile);
|
||||
this.callbacks = callbacks;
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
async run(): Promise<boolean> {
|
||||
if(this.options.outFile) {
|
||||
// TODO: callbacks.reportMessage
|
||||
console.error('--out-file should not be specified for project builds');
|
||||
this.callbacks.reportMessage(InfrastructureMessages.Error_OutFileNotValidForProjects());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -90,7 +90,7 @@ class ProjectBuilder {
|
|||
const kpjData = this.callbacks.loadFile(null, this.infile);
|
||||
const reader = new KPJFileReader();
|
||||
const kpj = reader.read(kpjData);
|
||||
const schema = this.callbacks.loadKpjJsonSchema();
|
||||
const schema = this.callbacks.loadSchema('kpj');
|
||||
try {
|
||||
reader.validate(kpj, schema);
|
||||
} catch(e) {
|
||||
|
|
@ -121,7 +121,7 @@ class ProjectBuilder {
|
|||
|
||||
fs.mkdirSync(path.dirname(options.outFile), {recursive:true});
|
||||
|
||||
let result = await activity.build(infile, options);
|
||||
let result = await activity.build(infile, this.callbacks, options);
|
||||
if(result) {
|
||||
console.log(`${path.basename(infile )} built successfully.`);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import * as fs from 'fs';
|
|||
import * as path from 'path';
|
||||
import * as kmc from '@keymanapp/kmc-keyboard';
|
||||
import { CompilerCallbacks, LDMLKeyboardTestDataXMLSourceFile } from '@keymanapp/common-types';
|
||||
import { NodeCompilerCallbacks } from '../../util/NodeCompilerCallbacks.js';
|
||||
import { NodeCompilerCallbacks } from '../../messages/NodeCompilerCallbacks.js';
|
||||
|
||||
export interface BuildTestDataOptions {
|
||||
outFile?: string;
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import { Command } from 'commander';
|
|||
import { compileModel } from '@keymanapp/kmc-model';
|
||||
import { SysExits } from './util/sysexits.js';
|
||||
import KEYMAN_VERSION from "@keymanapp/keyman-version";
|
||||
import { NodeCompilerCallbacks } from './util/NodeCompilerCallbacks.js';
|
||||
import { NodeCompilerCallbacks } from './messages/NodeCompilerCallbacks.js';
|
||||
|
||||
let inputFilename: string;
|
||||
const program = new Command();
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import KmpCompiler from '@keymanapp/kmc-package';
|
|||
import { ModelInfoOptions as ModelInfoOptions, writeMergedModelMetadataFile } from '@keymanapp/kmc-model-info';
|
||||
import { SysExits } from './util/sysexits.js';
|
||||
import KEYMAN_VERSION from "@keymanapp/keyman-version";
|
||||
import { NodeCompilerCallbacks } from './util/NodeCompilerCallbacks.js';
|
||||
import { NodeCompilerCallbacks } from './messages/NodeCompilerCallbacks.js';
|
||||
|
||||
let inputFilename: string;
|
||||
const program = new Command();
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import { Command } from 'commander';
|
|||
import KmpCompiler from '@keymanapp/kmc-package';
|
||||
import { SysExits } from './util/sysexits.js';
|
||||
import KEYMAN_VERSION from "@keymanapp/keyman-version";
|
||||
import { NodeCompilerCallbacks } from './util/NodeCompilerCallbacks.js';
|
||||
import { NodeCompilerCallbacks } from './messages/NodeCompilerCallbacks.js';
|
||||
|
||||
let inputFilename: string;
|
||||
const program = new Command();
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import * as fs from 'fs';
|
||||
import { CompilerCallbacks, CompilerEvent, compilerErrorSeverityName } from '@keymanapp/common-types';
|
||||
import { CompilerCallbacks, CompilerSchema, CompilerEvent, compilerErrorSeverityName } from '@keymanapp/common-types';
|
||||
|
||||
/**
|
||||
* Concrete implementation for CLI use
|
||||
|
|
@ -27,20 +27,12 @@ export class NodeCompilerCallbacks implements CompilerCallbacks {
|
|||
}
|
||||
}
|
||||
|
||||
loadLdmlKeyboardSchema(): Buffer {
|
||||
let schemaPath = new URL('ldml-keyboard.schema.json', import.meta.url);
|
||||
return fs.readFileSync(schemaPath);
|
||||
debug(msg: string) {
|
||||
console.debug(msg);
|
||||
}
|
||||
loadLdmlKeyboardTestSchema(): Buffer {
|
||||
let schemaPath = new URL('ldml-keyboardtest.schema.json', import.meta.url);
|
||||
return fs.readFileSync(schemaPath);
|
||||
}
|
||||
loadKvksJsonSchema(): Buffer {
|
||||
let schemaPath = new URL('kvks.schema.json', import.meta.url);
|
||||
return fs.readFileSync(schemaPath);
|
||||
}
|
||||
loadKpjJsonSchema(): Buffer {
|
||||
let schemaPath = new URL('kpj.schema.json', import.meta.url);
|
||||
|
||||
loadSchema(schema: CompilerSchema) {
|
||||
let schemaPath = new URL(schema + '.schema.json', import.meta.url);
|
||||
return fs.readFileSync(schemaPath);
|
||||
}
|
||||
}
|
||||
39
developer/src/kmc/src/messages/messages.ts
Normal file
39
developer/src/kmc/src/messages/messages.ts
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
import { CompilerErrorNamespace, CompilerErrorSeverity, CompilerMessageSpec as m } from "@keymanapp/common-types";
|
||||
|
||||
const Namespace = CompilerErrorNamespace.Infrastructure;
|
||||
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;
|
||||
|
||||
export class InfrastructureMessages {
|
||||
static Fatal_UnexpectedException = (o:{e: any}) => m(this.FATAL_UnexpectedException,
|
||||
`Unexpected exception: ${(o.e ?? 'unknown error').toString()}\n\nCall stack:\n${(o.e instanceof Error ? o.e.stack : (new Error()).stack)}`);
|
||||
static FATAL_UnexpectedException = SevFatal | 0x0001;
|
||||
|
||||
static Info_BuildingFile = (o:{filename:string}) => m(this.INFO_BuildingFile,
|
||||
`Building ${o.filename}`);
|
||||
static INFO_BuildingFile = SevInfo | 0x0002;
|
||||
|
||||
static Error_FileDoesNotExist = (o:{filename:string}) => m(this.ERROR_FileDoesNotExist,
|
||||
`File ${o.filename} does not exist`);
|
||||
static ERROR_FileDoesNotExist = SevError | 0x0003;
|
||||
|
||||
static Error_FileTypeNotRecognized = (o:{filename: string, extensions: string}) => m(this.ERROR_FileTypeNotRecognized,
|
||||
`Unrecognised input file ${o.filename}, expecting ${o.extensions}, or project folder`);
|
||||
static ERROR_FileTypeNotRecognized = SevError | 0x0004;
|
||||
|
||||
static Error_OutFileNotValidForProjects = () => m(this.ERROR_OutFileNotValidForProjects,
|
||||
`--out-file should not be specified for project builds`);
|
||||
static ERROR_OutFileNotValidForProjects = SevError | 0x0005;
|
||||
|
||||
static Info_FileBuiltSuccessfully = (o:{filename:string}) => m(this.INFO_FileBuiltSuccessfully,
|
||||
`${o.filename} built successfully.`);
|
||||
static INFO_FileBuiltSuccessfully = SevInfo | 0x0006;
|
||||
|
||||
static Info_FileNotBuiltSuccessfully = (o:{filename:string}) => m(this.INFO_FileNotBuiltSuccessfully,
|
||||
`${o.filename} failed to build.`);
|
||||
static INFO_FileNotBuiltSuccessfully = SevInfo | 0x0007;
|
||||
}
|
||||
|
||||
Loading…
Add table
Reference in a new issue