frictionless-ckan-mapper-js
Version:
This is JS version of [Frictionless CKAN Mapper](https://github.com/frictionlessdata/frictionless-ckan-mapper).
193 lines (171 loc) • 5 kB
JavaScript
/**
*
* Any key not in this list is passed as is inside "extras".
* Further processing will happen for possible matchings, e.g.
* contributor <=> author
* */
const ckanPackageKeys = [
'author',
'author_email',
'creator_user_id',
'groups',
'id',
'license_id',
'license_title',
'license_url',
'maintainer',
'maintainer_email',
'metadata_created',
'metadata_modified',
'name',
'notes',
'owner_org',
'private',
'relationships_as_object',
'relationships_as_subject',
'revision_id',
'resources',
'state',
'tags',
'tracking_summary',
'title',
'type',
'url',
'version',
]
const resourceMapping = {
bytes: 'size',
mediatype: 'mimetype',
path: 'url',
}
const packageMapping = {
description: 'notes',
homepage: 'url',
}
const frictionlessPackageKeysToExclude = ['extras']
/**
* Checks if there is a mapping for resource returns the new key
* otherwise return the same input
* @param {string} key
*/
const getResourceMapping = (key) => {
const newKey = resourceMapping[key]
if (newKey) return newKey
return key
}
/**
* Checks if there is a mapping for package returns the new key
* otherwise return the same input
* @param {string} key
*/
const getPackageMapping = (key) => {
const newKey = packageMapping[key]
if (newKey) return newKey
return key
}
/**
* Converts the Frictionless resource to a CKAN package (dataset)
* @param {Object} frictionlessResource
*/
const resourceFrictionlessToCkan = (frictionlessResource) => {
const newResource = {}
Object.entries(frictionlessResource).map(([key, value]) => {
// get the mapping is applicable
const newKey = getResourceMapping(key)
newResource[newKey] = value
})
return newResource
}
/**
* Converts the Frictionless package to a CKAN package (dataset)
* @param {Object} frictionlessPackage
*/
const packageFrictionlessToCkan = (frictionlessPackage) => {
const ckanPackage = {}
Object.entries(frictionlessPackage).map(([key, value]) => {
// Map resources inside dataset
if (key === 'resources') {
return (ckanPackage.resources = value.map((resource) => {
return resourceFrictionlessToCkan(resource)
}))
}
if (key === 'licenses' && value && value.length) {
const { title, path, name } = value[0]
if (title) ckanPackage.license_title = title
if (path) ckanPackage.license_url = path
if (name) ckanPackage.license_id = name
// Skip licenses array so it won't get put in extras
if (value.length === 1) return
}
const contributors = value
if (key === 'contributors' && contributors && contributors.length) {
// find the author and maintainer
for (let contrib of contributors) {
const { title, email, role } = contrib
if (!role || role === 'author') {
ckanPackage.author = title
ckanPackage.author_email = email
break
}
}
for (let contrib of contributors) {
const { title, email, role } = contrib
if (role === 'maintainer') {
ckanPackage.maintainer = title
ckanPackage.maintainer_email = email
break
}
}
/**
* we skip contributors where we have extracted everything into
* ckan core that way it won't end up in extras
* this helps ensure that round tripping with ckan is good
* when have we extracted everything?
* if contributors has length 1 and role in author or maintainer
* or contributors == 2 and no of authors and maintainer types <= 1
*/
if (contributors) {
if (
contributors.length === 1 &&
(!contributors[0].role ||
contributors[0].role === 'author' ||
contributors[0].role === 'maintainer')
)
return
if (contributors.length === 2) {
let authorsCount = 0
let maintainersCount = 0
contributors.map((contributor) => {
const { role } = contributor
if (role === 'authors') authorsCount++
if (role === 'maintainer') maintainersCount++
})
if (authorsCount < 2 && maintainersCount < 2) return
}
}
}
// Map keywords to tags
if (key == 'keywords') {
return (ckanPackage.tags = value.map((keyword) => {
return { name: keyword }
}))
}
// get the mapping if applicable
const newKey = getPackageMapping(key)
// Creating extras. If it is not ckan key and neither excluded frictionless key
if (
ckanPackageKeys.indexOf(newKey) < 0 &&
frictionlessPackageKeysToExclude.indexOf(newKey) < 0
) {
ckanPackage.extras = ckanPackage.extras || []
if (typeof value === 'object') value = JSON.stringify(value)
return ckanPackage.extras.push({ key, value })
}
ckanPackage[newKey] = value
})
return ckanPackage
}
module.exports = {
packageFrictionlessToCkan,
resourceFrictionlessToCkan,
}