UNPKG

@carlosv2/glue

Version:

Dependency injection library that stays out of the way

218 lines (217 loc) 10.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Processor = void 0; const index_1 = require("./context/index"); const error_1 = require("./error"); const service_1 = require("./error/service"); const utils_1 = require("./utils"); class Processor { fromPaths(pattern) { let fullPattern = pattern; if (!fullPattern.startsWith('/')) { const base = (0, utils_1.getCallerFile)(); if (!base) { throw new error_1.DiError('The caller file could not be determined'); } fullPattern = this.getFullPath(base, pattern); } this.glob(fullPattern).forEach(this.fromPath.bind(this)); } fromPath(path) { this.fromContent(path, this.readContents(path)); } fromContent(path, content) { this.fromData(path, this.deserialise(path, content)); } fromData(path, content) { if (!(0, utils_1.isDictionary)(content)) { throw new error_1.DiError(`The contents of the path \`${path}\` must represent an object`); } if ((0, utils_1.has)('extends', content)) { if (!(0, utils_1.isArray)(content['extends'])) { throw new error_1.DiError(`The extends section in the path \`${path}\` must represent an array`); } const context = new index_1.DefinitionContext(path, 'ignore', 'ignore'); content['extends'].forEach(extension => { if (!(0, utils_1.isString)(extension)) { throw new error_1.DiError(`Each extended file must add as an string in the path \`${path}\``); } this.addExtend(this.getFullPath(context.getPath(), extension)); }); } if ((0, utils_1.has)('parameters', content)) { if (!(0, utils_1.isDictionary)(content['parameters'])) { throw new error_1.DiError(`The parameters section in the path \`${path}\` must represent an object`); } Object.entries(content['parameters']).forEach(([id, value]) => { const definition = this.serialise(path, value); const context = new index_1.DefinitionContext(path, id, definition); this.addParameter(id, this.parseValue(context, value)); }); } if ((0, utils_1.has)('services', content)) { if (!(0, utils_1.isDictionary)(content['services'])) { throw new error_1.DiError(`The services section in the path \`${path}\` must represent an object`); } Object.entries(content['services']).forEach(([id, value]) => { const definition = this.serialise(path, value); const context = new index_1.DefinitionContext(path, id, definition); if ((0, utils_1.isString)(value)) { this.addAlias(id, this.parseAlias(context, value)); } else { this.addService(id, this.parseService(context, value)); } }); } } parseValue(context, value) { if ((0, utils_1.isArray)(value)) { return this.processLiteralValue(context, value.map(item => this.parseValue(context, item))); } if ((0, utils_1.isDictionary)(value)) { if ((0, utils_1.has)('symbol', value)) { return this.parseService(context, value); } if ((0, utils_1.has)('_symbol', value)) { value['symbol'] = value['_symbol']; } return this.processLiteralValue(context, Object.fromEntries(Object.entries(value).map(([key, item]) => [ key, this.parseValue(context, item), ]))); } if ((0, utils_1.isString)(value)) { if ((0, utils_1.isFirstChar)(value, '<')) { return this.processServiceValue(context, value.substring(1)); } else if ((0, utils_1.isFirstChar)(value, '$')) { return this.processParameterValue(context, value.substring(1)); } else if ((0, utils_1.isFirstChar)(value, '>')) { return this.processTagListValue(context, value.substring(1)); } else if ((0, utils_1.isFirstChar)(value, '}')) { return this.processTagObjectValue(context, value.substring(1)); } else if ((0, utils_1.isFirstChar)(value, '%')) { const [name, declaredType, ...values] = value.substring(1).split('/'); const type = declaredType !== null && declaredType !== void 0 ? declaredType : 's'; const fallback = values.length > 0 ? values.join('/') : undefined; if (type === 's') { return this.processEnvStrValue(context, name, fallback); } else if (type === 'b') { return this.processEnvBoolValue(context, name, fallback); } else if (type === 'n') { return this.processEnvNumValue(context, name, fallback); } else { throw new error_1.DiError('Unknown environment variable type while parsing', context); } } else if ((0, utils_1.isFirstChar)(value, '!')) { return this.processEvalValue(context, value); } else if ((0, utils_1.isFirstChar)(value, '(')) { // eslint-disable-next-line @typescript-eslint/no-unused-vars const [_, path, name] = value.match(/^\(([^\)]+)(?:\)(.*))?$/); return this.processSymbolValue(context, path, name); } else if ((0, utils_1.isFirstChar)(value, '[')) { // eslint-disable-next-line @typescript-eslint/no-unused-vars const [_, pattern, name] = value.match(/^\[([^\]]+)(?:\](.*))?$/); const fullPattern = this.getFullPath(context.getPath(), pattern, false); return this.processLiteralValue(context, this.glob(fullPattern).map(path => { return this.processSymbolValue(context, path, name); })); } else { return this.processLiteralValue(context, value); } } return this.processLiteralValue(context, value); } parseAlias(context, value) { if (!(0, utils_1.isString)(value)) { throw new error_1.DiError('A string definition was expected', context); } return this.processAlias(context, value); } parseTag(context, value) { if ((0, utils_1.isString)(value)) { return { name: value }; } if ((0, utils_1.isDictionary)(value)) { if (!(0, utils_1.has)('name', value)) { throw new error_1.DiError('POJO tags must have the `name` key.', context); } return value; } throw new error_1.DiError('Tags must be defined as strings or POJOs.', context); } parseCall(context, value) { var _a; if ((0, utils_1.isString)(value)) { return { method: this.parseValue(context, value), params: [] }; } if ((0, utils_1.isDictionary)(value)) { if (!(0, utils_1.has)('method', value)) { throw new error_1.DiError('POJO calls must have the `method` key.', context); } const method = this.parseValue(context, value['method']); const params = (_a = value['params']) !== null && _a !== void 0 ? _a : []; if (!(0, utils_1.isArray)(params)) { throw new error_1.DiError('Service call parameters must be an array of values.', context); } return { method, params: params.map(param => this.parseValue(context, param)), }; } throw new error_1.DiError('Calls must be defined as strings or POJOs.', context); } parseService(context, value) { var _a, _b; if (!(0, utils_1.isDictionary)(value)) { throw new error_1.DiError('A service can only be created from a POJO', context); } if (!(0, utils_1.has)('symbol', value)) { throw new error_1.DiError('A service must declare the `symbol` property.', context); } const symbol = this.parseValue(context, value['symbol']); const scope = value['scope']; let tags = []; if ((0, utils_1.has)('tags', value)) { if (!(0, utils_1.isArray)(value['tags'])) { throw new error_1.DiError('Service tags must be an array of tags.', context); } tags = value['tags'].map(tag => this.parseTag(context, tag)); } let calls = []; if ((0, utils_1.has)('calls', value)) { if (!(0, utils_1.isArray)(value['calls'])) { throw new error_1.DiError('Service calls must be an array of calls.', context); } calls = value['calls'].map(call => this.parseCall(context, call)); } if (!(0, utils_1.has)('factory', value) && !(0, utils_1.has)('property', value)) { const args = ((_a = value['args']) !== null && _a !== void 0 ? _a : []).map(arg => this.parseValue(context, arg)); return this.processConstructorService(context, symbol, args, scope, tags, calls); } else if ((0, utils_1.has)('factory', value) && !(0, utils_1.has)('property', value)) { const factory = this.parseValue(context, value['factory']); const args = ((_b = value['args']) !== null && _b !== void 0 ? _b : []).map(arg => this.parseValue(context, arg)); return this.processFactoryService(context, symbol, factory, args, scope, tags, calls); } else if (!(0, utils_1.has)('factory', value) && (0, utils_1.has)('property', value)) { const property = this.parseValue(context, value['property']); return this.processPropertyService(context, symbol, property, scope, tags, calls); } else { throw new service_1.UnknownServiceTypeError(context); } } } exports.Processor = Processor;