diff --git a/package.json b/package.json index 31ad572ad994ae22ff0b852798a91c6d15b35d76..ae74e31e7843cfcee96df6862a932c6d13e567e9 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,8 @@ "test": "./node_modules/.bin/jest", "dist": "./node_modules/.bin/uglifyjs build/js/molio.dev.js -cm > dist/molio.js && cp build/js/molio.esm.js dist/molio.esm.js", "script": "./node_modules/.bin/rollup build/js/src/script.js -e fs -f cjs -o build/js/script.js", - "runscript": "npm run script && node build/js/script.js" + "runscript": "npm run script && node build/js/script.js", + "download-dics": "./node_modules/.bin/download -o build/dics http://mmcif.wwpdb.org/dictionaries/ascii/mmcif_pdbx_v50.dic && ./node_modules/.bin/download -o build/dics http://mmcif.wwpdb.org/dictionaries/ascii/mmcif_ddl.dic" }, "jest": { "moduleFileExtensions": [ @@ -29,7 +30,8 @@ "license": "MIT", "devDependencies": { "@types/jest": "^21.1.2", - "@types/node": "^8.0.32", + "@types/node": "^8.0.34", + "download-cli": "^1.0.5", "jest": "^21.2.1", "rollup": "^0.50.0", "rollup-plugin-buble": "^0.16.0", @@ -37,10 +39,11 @@ "rollup-plugin-json": "^2.3.0", "rollup-plugin-node-resolve": "^3.0.0", "rollup-watch": "^4.3.1", - "ts-jest": "^21.0.1", + "ts-jest": "^21.1.2", "tslint": "^5.7.0", "typescript": "^2.5.3", - "uglify-js": "^3.1.3" + "uglify-js": "^3.1.3", + "util.promisify": "^1.0.0" }, "dependencies": {} } diff --git a/src/reader/cif/schema/utils.ts b/src/reader/cif/schema/utils.ts index 42093d8391390b99cc3a7f6e5efb2161dd362af1..94d68bb2c7b464432cca2c374f2655f2e8fe2df7 100644 --- a/src/reader/cif/schema/utils.ts +++ b/src/reader/cif/schema/utils.ts @@ -1,6 +1,6 @@ // import dic from './dic' -import { Field, Category } from '../schema' +import { Field, Block, Category } from '../schema' import * as Data from '../data-model' const pooledStr = Field.pooledStr() @@ -8,7 +8,7 @@ const str = Field.str() const int = Field.int() const float = Field.float() -function getFieldType (type: string) { +export function getFieldType (type: string) { switch (type) { case 'code': case 'ucode': @@ -63,38 +63,102 @@ function getFieldType (type: string) { return str } +type SafeFrameCategories = { [category: string]: Data.SafeFrame } +type SafeFrameLinks = { [k: string]: string } + +interface SafeFrameData { + categories: SafeFrameCategories + links: SafeFrameLinks +} + +// get field from given or linked category +function getField ( category: string, field: string, d: Data.SafeFrame, ctx: SafeFrameData): Data.Field|undefined { + const { categories, links } = ctx + + const cat = d.categories[category] + if (cat) { + return cat.getField(field) + } else { + if (d.header in links) { + return getField(category, field, categories[links[d.header]], ctx) + } else { + // console.log(`no links found for '${d.header}'`) + } + } +} + +// function getEnums (d: Data.SafeFrame, ctx: SafeFrameData): string[]|undefined { +// const value = getField('_item_enumeration', 'value', d, ctx) +// if (value) { +// const enums: string[] = [] +// for (let i = 0; i < value.rowCount; ++i) { +// enums.push(value.str(i)) +// // console.log(value.str(i)) +// } +// return enums +// } else { +// // console.log(`item_enumeration.value not found for '${d.header}'`) +// } +// } + +function getCode (d: Data.SafeFrame, ctx: SafeFrameData): string|undefined { + const code = getField('_item_type', 'code', d, ctx) + if (code) { + let c = code.str(0) + // if (c === 'ucode') { + // const enums = getEnums(d, ctx) + // if (enums) c += `: ${enums.join('|')}` + // } + return c + } else { + console.log(`item_type.code not found for '${d.header}'`) + } +} + export function getSchema (dic: Data.Block) { // todo Block needs to be specialized with safe frames as well - const schema: { [category: string]: Category.Schema } = {} + const schema: Block.Schema = {} // { [category: string]: Category.Schema } = {} + const categories: SafeFrameCategories = {} + const links: SafeFrameLinks = {} dic.saveFrames.forEach(d => { - if (d.header[0] !== '_') { - schema[d.header] = {} - } else { - const categoryName = d.header.substring(1, d.header.indexOf('.')) - const itemName = d.header.substring(d.header.indexOf('.') + 1) - let fields - if (categoryName in schema) { - fields = schema[categoryName] - } else { - fields = {} - schema[categoryName] = fields - } - // console.log(util.inspect(d.categories, {showHidden: false, depth: 1})) - const item_type = d.categories['_item_type'] - if (item_type) { - const code = item_type.getField('code') - if (code) { - fields[itemName] = getFieldType(code.str(0)) - } else { - console.log(`item_type.code not found for '${d.header}'`) + if (d.header[0] !== '_') return + categories[d.header] = d + const item_linked = d.categories['_item_linked'] + if (item_linked) { + const child_name = item_linked.getField('child_name') + const parent_name = item_linked.getField('parent_name') + if (child_name && parent_name) { + for (let i = 0; i < item_linked.rowCount; ++i) { + const childName = child_name.str(i) + const parentName = parent_name.str(i) + if (childName in links && links[childName] !== parentName) { + console.log(`${childName} linked to ${links[childName]}, ignoring link to ${parentName}`) + } + links[childName] = parentName } - } else { - // TODO check for _item_linked.parent_name and use its type - console.log(`item_type not found for '${d.header}'`) } + } + }) + Object.keys(categories).forEach(fullName => { + const d = categories[fullName] + const categoryName = d.header.substring(1, d.header.indexOf('.')) + const itemName = d.header.substring(d.header.indexOf('.') + 1) + let fields + if (categoryName in schema) { + fields = schema[categoryName] + } else { + fields = {} + schema[categoryName] = fields + } + + const code = getCode(d, { categories, links }) + if (code) { + fields[itemName] = getFieldType(code) + } else { + console.log(`could not determine code for '${d.header}'`) } }) - return schema + return schema as Block.Instance<any> } diff --git a/src/script.ts b/src/script.ts index 06868a492c54fa9971cfd113a919448c5a9051f8..4f5615a1225f9a77ac08b37cb9e05e8c35f85840 100644 --- a/src/script.ts +++ b/src/script.ts @@ -8,9 +8,13 @@ import * as util from 'util' import * as fs from 'fs' +require('util.promisify').shim(); +const readFileAsync = util.promisify(fs.readFile); + import Gro from './reader/gro/parser' import CIF from './reader/cif/index' +import { apply as applySchema } from './reader/cif/schema' import { getSchema } from './reader/cif/schema/utils' const file = '1crn.gro' @@ -76,13 +80,9 @@ async function runGro(input: string) { console.log(residueNumber.length, residueNumber[0], residueNumber[residueNumber.length - 1]) } -export function _gro() { - fs.readFile(`./examples/${file}`, 'utf8', function (err, input) { - if (err) { - return console.log(err); - } - runGro(input) - }); +export async function _gro() { + const input = await readFileAsync(`./examples/${file}`, 'utf8') + runGro(input) } // _gro() @@ -108,35 +108,38 @@ async function runCIF(input: string | Uint8Array) { console.log(mmcif.atom_site.Cartn_x.value(0)); console.log(mmcif.entity.type.toArray()); console.log(mmcif.pdbx_struct_oper_list.matrix.value(0)); + + const schema = await _dic() + if (schema) { + const mmcif2 = applySchema(schema, data) + // console.log(util.inspect(mmcif2.atom_site, {showHidden: false, depth: 3})) + console.log(mmcif2.atom_site.Cartn_x.value(0)); + console.log(mmcif2.entity.type.toArray()); + // console.log(mmcif2.pdbx_struct_oper_list.matrix.value(0)); // TODO + } else { + console.log('error getting mmcif schema from dic') + } } -export function _cif() { +export async function _cif() { let path = `./examples/1cbs_updated.cif`; - path = '../test/3j3q.cif' // lets have a relative path for big test files - fs.readFile(path, 'utf8', function (err, input) { - if (err) { - return console.log(err); - } - console.log('------------------'); - console.log('Text CIF:'); - runCIF(input); - }); + // path = '../test/3j3q.cif' // lets have a relative path for big test files + const input = await readFileAsync(path, 'utf8') + console.log('------------------'); + console.log('Text CIF:'); + runCIF(input); path = `./examples/1cbs_full.bcif`; // const path = 'c:/test/quick/3j3q.cif'; - fs.readFile(path, function (err, input) { - if (err) { - return console.log(err); - } - console.log('------------------'); - console.log('BinaryCIF:'); - const data = new Uint8Array(input.byteLength); - for (let i = 0; i < input.byteLength; i++) data[i] = input[i]; - runCIF(input); - }); + const input2 = await readFileAsync(path) + console.log('------------------'); + console.log('BinaryCIF:'); + const data = new Uint8Array(input2.byteLength); + for (let i = 0; i < input2.byteLength; i++) data[i] = input2[i]; + runCIF(input2); } -// _cif(); +_cif(); async function runDic(input: string | Uint8Array) { console.time('parseDic'); @@ -151,23 +154,21 @@ async function runDic(input: string | Uint8Array) { } const schema = getSchema(parsed.result.blocks[0]) - // console.log(util.inspect(schema, {showHidden: false, depth: 1})) - console.log(util.inspect(Object.keys(schema).length, {showHidden: false, depth: 1})) + console.log(util.inspect(schema, {showHidden: false, depth: 3})) + // console.log(util.inspect(Object.keys(schema).length, {showHidden: false, depth: 1})) + + return schema } -export function _dic() { - let path = '../test/mmcif_pdbx_v50.dic' - fs.readFile(path, 'utf8', function (err, input) { - if (err) { - return console.log(err); - } - console.log('------------------'); - console.log('Text DIC:'); - runDic(input); - }); +export async function _dic() { + let path = './build/dics/mmcif_pdbx_v50.dic' + const input = await readFileAsync(path, 'utf8') + console.log('------------------'); + console.log('Text DIC:'); + return runDic(input); } -_dic(); +// _dic(); import Computation from './utils/computation' const comp = Computation.create(async ctx => {