Skip to content

Commit

Permalink
feat(developer): kmc-generate module
Browse files Browse the repository at this point in the history
Plenty of todo items left but this is a mostly-functional module for the
kmc generate command for automatically creating keyboard and model
projects.
  • Loading branch information
mcdurdin committed Mar 17, 2024
1 parent 0d2e044 commit 3d22452
Show file tree
Hide file tree
Showing 57 changed files with 2,302 additions and 2 deletions.
4 changes: 4 additions & 0 deletions common/web/types/src/util/compiler-interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,10 @@ export enum CompilerErrorNamespace {
* kmc-keyboard-info 0x9000…0x9FFF
*/
KeyboardInfoCompiler = 0x9000,
/**
* kmc-generate 0xA000…0xAFFF
*/
Generator = 0xA000,
};

/**
Expand Down
1 change: 1 addition & 0 deletions developer/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ builder_describe \
":utils=src/common/web/utils Developer utils" \
":kmcmplib=src/kmcmplib Compiler - .kmn compiler" \
":kmc-analyze=src/kmc-analyze Compiler - Analysis Tools" \
":kmc-generate=src/kmc-generate Compiler - Generation Tools" \
":kmc-keyboard-info=src/kmc-keyboard-info Compiler - .keyboard_info Module" \
":kmc-kmn=src/kmc-kmn Compiler - .kmn to .kmx and .js Keyboard Module" \
":kmc-ldml=src/kmc-ldml Compiler - LDML Keyboard Module" \
Expand Down
6 changes: 5 additions & 1 deletion developer/src/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -64,14 +64,18 @@ server: .virtual
cd $(DEVELOPER_ROOT)\src\server
$(MAKE) $(TARGET)

kmc: kmc-analyze kmc-ldml kmc-keyboard-info kmc-kmn kmc-model kmc-model-info kmc-package
kmc: kmc-analyze kmc-generate kmc-ldml kmc-keyboard-info kmc-kmn kmc-model kmc-model-info kmc-package
cd $(DEVELOPER_ROOT)\src\kmc
$(MAKE) $(TARGET)

kmc-analyze: .virtual
cd $(DEVELOPER_ROOT)\src\kmc-analyze
$(MAKE) $(TARGET)

kmc-generate: .virtual
cd $(DEVELOPER_ROOT)\src\kmc-generate
$(MAKE) $(TARGET)

kmc-keyboard-info: .virtual
cd $(DEVELOPER_ROOT)\src\kmc-keyboard-info
$(MAKE) $(TARGET)
Expand Down
4 changes: 4 additions & 0 deletions developer/src/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ node-based next generation compiler, hosts kmc, (and legacy kmlmc, kmlmp)

File analysis tools for Keyman files.

### src/kmc-generate - Generation tools

Project generation tools for Keyman.

### src/kmc-keyboard-info - Keyboard Info Compiler

Builds .keyboard_info files for use on the Keyman Cloud keyboard repository
Expand Down
15 changes: 15 additions & 0 deletions developer/src/kmc-generate/.eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
module.exports = {
parserOptions: {
project: ["./tsconfig.json", "./test/tsconfig.json"],
},
ignorePatterns: ["test/fixtures/**/*", "src/template/**/*"],
overrides: [
{
files:"src/**/*.ts",
//TODO: enable extends: ["../../../common/web/eslint/eslintNoNodeImports.js"],
}
],
rules: {
"prefer-const": 1,
},
};
39 changes: 39 additions & 0 deletions developer/src/kmc-generate/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#
# Keyman Developer - kmc Keyboard Compiler Makefile
#

!include ..\Defines.mak

# We do configure here because parent Makefile calls this first; other
# kmc and kmc-* makefiles don't do it
build: configure .virtual
$(GIT_BASH_FOR_KEYMAN) build.sh build

configure: .virtual
$(GIT_BASH_FOR_KEYMAN) build.sh configure

clean: .virtual
$(GIT_BASH_FOR_KEYMAN) build.sh clean

test: .virtual
$(GIT_BASH_FOR_KEYMAN) build.sh test

# build.sh bundle must be run from shell as it requires a temp folder to be
# passed in. See inst/download.in.mak for instantiation.

publish: .virtual
$(GIT_BASH_FOR_KEYMAN) build.sh publish

signcode:
@rem nothing to do

wrap-symbols:
@rem nothing to do

test-manifest:
@rem nothing to do

install:
@rem nothing to do

!include ..\Target.mak
49 changes: 49 additions & 0 deletions developer/src/kmc-generate/build.sh
Original file line number Diff line number Diff line change
@@ -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/build-utils.sh"
## END STANDARD BUILD SCRIPT INCLUDE

. "$KEYMAN_ROOT/resources/build/build-utils-ci.inc.sh"

builder_describe "Build Keyman kmc-generate module" \
"@/common/web/keyman-version" \
"@/common/web/types" \
"@/developer/src/common/web/test-helpers" \
"configure" \
"build" \
"clean" \
"test" \
"pack build a local .tgz pack for testing" \
"publish publish to npm" \
"--dry-run,-n don't actually publish, just dry run"
builder_describe_outputs \
configure /node_modules \
build /developer/src/kmc-generate/build/src/main.js

builder_parse "$@"

#-------------------------------------------------------------------------------------------------------------------

do_build() {
tsc --build
rm -rf ./build/src/template
mkdir -p ./build/src/template
cp -R ./src/template/ ./build/src/
}

do_test() {
eslint .
cd test
tsc -b
cd ..
c8 --reporter=lcov --reporter=text mocha "${builder_extra_params[@]}"
}

