diff --git a/src/reader/cif/schema/utils.ts b/src/reader/cif/schema/utils.ts index 42093d8391390b99cc3a7f6e5efb2161dd362af1..250d5e91a751203e5d88cdb88fc93fa046dcd53a 100644 --- a/src/reader/cif/schema/utils.ts +++ b/src/reader/cif/schema/utils.ts @@ -63,38 +63,87 @@ function getFieldType (type: string) { return str } +type SafeFrameCategories = { [category: string]: Data.SafeFrame } +type SafeFrameLinks = { [k: string]: string } + +interface SafeFrameData { + categories: SafeFrameCategories + links: SafeFrameLinks +} + +function getCode (d: Data.SafeFrame, ctx: SafeFrameData): string|undefined { + const { categories, links } = ctx + + const item_type = d.categories['_item_type'] + if (item_type) { + const code = item_type.getField('code') + if (code) { + return code.str(0) + } else { + console.log(`item_type.code not found for '${d.header}'`) + } + } else { + if (d.header in links) { + return getCode(categories[links[d.header]], ctx) + } else { + console.log(`no links 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 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(categoryName => { + const d = categories[categoryName] + 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 } + +// TODO +// support controlled vocabulary as a specialization string type field +// in the example below the string type would be `Y|N` +// _item_type.code ucode + // loop_ + // _item_enumeration.value + // _item_enumeration.detail + // Y 'Yes' + // N 'No' diff --git a/src/script.ts b/src/script.ts index 06868a492c54fa9971cfd113a919448c5a9051f8..19fc04183f74cfe2984fb85323d7490e4a413d67 100644 --- a/src/script.ts +++ b/src/script.ts @@ -156,7 +156,7 @@ async function runDic(input: string | Uint8Array) { } export function _dic() { - let path = '../test/mmcif_pdbx_v50.dic' + let path = './build/dics/mmcif_pdbx_v50.dic' fs.readFile(path, 'utf8', function (err, input) { if (err) { return console.log(err);