|
@@ -20,14 +20,11 @@ import * as Data from './data'
|
|
|
*
|
|
|
* const mmCIF = { atom_site };
|
|
|
*/
|
|
|
-export type BlockDefinition = { [category: string]: CategoryDefinition }
|
|
|
-export type CategoryDefinition = { '@alias'?: string } & { [field: string]: Field.Schema<any> }
|
|
|
|
|
|
-export type BlockInstance<Definition extends BlockDefinition> = Block<{ [C in keyof Definition]: CategoryInstance<Definition[C]> }>
|
|
|
-export type CategoryInstance<Definition extends CategoryDefinition> = Category<{ [F in keyof Definition]: Field<Definition[F]['type']> }>
|
|
|
+//////////////////////////////////////////////
|
|
|
|
|
|
-export function apply<Definition extends BlockDefinition>(schema: Definition, block: Data.Block): BlockInstance<Definition> {
|
|
|
- return createBlock(schema, block) as BlockInstance<Definition>;
|
|
|
+export function apply<Schema extends Block.Schema>(schema: Schema, block: Data.Block): Block.Instance<Schema> {
|
|
|
+ return createBlock(schema, block) as Block.Instance<Schema>;
|
|
|
}
|
|
|
|
|
|
export type Block<Categories> = Categories & {
|
|
@@ -36,12 +33,22 @@ export type Block<Categories> = Categories & {
|
|
|
_getCategory(name: string): Data.Category | undefined
|
|
|
}
|
|
|
|
|
|
+export namespace Block {
|
|
|
+ export type Schema = { [category: string]: Category.Schema }
|
|
|
+ export type Instance<T extends Schema> = Block<{ [C in keyof T]: Category.Instance<T[C]> }>
|
|
|
+}
|
|
|
+
|
|
|
export type Category<Fields> = Fields & {
|
|
|
readonly _rowCount: number,
|
|
|
/** For accessing 'non-standard' fields */
|
|
|
_getField(name: string): Data.Field | undefined
|
|
|
}
|
|
|
|
|
|
+export namespace Category {
|
|
|
+ export type Schema = { '@alias'?: string } & { [field: string]: Field.Schema<any> }
|
|
|
+ export type Instance<T extends Schema> = Category<{ [F in keyof T]: Field<T[F]['type']> }>
|
|
|
+}
|
|
|
+
|
|
|
export interface Field<T> {
|
|
|
readonly isDefined: boolean,
|
|
|
value(row: number): T,
|
|
@@ -53,6 +60,13 @@ export interface Field<T> {
|
|
|
}
|
|
|
|
|
|
export namespace Field {
|
|
|
+ export interface Schema<T> { type: T, ctor: (field: Data.Field) => Field<T>, undefinedField: Data.Field, alias?: string };
|
|
|
+ export interface Spec { undefinedField?: Data.Field, alias?: string }
|
|
|
+
|
|
|
+ export function str(spec?: Spec) { return createSchema(spec, Str); }
|
|
|
+ export function int(spec?: Spec) { return createSchema(spec, Int); }
|
|
|
+ export function float(spec?: Spec) { return createSchema(spec, Float); }
|
|
|
+
|
|
|
function create<T>(field: Data.Field, value: (row: number) => T, toArray: Field<T>['toArray']): Field<T> {
|
|
|
return { isDefined: field.isDefined, value, presence: field.presence, areValuesEqual: field.areValuesEqual, stringEquals: field.stringEquals, toArray };
|
|
|
}
|
|
@@ -60,14 +74,13 @@ export namespace Field {
|
|
|
function Str(field: Data.Field) { return create(field, field.str, field.toStringArray); }
|
|
|
function Int(field: Data.Field) { return create(field, field.int, field.toNumberArray); }
|
|
|
function Float(field: Data.Field) { return create(field, field.float, field.toNumberArray); }
|
|
|
- function Bin(field: Data.Field) { return create(field, field.bin, (s, e, ctor) => void 0); }
|
|
|
|
|
|
const DefaultUndefined: Data.Field = {
|
|
|
isDefined: false,
|
|
|
str: row => null,
|
|
|
int: row => 0,
|
|
|
float: row => 0,
|
|
|
- bin: row => null,
|
|
|
+ value: row => null,
|
|
|
|
|
|
presence: row => Data.ValuePresence.NotSpecified,
|
|
|
areValuesEqual: (rowA, rowB) => true,
|
|
@@ -82,23 +95,15 @@ export namespace Field {
|
|
|
toNumberArray: (startRow, endRowExclusive, ctor) => new Uint8Array(endRowExclusive - startRow) as any
|
|
|
};
|
|
|
|
|
|
- export interface Schema<T> { type: T, ctor: (field: Data.Field) => Field<T>, undefinedField: Data.Field, alias?: string };
|
|
|
- export interface Spec { undefinedField?: Data.Field, alias?: string }
|
|
|
-
|
|
|
function createSchema<T>(spec: Spec | undefined, ctor: (field: Data.Field) => Field<T>): Schema<T> {
|
|
|
return { type: 0 as any, ctor, undefinedField: (spec && spec.undefinedField) || DefaultUndefined, alias: spec && spec.alias };
|
|
|
}
|
|
|
-
|
|
|
- export function str(spec?: Spec) { return createSchema(spec, Str); }
|
|
|
- export function int(spec?: Spec) { return createSchema(spec, Int); }
|
|
|
- export function float(spec?: Spec) { return createSchema(spec, Float); }
|
|
|
- export function bin(spec?: Spec) { return createSchema(spec, Bin); }
|
|
|
}
|
|
|
|
|
|
class _Block implements Block<any> { // tslint:disable-line:class-name
|
|
|
header = this._block.header;
|
|
|
getCategory(name: string) { return this._block.categories[name]; }
|
|
|
- constructor(private _block: Data.Block, schema: BlockDefinition) {
|
|
|
+ constructor(private _block: Data.Block, schema: Block.Schema) {
|
|
|
for (const k of Object.keys(schema)) {
|
|
|
Object.defineProperty(this, k, { value: createCategory(k, schema[k], _block), enumerable: true, writable: false, configurable: false });
|
|
|
}
|
|
@@ -108,7 +113,7 @@ class _Block implements Block<any> { // tslint:disable-line:class-name
|
|
|
class _Category implements Category<any> { // tslint:disable-line:class-name
|
|
|
_rowCount = this._category.rowCount;
|
|
|
_getField(name: string) { return this._category.getField(name); }
|
|
|
- constructor(private _category: Data.Category, schema: CategoryDefinition) {
|
|
|
+ constructor(private _category: Data.Category, schema: Category.Schema) {
|
|
|
const fieldKeys = Object.keys(schema).filter(k => k !== '@alias');
|
|
|
const cache = Object.create(null);
|
|
|
for (const k of fieldKeys) {
|
|
@@ -127,11 +132,11 @@ class _Category implements Category<any> { // tslint:disable-line:class-name
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-function createBlock(schema: BlockDefinition, block: Data.Block): any {
|
|
|
+function createBlock(schema: Block.Schema, block: Data.Block): any {
|
|
|
return new _Block(block, schema);
|
|
|
}
|
|
|
|
|
|
-function createCategory(key: string, schema: CategoryDefinition, block: Data.Block) {
|
|
|
+function createCategory(key: string, schema: Category.Schema, block: Data.Block) {
|
|
|
const cat = block.categories[schema['@alias'] || key] || Data.Category.Empty;
|
|
|
return new _Category(cat, schema);
|
|
|
}
|