diff --git a/common/web/types/src/main.ts b/common/web/types/src/main.ts index 3ebb5bd549..b783602fe5 100644 --- a/common/web/types/src/main.ts +++ b/common/web/types/src/main.ts @@ -28,3 +28,5 @@ export { TouchLayoutFileWriter, TouchLayoutFileWriterOptions } from './keyman-to export * as KPJ from './kpj/kpj-file.js'; export { KPJFileReader } from './kpj/kpj-file-reader.js'; export { KeymanDeveloperProject } from './kpj/keyman-developer-project.js'; + +export * as util from './util/util.js'; \ No newline at end of file diff --git a/common/web/types/src/util/util.ts b/common/web/types/src/util/util.ts index 7d70d001d4..9594c6c2f1 100644 --- a/common/web/types/src/util/util.ts +++ b/common/web/types/src/util/util.ts @@ -66,3 +66,19 @@ export function unescapeString(s: string): string { return s; } + +/** + * This function operates similarly to Node's path.basename(); unlike + * path.basename(), it currently requires the ext parameter. + * @param name a pathname, which should end in ext, e.g. "/tmp/file.xml" or "C:\temp\file.xml" + * @param ext a file extension. including initial period, such as ".xml" + * @returns the base name without path or extension + */ +export function basename(name: string, ext: string) { + const basenameRegexp = new RegExp("([\\/\\\\]|^)([^\\/\\\\]+)\\"+ext+"$", "i"); + const m = name.match(basenameRegexp); + if(!m) { + return null; + } + return m[2]; +} \ No newline at end of file diff --git a/common/web/types/test/util/test-util.ts b/common/web/types/test/util/test-util.ts new file mode 100644 index 0000000000..0bf60a95af --- /dev/null +++ b/common/web/types/test/util/test-util.ts @@ -0,0 +1,17 @@ +import 'mocha'; +import {assert} from 'chai'; +import {basename} from '../../src/util/util.js'; + +describe('test basename()', function() { + it("should correctly extract a base name", function() { + assert.equal(basename("file.ext", ".ext"), "file"); + assert.equal(basename("/tmp/file.ext", ".ext"), "file"); + assert.equal(basename("..\\myfile.xml", ".xml"), "myfile"); + assert.equal(basename("C:\\temp.ext\\file.ext", ".ext"), "file"); + }); + + it("should return null if ext cannot be matched", function() { + assert.isNull(basename("file.ext", ".xml")); + assert.isNull(basename("file.xml.ext", ".xml")); + }); +}); diff --git a/developer/src/kmc-keyboard/src/compiler/keymanweb-compiler.ts b/developer/src/kmc-keyboard/src/compiler/keymanweb-compiler.ts index f9e451d380..7996fc1bc0 100644 --- a/developer/src/kmc-keyboard/src/compiler/keymanweb-compiler.ts +++ b/developer/src/kmc-keyboard/src/compiler/keymanweb-compiler.ts @@ -1,4 +1,4 @@ -import { VisualKeyboard, LDMLKeyboard, TouchLayoutFileWriter } from "@keymanapp/common-types"; +import { util, VisualKeyboard, LDMLKeyboard, TouchLayoutFileWriter } from "@keymanapp/common-types"; import CompilerOptions from "./compiler-options.js"; import { TouchLayoutCompiler } from "./touch-layout-compiler.js"; import VisualKeyboardCompiler from "./visual-keyboard-compiler.js"; @@ -43,11 +43,10 @@ export class KeymanWebCompiler { } private cleanName(name: string): string { - const m = name.match(/([\/\\]|^)([^\/\\]+)\.xml$/i); - if(!m) { + let result = util.basename(name, '.xml'); + if(!result) { throw new Error(`Invalid file name ${name}`); } - let result = m[2]; result = result.replaceAll(/[^a-z0-9]/g, '_'); if(result.match(/^[0-9]/)) {