js/topology/registry/loaders/load_packages.js
// NPM IMPORTS
import assert from 'assert'
import path from 'path'
import _ from 'lodash'
// COMMON IMPORTS
import T from '../../../utils/types'
import attr_iter from '../../../utils/attributes_iterator'
import parser from '../../../utils/parser/parser'
const context = 'common/topology/registry/loaders/load_packages'
let error_msg_bad_config = context + ':bad config'
let error_msg_bad_base_dir = context + ':package.base_dir should be a string'
let error_msg_bad_resources = context + ':package.resources should be an array'
let error_msg_bad_templates = context + ':package.templates should be an array'
let error_msg_bad_includes = context + ':package.includes should be an array'
let error_msg_bad_service = context + ':package.services.* should be an object'
let error_msg_bad_resource = context + ':package.resources.* should be a string'
let error_msg_bad_template = context + ':package.templates.* should be a string'
let error_msg_bad_include = context + ':package.includes.* should be a string'
let error_msg_bad_package_config = context + ':bad package config'
let error_msg_bad_resource_config = context + ':bad resource config'
function load_packages(logs, arg_packages_config, arg_base_dir)
{
logs.info(context, 'loading world...packages')
try{
// CHECK PACKAGES
assert(T.isObject(arg_packages_config), error_msg_bad_config)
// LOOP ON PACKAGES
let files = {}
const load_one_package_fn = (package_name, package_obj, package_dir)=>{
// BAD FORMAT
if ( ! T.isObject(package_obj) )
{
throw 'error in packages.' + package_name + ':bad format, not a file name nor an object'
}
arg_packages_config[package_name] = load_package(logs, package_name, package_obj, package_dir, files)
// console.log(package_obj, 'package_obj')
// PROCESS ERRORS
if (package_obj.commands && package_obj.commands.error)
{
throw 'error in packages.' + package_name + '.commands:' + package_obj.commands.error
}
if (package_obj.services && package_obj.services.error)
{
throw 'error in packages.' + package_name + '.services:' + package_obj.services.error
}
if (package_obj.datasources && package_obj.datasources.error)
{
throw 'error in packages.' + package_name + '.datasources:' + package_obj.datasources.error
}
if (package_obj.models && package_obj.models.error)
{
throw 'error in packages.' + package_name + '.models:' + package_obj.models.error
}
if (package_obj.views && package_obj.views.error)
{
throw 'error in packages.' + package_name + '.views:' + package_obj.views.error
}
if (package_obj.menus && package_obj.menus.error)
{
throw 'error in packages.' + package_name + '.menus:' + package_obj.menus.error
}
if (package_obj.menubars && package_obj.menubars.error)
{
throw 'error in packages.' + package_name + '.menubars:' + package_obj.menubars.error
}
}
Object.keys(arg_packages_config).forEach(
function(arg_package_name)
{
if (arg_package_name == 'files')
{
return
}
logs.info(context, 'loading world...packages.' + arg_package_name)
let package_obj = arg_packages_config[arg_package_name]
// LOAD A FILE NAME
if ( T.isString(package_obj) )
{
const pkg_name = package_obj
const file_path_name = path.join(arg_base_dir, pkg_name)
package_obj = require(file_path_name).packages
const pkg_dir = path.dirname(file_path_name)
// DEBUG
logs.info(context + ':file=[%s] package_obj:', file_path_name, package_obj)
Object.keys(package_obj).forEach(
function(arg_sub_name)
{
const sub_pkg = package_obj[arg_sub_name]
load_one_package_fn(arg_sub_name, sub_pkg, pkg_dir)
}
)
return
}
// BAD FORMAT
if ( ! T.isObject(package_obj) )
{
throw 'error in packages.' + arg_package_name + ':bad format, not a file name nor an object'
}
load_one_package_fn(arg_package_name, package_obj, arg_base_dir)
}
)
// CACHE FILES CONTENT
// arg_packages_config.files = files
}
catch(e)
{
arg_packages_config = { error: { context:context, exception:e, error_msg:e.toString() } }
// console.error(context, arg_packages_config)
}
return arg_packages_config
}
function load_package(logs, arg_package_name, arg_package_config, arg_base_dir, files)
{
logs.info(context, 'loading world...packages.' + arg_package_name + ':BEGIN')
// CHECK PACKAGES
assert(T.isObject(arg_package_config), error_msg_bad_config)
arg_package_config.base_dir = arg_package_config.base_dir ? arg_package_config.base_dir : ''
arg_package_config.commands = arg_package_config.commands ? arg_package_config.commands : {}
arg_package_config.services = arg_package_config.services ? arg_package_config.services : {}
arg_package_config.resources = arg_package_config.resources ? arg_package_config.resources : {}
arg_package_config.templates = arg_package_config.templates ? arg_package_config.templates : {}
arg_package_config.includes = arg_package_config.includes ? arg_package_config.includes : {}
// LOAD COMMANDS
if (T.isString(arg_package_config.commands))
{
logs.info(context, 'loading world...packages.' + arg_package_name + '.commands is a string')
const absolute_path_name = path.join(arg_base_dir, arg_package_config.base_dir, arg_package_config.commands)
arg_package_config.commands = parser.read(absolute_path_name, 'utf8').commands
// const file_path_name = path.join(arg_base_dir, arg_package_config.commands)
// arg_package_config.commands = require(file_path_name).commands
}
// console.log( Object.keys(arg_package_config.commands), 'arg_package_config.commands for ' + arg_package_name)
// LOAD SERVICES
if (T.isString(arg_package_config.services))
{
logs.info(context, 'loading world...packages.' + arg_package_name + '.services is a string')
const absolute_path_name = path.join(arg_base_dir, arg_package_config.base_dir, arg_package_config.services)
arg_package_config.services = parser.read(absolute_path_name, 'utf8').services
// const file_path_name = path.join(arg_base_dir, arg_package_config.services)
// arg_package_config.services = require(file_path_name).services
}
if ( T.isObject(arg_package_config.services) )
{
logs.info(context, 'loading world...packages.' + arg_package_name + '.services is now an object')
// load_services(arg_package_config.services)
}
// console.log( Object.keys(arg_package_config.services), 'arg_package_config.services for ' + arg_package_name)
// CHECK ATTRIBUTES
assert(T.isString(arg_package_config.base_dir), error_msg_bad_base_dir + ' for package ' + arg_package_name)
assert(T.isArray(arg_package_config.resources), error_msg_bad_resources + ' for package ' + arg_package_name)
assert(T.isArray(arg_package_config.templates), error_msg_bad_templates + ' for package ' + arg_package_name)
assert(T.isArray(arg_package_config.includes), error_msg_bad_includes + ' for package ' + arg_package_name)
// CHECK ATTRIBUTES ITEMS
arg_package_config.resources.forEach( (resource) => { assert(T.isString(resource), error_msg_bad_resource) } )
arg_package_config.templates.forEach( (template) => { assert(T.isString(template), error_msg_bad_template) } )
arg_package_config.includes.forEach( (include) => { assert(T.isString(include), error_msg_bad_include) } )
// INIT RESOURCES REPOSITORY
arg_package_config.resources_by_name = {}
arg_package_config.resources_by_type = {}
arg_package_config.resources_by_file = {}
arg_package_config.resources_by_type.templates = {}
arg_package_config.resources_by_type.views = {}
arg_package_config.resources_by_type.models = {}
arg_package_config.resources_by_type.menubars = {}
arg_package_config.resources_by_type.menus = {}
arg_package_config.resources_by_type.datasources = {}
arg_package_config.resources_by_type.services = {}
arg_package_config.resources_by_type.commands = {}
arg_package_config.views = {}
arg_package_config.models = {}
arg_package_config.menubars = {}
arg_package_config.menus = {}
arg_package_config.datasources = {}
// REGISTER SERVICES AS RESOURCES
Object.keys(arg_package_config.services).forEach(
(svc_name) => {
const svc = arg_package_config.services[svc_name]
assert(T.isObject(svc), error_msg_bad_service)
logs.info(context, 'loading world...packages.' + arg_package_name + '.services.' + svc_name + ' is registered')
// REGISTER BASE DIRECTORIES
svc.app_base_dir = arg_base_dir
svc.pkg_base_dir = arg_package_config.base_dir
arg_package_config.resources_by_name[svc_name] = svc
arg_package_config.resources_by_type['services'][svc_name] = svc
}
)
// REGISTER COMMANDS AS RESOURCES
Object.keys(arg_package_config.commands).forEach(
(cmd_name) => {
const cmd = arg_package_config.commands[cmd_name]
assert(T.isObject(cmd), error_msg_bad_service)
logs.info(context, 'loading world...packages.' + arg_package_name + '.commands.' + cmd_name + ' is registered')
arg_package_config.resources_by_name[cmd_name] = cmd
arg_package_config.resources_by_type['commands'][cmd_name] = cmd
}
)
// LOAD TEMPLATES
const templates = arg_package_config.templates
templates.forEach(
(template_file) => {
logs.info(context, 'loading world...packages.' + arg_package_name + ' arg_base_dir:' + arg_base_dir)
logs.info(context, 'loading world...packages.' + arg_package_name + ' templates file:' + template_file)
logs.info(context, 'loading world...packages.' + arg_package_name + ' arg_package_config.base_dir:' + arg_package_config.base_dir)
if ( ! T.isNotEmptyString(template_file) )
{
return
}
let relative_path_name = T.isNotEmptyString(arg_package_config.base_dir) ? path.join(arg_package_config.base_dir, template_file) : template_file
logs.info(context, 'loading world...packages.' + arg_package_name + ' relative_path_name:' + relative_path_name)
let absolute_path_name = path.join(arg_base_dir , relative_path_name)
let config = parser.read(absolute_path_name, 'utf8')
// console.log(config, 'config')
// GET TEMPLATES
if (! config.templates )
{
return
}
config = config.templates
files[relative_path_name] = config
arg_package_config.resources_by_file[relative_path_name] = {}
// CHECK package
assert(T.isObject(config), error_msg_bad_package_config + ' for file ' + template_file)
const types = ['views', 'models', 'menubars', 'menus', 'datasources']
types.forEach(
(type_name)=>{
logs.info(context, 'loading begin world...packages.' + arg_package_name + ' templates file:' + template_file + ' of type:' + type_name)
if ( config[type_name] && T.isObject(config[type_name]) )
{
load_package_template(logs, arg_package_name, arg_package_config, config[type_name], type_name, relative_path_name)
}
logs.info(context, 'loading end world...packages.' + arg_package_name + ' templates file:' + template_file + ' of type:' + type_name)
}
)
}
)
// LOAD RESOURCES
const resources = arg_package_config.resources
resources.forEach(
(resource_file) => {
logs.info(context, 'loading world...packages.' + arg_package_name + ' resources file:' + resource_file)
let relative_path_name = path.join(arg_package_config.base_dir, resource_file)
let absolute_path_name = path.join(arg_base_dir , relative_path_name)
let config = parser.read(absolute_path_name, 'utf8')
// console.log(config, 'config')
files[relative_path_name] = config
arg_package_config.resources_by_file[relative_path_name] = {}
// CHECK package
assert(T.isObject(config), error_msg_bad_package_config + ' for file ' + resource_file)
const types = ['views', 'models', 'menubars', 'menus', 'datasources']
types.forEach(
(type_name)=>{
logs.info(context, 'loading world...packages.' + arg_package_name + ' resources file:' + resource_file + ' of type:' + type_name)
if ( config[type_name] && T.isObject(config[type_name]) )
{
load_package_children(logs, arg_package_name, arg_package_config, config[type_name], type_name, relative_path_name)
}
}
)
}
)
logs.info(context, 'loading world...packages.' + arg_package_name + ':END')
return arg_package_config
}
function load_package_children(logs, arg_package_name, arg_package_config, arg_children, type_name, relative_path_name)
{
Object.keys(arg_children).forEach(
(res_name) => {
logs.debug(context, 'loading world...packages.' + arg_package_name + ' resource children for ' + res_name)
let res_obj = arg_children[res_name]
// DEBUG
// console.log('load_package_children:res_obj=', JSON.stringify(res_obj) )
// TEMPLATE
if ( T.isNotEmptyString(res_obj.template) )
{
// console.log('load_package_children:res_obj=', JSON.stringify(res_obj) )
const template_name = res_obj.template
const template_resource = arg_package_config.templates[template_name]
assert(T.isObject(template_resource), error_msg_bad_resource_config + ' for ' + res_name + ' with template ' + template_name)
const template_clone = _.clone(template_resource)
const res_clone = _.clone(res_obj)
res_obj = _.merge(template_clone, res_clone)
const xform_fn = (v)=>{
if ( T.isNotEmptyString(v) )
{
return v.replace('{{devapt-template-id}}', res_name)
}
return v
}
res_obj = attr_iter(res_obj, xform_fn)
arg_children[res_name] = res_obj
// DEBUG
// console.log(context + ':load_package_children:' + arg_package_name + ' resource [%s] of collection [%s] from template [%s]:', res_name, type_name, template_name, res_obj)
// if (res_obj && res_obj.state && res_obj.state.space)
// {
// console.log(context + ':load_package_children:' + arg_package_name + ' resource [%s] of collection [%s] from template [%s]', res_name, type_name, template_name)
// console.log(context + ':load_package_children:' + arg_package_name + ':source=')
// console.log(res_clone.state.space)
// console.log(context + ':load_package_children:' + arg_package_name + ':template=')
// console.log(template_clone.state.space)
// console.log(context + ':load_package_children:' + arg_package_name + ':merge=')
// console.log(res_obj.state.space)
// }
}
// GET RESOURCE TYPE
if (type_name !== 'menus' && type_name !== 'models')
{
res_obj.class_name = res_obj.class_name ? res_obj.class_name : res_obj.type
assert(T.isString(res_obj.class_name), error_msg_bad_resource_config + ' for resource ' + res_name)
}
res_obj.collection = type_name
res_obj.name = res_name
arg_package_config.resources_by_name[res_name] = res_obj
arg_package_config.resources_by_type[type_name][res_name] = res_obj
arg_package_config.resources_by_file[relative_path_name][res_name] = res_obj
arg_package_config[type_name][res_name] = res_obj
if ( T.isObject(res_obj.children) )
{
load_package_children(logs, arg_package_name, arg_package_config, res_obj.children, type_name, relative_path_name)
}
}
)
}
function load_package_template(logs, arg_package_name, arg_package_config, arg_children, type_name, relative_path_name)
{
Object.keys(arg_children).forEach(
(res_name) => {
logs.debug(context, 'loading begin world...packages.' + arg_package_name + ' resource template for ' + res_name)
let res_obj = arg_children[res_name]
// DEBUG
// console.log('load_package_template:res_obj=', JSON.stringify(res_obj.state) )
// TEMPLATE
if ( T.isNotEmptyString(res_obj.template) )
{
const template_name = res_obj.template
let template_resource = arg_package_config.templates[template_name]
if (! template_resource)
{
template_resource = arg_children[template_name]
}
if (! template_resource)
{
console.error(context + ':load_package_template:package=[' + arg_package_name + '] resource=[' + res_name + ']: template not found for [' + template_name + ']')
}
assert(T.isObject(template_resource), error_msg_bad_resource_config + ' for ' + res_name + ' with template ' + template_name)
const template_clone = _.clone(template_resource)
const res_clone = _.clone(res_obj)
res_obj = _.merge(template_clone, res_clone)
// DEBUG
// console.log(context + ':load_package_template world...packages.' + arg_package_name + ' resource [%s] of collection [%s] from template [%s] src[%o] template[%o] merg[%o]:', res_name, type_name, template_name, tmp, clone, res_obj)
// if (res_obj && res_obj.state && res_obj.state.space)
// {
// console.log(context + ':load_package_template world...packages.' + arg_package_name + ' resource [%s] of collection [%s] from template [%s]', res_name, type_name, template_name)
// console.log(context + ':load_package_template world...packages.' + arg_package_name + ':source=')
// console.log(res_clone.state.space)
// console.log(context + ':load_package_template world...packages.' + arg_package_name + ':template=')
// console.log(template_clone.state.space)
// console.log(context + ':load_package_template world...packages.' + arg_package_name + ':merge=')
// console.log(res_obj.state.space)
// }
}
if (type_name !== 'menus' && type_name !== 'models')
{
res_obj.class_name = res_obj.class_name ? res_obj.class_name : res_obj.type
assert(T.isString(res_obj.class_name), error_msg_bad_resource_config + ' for resource ' + res_name)
}
res_obj.collection = type_name
res_obj.name = res_name
// console.log('arg_package_config.templates', arg_package_config.templates)
// console.log('arg_package_config.resources_by_type.templates', arg_package_config.resources_by_type.templates)
// console.log('arg_package_config.resources_by_file[relative_path_name]', arg_package_config.resources_by_file[relative_path_name])
arg_package_config.resources_by_type.templates[res_name] = res_obj
arg_package_config.resources_by_file[relative_path_name][res_name] = res_obj
arg_package_config.templates[res_name] = res_obj
// if ( T.isObject(res_obj.children) )
// {
// load_package_template(logs, arg_package_name, arg_package_config, res_obj.children, type_name, relative_path_name)
// }
logs.debug(context, 'loading end world...packages.' + arg_package_name + ' resource template for ' + res_name)
}
)
}
export default load_packages