builder_run_action clean rm -rf ./build/ ./tsconfig.tsbuildinfo
builder_run_action configure verify_npm_setup
builder_run_action build do_build
builder_run_action test do_test
builder_run_action publish builder_publish_to_npm
builder_run_action pack builder_publish_to_pack
66 changes: 66 additions & 0 deletions developer/src/kmc-generate/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
{
"name": "@keymanapp/kmc-generate",
"description": "Keyman Developer generate module",
"keywords": [
"keyboard",
"keyman",
"ldml",
"unicode"
],
"type": "module",
"exports": {
".": "./build/src/main.js"
},
"files": [
"/build/src/"
],
"scripts": {
"build": "gosh ./build.sh build",
"lint": "eslint .",
"test": "gosh ./build.sh test"
},
"author": "Marc Durdin <[email protected]> (https://github.com/mcdurdin)",
"license": "MIT",
"bugs": {
"url": "https://github.com/keymanapp/keyman/issues"
},
"dependencies": {
"@keymanapp/keyman-version": "*",
"@keymanapp/common-types": "*"
},
"devDependencies": {
"@keymanapp/developer-test-helpers": "*",
"@keymanapp/resources-gosh": "*",
"@types/chai": "^4.1.7",
"@types/mocha": "^5.2.7",
"@types/node": "^20.4.1",
"@types/semver": "^7.3.12",
"c8": "^7.12.0",
"chai": "^4.3.4",
"chalk": "^2.4.2",
"mocha": "^8.4.0",
"ts-node": "^9.1.1",
"typescript": "^4.9.5"
},
"mocha": {
"spec": "build/test/**/test-*.js",
"require": [
"source-map-support/register"
]
},
"c8": {
"all": true,
"src": [
"src/"
],
"exclude-after-remap": true,
"exclude": [
"test/",
"src/template/"
]
},
"repository": {
"type": "git",
"url": "git+https://github.com/keymanapp/keyman.git"
}
}
125 changes: 125 additions & 0 deletions developer/src/kmc-generate/src/abstract-generator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import * as fs from 'fs'; //TODO
import { CompilerCallbacks, CompilerLogLevel } from "@keymanapp/common-types";
import { fileURLToPath } from 'url';

export interface GeneratorOptions /* not inheriting from CompilerBaseOptions */ {
/**
* Reporting level to console, used by NodeCompilerCallbacks (not used in
* compiler modules; all messages are still reported to the internal log)
*/
logLevel?: CompilerLogLevel;
targets: string[];
outPath: string;
name: string;
copyright?: string;
version: string;
languageTags: string[];
author?: string;
icon: Boolean;
description?: string;
};

export class AbstractGenerator {
/**
* id for the keyboard or model, aka the basename sans extension, foldername
* for the project
*/
protected get id() { return this._id }
private _id: string;

/**
* extension of options.copyright including copyright year
*/
protected fullCopyright: string = '';

/**
* identifiers for lines to include when transforming template files, filled
* by child classes
*/
protected get includedPrefixes() { return this._includedPrefixes; }
private _includedPrefixes: string[];

/**
* tokens to rewrite in output files
*/
protected get tokenMap() { return this._tokenMap; }
private _tokenMap: {[index:string]: string};

/**
* map of all files to be transformed, filled by this class and subclasses
*/
protected get filenameMap() { return this._filenameMap; }
private _filenameMap: {[index:string]: string};

/**
* base path for template files in this module
*/
protected get templateBasePath() { return this._templateBasePath; }
private _templateBasePath: string;

protected static readonly SPath_Source = 'source/';
protected static readonly SFile_WelcomeHTM = `${this.SPath_Source}welcome.htm`;
protected static readonly SFile_ReadmeHTM = `${this.SPath_Source}readme.htm`;
protected static readonly SFile_HistoryMD = 'HISTORY.md';
protected static readonly SFile_LicenseMD = 'LICENSE.md';
protected static readonly SFile_ReadmeMD = 'README.md';

constructor(protected callbacks: CompilerCallbacks, protected options: GeneratorOptions) {}

async init(id: string): Promise<boolean> {
this._id = id;
this._includedPrefixes = [];
this._filenameMap = {};
this._tokenMap = {};

this._templateBasePath = this.callbacks.path.join(
this.callbacks.path.dirname(fileURLToPath(import.meta.url)),
'template'
)
;


// These files are currently always included, for all project types
this.filenameMap[AbstractGenerator.SFile_WelcomeHTM] = AbstractGenerator.SFile_WelcomeHTM;
this.filenameMap[AbstractGenerator.SFile_ReadmeHTM] = AbstractGenerator.SFile_ReadmeHTM;
this.filenameMap[AbstractGenerator.SFile_HistoryMD] = AbstractGenerator.SFile_HistoryMD;
this.filenameMap[AbstractGenerator.SFile_LicenseMD] = AbstractGenerator.SFile_LicenseMD;
this.filenameMap[AbstractGenerator.SFile_ReadmeMD] = AbstractGenerator.SFile_ReadmeMD;
return true;
}

/**
* Create folders and verify accessibility
* @returns
*/
async run(): Promise<boolean> {

if(this.targetPathExists()) {
// TODO yammer
console.error('target path exists');
return false;
}
if(!this.createTargetPath()) {
// TODO yammer
console.error('failed creating target path');
return false;
}

return true;
}

protected readonly targetPath = () => this.callbacks.path.join(this.options.outPath,this.id);

private readonly targetPathExists = () => this.callbacks.fs.existsSync(this.targetPath());

private createTargetPath() {
/*TODO: this.callbacks.*/fs.mkdirSync(this.callbacks.path.join(this.targetPath(),'source'), {recursive:true});
/*if(!) {
// TODO log exception
// raise EKeyboardProjectTemplate.Create('Could not create destination path '+BasePath+ID);
return false;
}*/
return true;
}
}

Loading

0 comments on commit 3d22452

Please sign in to comment.