mirror of
https://github.com/keymanapp/keyman.git
synced 2026-08-31 20:57:41 +00:00
Merge pull request #7184 from keymanapp/feat/developer/7181-use-json-schema-to-verify-source-file
feat(developer): use json schema to verify source file 🙀
This commit is contained in:
commit
3307dc63a7
17 changed files with 1149 additions and 13 deletions
|
|
@ -46,6 +46,8 @@ fi
|
|||
|
||||
if builder_has_action build; then
|
||||
npm run build
|
||||
# We need the schema file at runtime and bundled
|
||||
cp "$KEYMAN_ROOT/resources/standards-data/ldml-keyboards/techpreview/ldml-keyboard.schema.json" "$THIS_SCRIPT_PATH/build/src/"
|
||||
builder_report success build
|
||||
fi
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
],
|
||||
"scripts": {
|
||||
"build": "tsc -b",
|
||||
"test": "cd test && tsc -b && cd .. && mocha ",
|
||||
"test": "cd test && tsc -b && cd .. && mocha",
|
||||
"prepublishOnly": "npm run build"
|
||||
},
|
||||
"author": "Marc Durdin <marc@keyman.com> (https://github.com/mcdurdin)",
|
||||
|
|
@ -19,6 +19,7 @@
|
|||
"kmldmlc": "build/src/kmldmlc.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"ajv": "^8.11.0",
|
||||
"commander": "^3.0.0",
|
||||
"crc-32": "^1.2.2",
|
||||
"restructure": "^3.0.0",
|
||||
|
|
@ -37,7 +38,9 @@
|
|||
"ts-node": "^9.1.1"
|
||||
},
|
||||
"mocha": {
|
||||
"spec": "build/test/test-*.js"
|
||||
"spec": "build/test/**/test-*.js",
|
||||
"require": ["source-map-support/register"]
|
||||
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
|
|
|||
|
|
@ -5,5 +5,6 @@ export interface CompilerEvent {
|
|||
|
||||
export default interface CompilerCallbacks {
|
||||
loadFile(baseFilename: string, filename: string): Buffer;
|
||||
loadLdmlKeyboardSchema(): Buffer;
|
||||
reportMessage(event: CompilerEvent): void;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -37,6 +37,10 @@ export class CompilerErrors {
|
|||
m(this.HINT_OneOrMoreRepeatedLocales, `After minimization, one or more locales is repeated and has been removed`);
|
||||
static HINT_OneOrMoreRepeatedLocales = SevHint | 0x0006;
|
||||
|
||||
static InvalidFile = (errorText: string) =>
|
||||
m(this.ERROR_InvalidFile, `The source file has an invalid structure: ${errorText}`);
|
||||
static ERROR_InvalidFile = SevError | 0x0007;
|
||||
|
||||
static severityName(code: number): string {
|
||||
let severity = code & CompilerErrorSeverity.Severity_Mask;
|
||||
switch(severity) {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
import * as xml2js from 'xml2js';
|
||||
import LDMLKeyboardXMLSourceFile from './ldml-keyboard-xml';
|
||||
import CompilerCallbacks from '../compiler/callbacks';
|
||||
import Ajv from 'ajv';
|
||||
import { CompilerErrors } from '../compiler/errors';
|
||||
|
||||
export default class LDMLKeyboardXMLSourceFileReader {
|
||||
private readonly callbacks: CompilerCallbacks;
|
||||
|
|
@ -16,7 +18,14 @@ export default class LDMLKeyboardXMLSourceFileReader {
|
|||
*/
|
||||
private boxArrays(source: any) {
|
||||
let box = (o: any, x: string) => {
|
||||
if(typeof o == 'object' && !Array.isArray(o[x])) o[x] = [o[x]];
|
||||
if(typeof o == 'object' && !Array.isArray(o[x])) {
|
||||
if(o[x] === null || o[x] === undefined) {
|
||||
o[x] = [];
|
||||
}
|
||||
else {
|
||||
o[x] = [o[x]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
box(source?.keyboard, 'layerMaps');
|
||||
|
|
@ -36,6 +45,16 @@ export default class LDMLKeyboardXMLSourceFileReader {
|
|||
return source;
|
||||
}
|
||||
|
||||
public validate(source: LDMLKeyboardXMLSourceFile): LDMLKeyboardXMLSourceFile {
|
||||
const schema = JSON.parse(this.callbacks.loadLdmlKeyboardSchema().toString('utf8'));
|
||||
const ajv = new Ajv();
|
||||
if(!ajv.validate(schema, source)) {
|
||||
this.callbacks.reportMessage(CompilerErrors.InvalidFile(ajv.errorsText()));
|
||||
return null;
|
||||
}
|
||||
return source;
|
||||
}
|
||||
|
||||
public loadFile(filename: string) {
|
||||
const buf = this.callbacks.loadFile(filename, filename);
|
||||
return this.load(buf);
|
||||
|
|
@ -47,11 +66,12 @@ export default class LDMLKeyboardXMLSourceFileReader {
|
|||
let parser = new xml2js.Parser({
|
||||
explicitArray: false,
|
||||
mergeAttrs: true,
|
||||
emptyTag: {}
|
||||
});
|
||||
parser.parseString(file, (e: unknown, r: unknown) => { a = r as LDMLKeyboardXMLSourceFile });
|
||||
return a;
|
||||
})();
|
||||
|
||||
return this.boxArrays(source);
|
||||
return this.validate(this.boxArrays(source));
|
||||
}
|
||||
}
|
||||
|
|
@ -46,6 +46,9 @@ class CompilerCallbacks {
|
|||
reportMessage(event: CompilerEvent): void {
|
||||
console.log(CompilerErrors.severityName(event.code) + ' ' + event.code.toString(16) + ': ' + event.message);
|
||||
}
|
||||
loadLdmlKeyboardSchema(): Buffer {
|
||||
return fs.readFileSync(path.join(__dirname, 'ldml-keyboard.schema.json'));
|
||||
}
|
||||
}
|
||||
|
||||
function compileKeyboard(inputFilename: string): Uint8Array {
|
||||
|
|
|
|||
19
developer/src/kmldmlc/test/fixtures/invalid-conforms-to.xml
vendored
Normal file
19
developer/src/kmldmlc/test/fixtures/invalid-conforms-to.xml
vendored
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!--
|
||||
DOCTYPE keyboard SYSTEM "../../../../../resources/standards-data/ldml-keyboards/techpreview/ldmlKeyboard.dtd"
|
||||
Disabling doctype for this invalid file, not used by compiler, and avoids complaints in IDEs etc.
|
||||
-->
|
||||
<keyboard locale="mt" conformsTo="nothing-anyone-ever-heard-of">
|
||||
<info author="srl295" indicator="🙀" layout="qwerty" normalization="NFC" />
|
||||
|
||||
<names>
|
||||
<name value="TestKbd" />
|
||||
</names>
|
||||
|
||||
<keys>
|
||||
<key id="hmaqtua" to="ħ" />
|
||||
<key id="that" to="ថា" />
|
||||
</keys>
|
||||
|
||||
</keyboard>
|
||||
8
developer/src/kmldmlc/test/fixtures/invalid-structure-per-dtd.xml
vendored
Normal file
8
developer/src/kmldmlc/test/fixtures/invalid-structure-per-dtd.xml
vendored
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!--
|
||||
DOCTYPE keyboard SYSTEM "../../../../../resources/standards-data/ldml-keyboards/techpreview/ldmlKeyboard.dtd"
|
||||
Disabling doctype for this invalid file, not used by compiler, and avoids complaints in IDEs etc.
|
||||
-->
|
||||
<keyboard locale="mt" conformsTo="techpreview">
|
||||
</keyboard>
|
||||
|
|
@ -29,6 +29,11 @@ export class CompilerCallbacks {
|
|||
reportMessage(event: CompilerEvent): void {
|
||||
this.messages.push(event);
|
||||
}
|
||||
loadLdmlKeyboardSchema(): Buffer {
|
||||
// Relative paths phooey!
|
||||
return fs.readFileSync(path.join(__dirname, '..', '..', '..', '..', '..', '..',
|
||||
'resources', 'standards-data', 'ldml-keyboards', 'techpreview', 'ldml-keyboard.schema.json'));
|
||||
}
|
||||
}
|
||||
|
||||
export function loadSectionFixture(compilerClass: typeof SectionCompiler, filename: string, callbacks: CompilerCallbacks): Section {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,30 @@
|
|||
import 'mocha';
|
||||
import {assert} from 'chai';
|
||||
import {CompilerCallbacks, makePathToFixture} from '../helpers/index';
|
||||
import LDMLKeyboardXMLSourceFileReader from '../../src/keyman/ldml-keyboard/ldml-keyboard-xml-reader';
|
||||
import { CompilerErrors } from '../../src/keyman/compiler/errors';
|
||||
|
||||
describe('ldml keyboard xml reader tests', function() {
|
||||
this.slow(500); // 0.5 sec -- json schema validation takes a while
|
||||
|
||||
it("should fail to load files that don't conform to DTD", function() {
|
||||
const inputFilename = makePathToFixture('invalid-structure-per-dtd.xml');
|
||||
const callbacks = new CompilerCallbacks();
|
||||
let reader = new LDMLKeyboardXMLSourceFileReader(callbacks);
|
||||
const source = reader.loadFile(inputFilename);
|
||||
assert.isNull(source);
|
||||
assert.equal(callbacks.messages.length, 1);
|
||||
assert.deepEqual(callbacks.messages[0], CompilerErrors.InvalidFile("data/keyboard must have required property 'names'"));
|
||||
});
|
||||
|
||||
it("should fail to load files with an invalid conformsTo", function() {
|
||||
const inputFilename = makePathToFixture('invalid-conforms-to.xml');
|
||||
const callbacks = new CompilerCallbacks();
|
||||
let reader = new LDMLKeyboardXMLSourceFileReader(callbacks);
|
||||
const source = reader.loadFile(inputFilename);
|
||||
assert.isNull(source);
|
||||
assert.equal(callbacks.messages.length, 1);
|
||||
assert.deepEqual(callbacks.messages[0], CompilerErrors.InvalidFile("data/keyboard/conformsTo must be equal to one of the allowed values"));
|
||||
});
|
||||
|
||||
});
|
||||
|
|
@ -30,6 +30,8 @@ function compileKeyboard(inputFilename: string): Uint8Array {
|
|||
}
|
||||
|
||||
describe('compiler-tests', function() {
|
||||
this.slow(500); // 0.5 sec -- json schema validation takes a while
|
||||
|
||||
it('should-build-fixtures', async function() {
|
||||
// Let's build basic.xml
|
||||
// It should match basic.kmx (built from basic.txt)
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ import { Loca } from '../src/keyman/kmx/kmx-plus';
|
|||
import { CompilerErrors } from '../src/keyman/compiler/errors';
|
||||
|
||||
describe('loca', function () {
|
||||
this.slow(500); // 0.5 sec -- json schema validation takes a while
|
||||
|
||||
it('should compile minimal loca data', function() {
|
||||
const callbacks = new CompilerCallbacks();
|
||||
let loca = loadSectionFixture(LocaCompiler, 'sections/loca/minimal.xml', callbacks) as Loca;
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ import { KeyboardSettings, Meta } from '../src/keyman/kmx/kmx-plus';
|
|||
import { CompilerErrors } from '../src/keyman/compiler/errors';
|
||||
|
||||
describe('meta', function () {
|
||||
this.slow(500); // 0.5 sec -- json schema validation takes a while
|
||||
|
||||
it('should compile minimal metadata', function() {
|
||||
const callbacks = new CompilerCallbacks();
|
||||
let meta = loadSectionFixture(MetaCompiler, 'sections/meta/minimal.xml', callbacks) as Meta;
|
||||
|
|
|
|||
63
package-lock.json
generated
63
package-lock.json
generated
|
|
@ -473,6 +473,7 @@
|
|||
"name": "@keymanapp/ldml-keyboard-compiler",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ajv": "^8.11.0",
|
||||
"commander": "^3.0.0",
|
||||
"crc-32": "^1.2.2",
|
||||
"restructure": "^3.0.0",
|
||||
|
|
@ -506,6 +507,21 @@
|
|||
"integrity": "sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw==",
|
||||
"dev": true
|
||||
},
|
||||
"developer/src/kmldmlc/node_modules/ajv": {
|
||||
"version": "8.11.0",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz",
|
||||
"integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==",
|
||||
"dependencies": {
|
||||
"fast-deep-equal": "^3.1.1",
|
||||
"json-schema-traverse": "^1.0.0",
|
||||
"require-from-string": "^2.0.2",
|
||||
"uri-js": "^4.2.2"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/epoberezkin"
|
||||
}
|
||||
},
|
||||
"developer/src/kmldmlc/node_modules/ansi-styles": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
|
||||
|
|
@ -556,6 +572,11 @@
|
|||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"developer/src/kmldmlc/node_modules/json-schema-traverse": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
|
||||
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="
|
||||
},
|
||||
"developer/src/kmldmlc/node_modules/supports-color": {
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
||||
|
|
@ -3340,8 +3361,7 @@
|
|||
"node_modules/fast-deep-equal": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
||||
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
|
||||
"optional": true
|
||||
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
|
||||
},
|
||||
"node_modules/fast-json-stable-stringify": {
|
||||
"version": "2.1.0",
|
||||
|
|
@ -5580,7 +5600,6 @@
|
|||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
|
||||
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
|
|
@ -5747,6 +5766,14 @@
|
|||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/require-from-string": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
|
||||
"integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/require-main-filename": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
|
||||
|
|
@ -6600,7 +6627,6 @@
|
|||
"version": "4.4.1",
|
||||
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
|
||||
"integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"punycode": "^2.1.0"
|
||||
}
|
||||
|
|
@ -7781,6 +7807,7 @@
|
|||
"@types/mocha": "^5.2.7",
|
||||
"@types/node": "^10.14.6",
|
||||
"@types/xml2js": "^0.4.5",
|
||||
"ajv": "^8.11.0",
|
||||
"chai": "^4.3.4",
|
||||
"chalk": "^2.4.2",
|
||||
"commander": "^3.0.0",
|
||||
|
|
@ -7804,6 +7831,17 @@
|
|||
"integrity": "sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw==",
|
||||
"dev": true
|
||||
},
|
||||
"ajv": {
|
||||
"version": "8.11.0",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz",
|
||||
"integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==",
|
||||
"requires": {
|
||||
"fast-deep-equal": "^3.1.1",
|
||||
"json-schema-traverse": "^1.0.0",
|
||||
"require-from-string": "^2.0.2",
|
||||
"uri-js": "^4.2.2"
|
||||
}
|
||||
},
|
||||
"ansi-styles": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
|
||||
|
|
@ -7845,6 +7883,11 @@
|
|||
"integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
|
||||
"dev": true
|
||||
},
|
||||
"json-schema-traverse": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
|
||||
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
||||
|
|
@ -9981,8 +10024,7 @@
|
|||
"fast-deep-equal": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
||||
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
|
||||
"optional": true
|
||||
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
|
||||
},
|
||||
"fast-json-stable-stringify": {
|
||||
"version": "2.1.0",
|
||||
|
|
@ -11747,8 +11789,7 @@
|
|||
"punycode": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
|
||||
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
|
||||
"optional": true
|
||||
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
|
||||
},
|
||||
"q": {
|
||||
"version": "1.5.1",
|
||||
|
|
@ -11874,6 +11915,11 @@
|
|||
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
|
||||
"integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I="
|
||||
},
|
||||
"require-from-string": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
|
||||
"integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="
|
||||
},
|
||||
"require-main-filename": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
|
||||
|
|
@ -12520,7 +12566,6 @@
|
|||
"version": "4.4.1",
|
||||
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
|
||||
"integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"punycode": "^2.1.0"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,4 +12,13 @@ That will very roughly correspond to <https://github.com/unicode-org/cldr/tree/k
|
|||
Each directory contains:
|
||||
|
||||
- `ldmlKeyboard.dtd` - the DTD file
|
||||
- `ldmlKeyboard.xsd` - the XSD file, automatically converted from the DTD using
|
||||
Visual Studio, hand tweaked as necessary
|
||||
- `ldml-keyboard.schema.json` - the JSON schema file, automatically converted
|
||||
from the XSD using xsd2json (https://github.com/Mermade/jgeXml), hand tweaked
|
||||
as necessary:
|
||||
- change toplevel "id" to "$id"
|
||||
- add "type": "object" to /keyboard
|
||||
- change /keyboard/keys/key type to "array"
|
||||
|
||||
- `imports/` - the importable data files (TODO-LDML)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,677 @@
|
|||
{
|
||||
"title": "techpreview/ldmlKeyboard.xsd",
|
||||
"$schema": "http://json-schema.org/schema#",
|
||||
"$id": "http://tempuri.org/ldmlKeyboard",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"keyboard": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"import": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/import"
|
||||
}
|
||||
},
|
||||
"locales": {
|
||||
"$ref": "#/definitions/locales"
|
||||
},
|
||||
"version": {
|
||||
"$ref": "#/definitions/version"
|
||||
},
|
||||
"info": {
|
||||
"$ref": "#/definitions/info"
|
||||
},
|
||||
"names": {
|
||||
"$ref": "#/definitions/names"
|
||||
},
|
||||
"settings": {
|
||||
"$ref": "#/definitions/settings"
|
||||
},
|
||||
"vkeyMaps": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/vkeyMaps"
|
||||
}
|
||||
},
|
||||
"displayMap": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/displayMap"
|
||||
}
|
||||
},
|
||||
"keys": {
|
||||
"$ref": "#/definitions/keys"
|
||||
},
|
||||
"layerMaps": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/layerMaps"
|
||||
}
|
||||
},
|
||||
"transforms": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/transforms"
|
||||
}
|
||||
},
|
||||
"reorders": {
|
||||
"$ref": "#/definitions/reorders"
|
||||
},
|
||||
"backspaces": {
|
||||
"$ref": "#/definitions/backspaces"
|
||||
},
|
||||
"special": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/special"
|
||||
}
|
||||
},
|
||||
"locale": {
|
||||
"type": "string"
|
||||
},
|
||||
"conformsTo": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"techpreview"
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"names",
|
||||
"keys",
|
||||
"locale",
|
||||
"conformsTo"
|
||||
],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"keyboard"
|
||||
],
|
||||
"additionalProperties": false,
|
||||
"definitions": {
|
||||
"import": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"path": {
|
||||
"type": "string"
|
||||
},
|
||||
"base": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"cldr"
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"path"
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"locales": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"locale": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/locale"
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"locale": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"id"
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"version": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"number": {
|
||||
"type": "string"
|
||||
},
|
||||
"cldrVersion": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"techpreview"
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"info": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"author": {
|
||||
"type": "string"
|
||||
},
|
||||
"normalization": {
|
||||
"type": "string"
|
||||
},
|
||||
"layout": {
|
||||
"type": "string"
|
||||
},
|
||||
"indicator": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"names": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"import": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/import"
|
||||
}
|
||||
},
|
||||
"name": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"$ref": "#/definitions/name"
|
||||
}
|
||||
},
|
||||
"special": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/special"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"name"
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"name": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"value": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"value"
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"special": {
|
||||
"type": "string"
|
||||
},
|
||||
"settings": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"fallback": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"omit"
|
||||
]
|
||||
},
|
||||
"transformFailure": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"omit"
|
||||
]
|
||||
},
|
||||
"transformPartial": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"hide"
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"vkeyMaps": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"import": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/import"
|
||||
}
|
||||
},
|
||||
"vkeyMap": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/vkeyMap"
|
||||
}
|
||||
},
|
||||
"special": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/special"
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"vkeyMap": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"from": {
|
||||
"type": "string"
|
||||
},
|
||||
"to": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"from",
|
||||
"to"
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"displayMap": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"import": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/import"
|
||||
}
|
||||
},
|
||||
"display": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/display"
|
||||
}
|
||||
},
|
||||
"displayOptions": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/displayOptions"
|
||||
}
|
||||
},
|
||||
"special": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/special"
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"display": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"to": {
|
||||
"type": "string"
|
||||
},
|
||||
"display": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"to",
|
||||
"display"
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"displayOptions": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"baseCharacter": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"keys": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"import": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/import"
|
||||
}
|
||||
},
|
||||
"special": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/special"
|
||||
}
|
||||
},
|
||||
"key": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/key"
|
||||
}
|
||||
},
|
||||
"flicks": {
|
||||
"$ref": "#/definitions/flicks"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"key": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"flicks": {
|
||||
"type": "string"
|
||||
},
|
||||
"gap": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"true"
|
||||
]
|
||||
},
|
||||
"to": {
|
||||
"type": "string"
|
||||
},
|
||||
"longPress": {
|
||||
"type": "string"
|
||||
},
|
||||
"longPressDefault": {
|
||||
"type": "string"
|
||||
},
|
||||
"multitap": {
|
||||
"type": "string"
|
||||
},
|
||||
"switch": {
|
||||
"type": "string"
|
||||
},
|
||||
"transform": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"no"
|
||||
]
|
||||
},
|
||||
"width": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"id"
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"flicks": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"flick": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"$ref": "#/definitions/flick"
|
||||
}
|
||||
},
|
||||
"special": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/special"
|
||||
}
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"flick",
|
||||
"id"
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"flick": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"directions": {
|
||||
"type": "string"
|
||||
},
|
||||
"to": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"directions",
|
||||
"to"
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"layerMaps": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"import": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/import"
|
||||
}
|
||||
},
|
||||
"layerMap": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/layerMap"
|
||||
}
|
||||
},
|
||||
"special": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/special"
|
||||
}
|
||||
},
|
||||
"form": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"hardware",
|
||||
"touch"
|
||||
]
|
||||
},
|
||||
"minDeviceWidthMM": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"form"
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"layerMap": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"row": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"$ref": "#/definitions/row"
|
||||
}
|
||||
},
|
||||
"special": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/special"
|
||||
}
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"modifier": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"row"
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"row": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"keys": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"keys"
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"transforms": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"import": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/import"
|
||||
}
|
||||
},
|
||||
"transform": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/transform"
|
||||
}
|
||||
},
|
||||
"special": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/special"
|
||||
}
|
||||
},
|
||||
"type": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"type"
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"transform": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"before": {
|
||||
"type": "string"
|
||||
},
|
||||
"from": {
|
||||
"type": "string"
|
||||
},
|
||||
"to": {
|
||||
"type": "string"
|
||||
},
|
||||
"error": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"fail"
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"from",
|
||||
"to"
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"reorders": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"import": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/import"
|
||||
}
|
||||
},
|
||||
"reorder": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/reorder"
|
||||
}
|
||||
},
|
||||
"special": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/special"
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"reorder": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"before": {
|
||||
"type": "string"
|
||||
},
|
||||
"from": {
|
||||
"type": "string"
|
||||
},
|
||||
"order": {
|
||||
"type": "string"
|
||||
},
|
||||
"tertiary": {
|
||||
"type": "string"
|
||||
},
|
||||
"tertiary_base": {
|
||||
"type": "string"
|
||||
},
|
||||
"prebase": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"from"
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"backspaces": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"import": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/import"
|
||||
}
|
||||
},
|
||||
"backspace": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/backspace"
|
||||
}
|
||||
},
|
||||
"special": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/special"
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"backspace": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"before": {
|
||||
"type": "string"
|
||||
},
|
||||
"from": {
|
||||
"type": "string"
|
||||
},
|
||||
"to": {
|
||||
"type": "string"
|
||||
},
|
||||
"error": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"fail"
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"from"
|
||||
],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,304 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- generated via Visual Studio from ldmlKeyboard.dtd -->
|
||||
<xs:schema xmlns="http://tempuri.org/ldmlKeyboard" elementFormDefault="qualified" targetNamespace="http://tempuri.org/ldmlKeyboard" xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
||||
<xs:element name="keyboard">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element minOccurs="0" maxOccurs="unbounded" ref="import" />
|
||||
<xs:element minOccurs="0" maxOccurs="1" ref="locales" />
|
||||
<xs:element minOccurs="0" maxOccurs="1" ref="version" />
|
||||
<xs:element minOccurs="0" maxOccurs="1" ref="info" />
|
||||
<xs:element ref="names" />
|
||||
<xs:element minOccurs="0" maxOccurs="1" ref="settings" />
|
||||
<xs:element minOccurs="0" maxOccurs="unbounded" ref="vkeyMaps" />
|
||||
<xs:element minOccurs="0" maxOccurs="unbounded" ref="displayMap" />
|
||||
<xs:element ref="keys" />
|
||||
<xs:element minOccurs="0" maxOccurs="unbounded" ref="layerMaps" />
|
||||
<xs:element minOccurs="0" maxOccurs="unbounded" ref="transforms" />
|
||||
<xs:element minOccurs="0" maxOccurs="1" ref="reorders" />
|
||||
<xs:element minOccurs="0" maxOccurs="1" ref="backspaces" />
|
||||
<xs:element minOccurs="0" maxOccurs="unbounded" ref="special" />
|
||||
</xs:sequence>
|
||||
<xs:attribute name="locale" type="xs:string" use="required" />
|
||||
<xs:attribute name="conformsTo" use="required">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:NMTOKEN">
|
||||
<xs:enumeration value="techpreview" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:attribute>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="import">
|
||||
<xs:complexType>
|
||||
<xs:attribute name="path" type="xs:string" use="required" />
|
||||
<xs:attribute name="base">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:NMTOKEN">
|
||||
<xs:enumeration value="cldr" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:attribute>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="locales">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element minOccurs="0" maxOccurs="unbounded" ref="locale" />
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="locale">
|
||||
<xs:complexType>
|
||||
<xs:attribute name="id" type="xs:string" use="required" />
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="version">
|
||||
<xs:complexType>
|
||||
<xs:attribute name="number" type="xs:string" />
|
||||
<xs:attribute fixed="techpreview" name="cldrVersion" type="xs:string" />
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="info">
|
||||
<xs:complexType>
|
||||
<xs:attribute name="author" type="xs:string" />
|
||||
<xs:attribute name="normalization" type="xs:string" />
|
||||
<xs:attribute name="layout" type="xs:string" />
|
||||
<xs:attribute name="indicator" type="xs:string" />
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="names">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element minOccurs="0" maxOccurs="unbounded" ref="import" />
|
||||
<xs:element minOccurs="1" maxOccurs="unbounded" ref="name" />
|
||||
<xs:element minOccurs="0" maxOccurs="unbounded" ref="special" />
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="name">
|
||||
<xs:complexType>
|
||||
<xs:attribute name="value" type="xs:string" use="required" />
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="special">
|
||||
<xs:complexType mixed="true">
|
||||
<xs:sequence>
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##any" />
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="settings">
|
||||
<xs:complexType>
|
||||
<xs:attribute name="fallback">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:NMTOKEN">
|
||||
<xs:enumeration value="omit" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="transformFailure">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:NMTOKEN">
|
||||
<xs:enumeration value="omit" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="transformPartial">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:NMTOKEN">
|
||||
<xs:enumeration value="hide" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:attribute>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="vkeyMaps">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element minOccurs="0" maxOccurs="unbounded" ref="import" />
|
||||
<xs:element minOccurs="0" maxOccurs="unbounded" ref="vkeyMap" />
|
||||
<xs:element minOccurs="0" maxOccurs="unbounded" ref="special" />
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="vkeyMap">
|
||||
<xs:complexType>
|
||||
<xs:attribute name="from" type="xs:string" use="required" />
|
||||
<xs:attribute name="to" type="xs:string" use="required" />
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="displayMap">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element minOccurs="0" maxOccurs="unbounded" ref="import" />
|
||||
<xs:element minOccurs="0" maxOccurs="unbounded" ref="display" />
|
||||
<xs:element minOccurs="0" maxOccurs="unbounded" ref="displayOptions" />
|
||||
<xs:element minOccurs="0" maxOccurs="unbounded" ref="special" />
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="display">
|
||||
<xs:complexType>
|
||||
<xs:attribute name="to" type="xs:string" use="required" />
|
||||
<xs:attribute name="display" type="xs:string" use="required" />
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="displayOptions">
|
||||
<xs:complexType>
|
||||
<xs:attribute name="baseCharacter" type="xs:string" />
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="keys">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element minOccurs="0" maxOccurs="unbounded" ref="import" />
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element ref="key" />
|
||||
<xs:element ref="flicks" />
|
||||
</xs:choice>
|
||||
<xs:element minOccurs="0" maxOccurs="unbounded" ref="special" />
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="key">
|
||||
<xs:complexType>
|
||||
<xs:attribute name="id" type="xs:string" use="required" />
|
||||
<xs:attribute name="flicks" type="xs:NMTOKEN" />
|
||||
<xs:attribute name="gap">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:NMTOKEN">
|
||||
<xs:enumeration value="true" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="to" type="xs:string" />
|
||||
<xs:attribute name="longPress" type="xs:string" />
|
||||
<xs:attribute name="longPressDefault" type="xs:string" />
|
||||
<xs:attribute name="multitap" type="xs:string" />
|
||||
<xs:attribute name="switch" type="xs:NMTOKEN" />
|
||||
<xs:attribute name="transform">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:NMTOKEN">
|
||||
<xs:enumeration value="no" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="width" type="xs:string" />
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="flicks">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element minOccurs="1" maxOccurs="unbounded" ref="flick" />
|
||||
<xs:element minOccurs="0" maxOccurs="unbounded" ref="special" />
|
||||
</xs:sequence>
|
||||
<xs:attribute name="id" type="xs:NMTOKEN" use="required" />
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="flick">
|
||||
<xs:complexType>
|
||||
<xs:attribute name="directions" type="xs:NMTOKENS" use="required" />
|
||||
<xs:attribute name="to" type="xs:string" use="required" />
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="layerMaps">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element minOccurs="0" maxOccurs="unbounded" ref="import" />
|
||||
<xs:element minOccurs="0" maxOccurs="unbounded" ref="layerMap" />
|
||||
<xs:element minOccurs="0" maxOccurs="unbounded" ref="special" />
|
||||
</xs:sequence>
|
||||
<xs:attribute name="form" use="required">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:NMTOKEN">
|
||||
<xs:enumeration value="hardware" />
|
||||
<xs:enumeration value="touch" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="minDeviceWidthMM" type="xs:string" />
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="layerMap">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element minOccurs="1" maxOccurs="unbounded" ref="row" />
|
||||
<xs:element minOccurs="0" maxOccurs="unbounded" ref="special" />
|
||||
</xs:sequence>
|
||||
<xs:attribute name="id" type="xs:NMTOKEN" />
|
||||
<xs:attribute name="modifier" type="xs:NMTOKEN" />
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="row">
|
||||
<xs:complexType>
|
||||
<xs:attribute name="keys" type="xs:NMTOKENS" use="required" />
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="transforms">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element minOccurs="0" maxOccurs="unbounded" ref="import" />
|
||||
<xs:element minOccurs="0" maxOccurs="unbounded" ref="transform" />
|
||||
<xs:element minOccurs="0" maxOccurs="unbounded" ref="special" />
|
||||
</xs:sequence>
|
||||
<xs:attribute name="type" type="xs:string" use="required" />
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="transform">
|
||||
<xs:complexType>
|
||||
<xs:attribute name="before" type="xs:string" />
|
||||
<xs:attribute name="from" type="xs:string" use="required" />
|
||||
<xs:attribute name="to" type="xs:string" use="required" />
|
||||
<xs:attribute name="error">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:NMTOKEN">
|
||||
<xs:enumeration value="fail" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:attribute>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="reorders">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element minOccurs="0" maxOccurs="unbounded" ref="import" />
|
||||
<xs:element minOccurs="0" maxOccurs="unbounded" ref="reorder" />
|
||||
<xs:element minOccurs="0" maxOccurs="unbounded" ref="special" />
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="reorder">
|
||||
<xs:complexType>
|
||||
<xs:attribute name="before" type="xs:string" />
|
||||
<xs:attribute name="from" type="xs:string" use="required" />
|
||||
<xs:attribute name="order" type="xs:string" />
|
||||
<xs:attribute name="tertiary" type="xs:string" />
|
||||
<xs:attribute name="tertiary_base" type="xs:string" />
|
||||
<xs:attribute name="prebase" type="xs:string" />
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="backspaces">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element minOccurs="0" maxOccurs="unbounded" ref="import" />
|
||||
<xs:element minOccurs="0" maxOccurs="unbounded" ref="backspace" />
|
||||
<xs:element minOccurs="0" maxOccurs="unbounded" ref="special" />
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="backspace">
|
||||
<xs:complexType>
|
||||
<xs:attribute name="before" type="xs:string" />
|
||||
<xs:attribute name="from" type="xs:string" use="required" />
|
||||
<xs:attribute name="to" type="xs:string" />
|
||||
<xs:attribute name="error">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:NMTOKEN">
|
||||
<xs:enumeration value="fail" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:attribute>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:schema>
|
||||
Loading…
Add table
Reference in a new issue