feat: hooks!

This commit is contained in:
cha0s 2019-11-20 00:53:35 -06:00
parent 3b3ee97e70
commit 2fdee43950
5 changed files with 110 additions and 1 deletions

View File

@ -5,3 +5,11 @@ export function arrayUnique(array) {
export function flatten(array) {
return array.reduce((flattened, elm) => flattened.concat(elm), []);
}
export function fromObject(object) {
const array = [];
for (const key in object) {
array.push(object[key]);
}
return array;
}

View File

@ -0,0 +1 @@
// I don't know how to create assets out of thin air with webpack.

View File

@ -0,0 +1,72 @@
const glob = require('glob');
const {getOptions} = require('loader-utils');
const path = require('path');
const validateOptions = require('schema-utils');
const schema = {
type: 'object',
properties: {
paths: {
items: {
type: 'string',
},
type: 'array',
},
},
required: [
'paths',
],
};
// Dynamically require all traits.
module.exports = function(source) {
const options = getOptions(this);
// Validate schema.
validateOptions(schema, options, 'Avocado hooks');
// Extract options.
const {paths} = options;
// Search avocado.
const avocadoPath = path.normalize(
path.join(__dirname, '..', '..'),
);
paths.push(avocadoPath);
// Get source paths.
const sourcePaths = [];
paths.forEach((path) => {
const files = glob.sync(`${path}/**/hooks.js`, {
follow: true,
});
sourcePaths.push(...files);
});
// Build registers.
const registers = sourcePaths.map((sourcePath) => {
const relativePath = path.relative(__dirname, sourcePath);
const basename = path.basename(relativePath, '.js');
const parts = relativePath.split('/');
// Chop off basename.
parts.pop();
// Module or local?
let importDirectory;
if ('..' === parts[0]) {
const avocadoPathParts = ['@avocado', 'core', 'hook'].concat(parts);
importDirectory = path.normalize(avocadoPathParts.join('/'));
}
else if ('node_modules' === parts[0]) {
importDirectory = parts.slice(1).join('/');
}
else {
importDirectory = `./${parts.join('/')}`;
}
// Register hooks.
const importPath = `${importDirectory}/hooks`;
return [
`registerHooks('${importDirectory}', require('${importPath}'));`,
].join('\n');
});
// Import trait registry first.
const output = [
`import {registerHooks} from '@avocado/core/hook/registry'`,
'',
...registers
].join('\n');
return output;
}

View File

@ -0,0 +1,27 @@
import {fromObject} from '../array';
const impl = {};
export function registerHooks(name, implementations) {
for (const hook in implementations) {
if (!impl[hook]) {
impl[hook] = {};
}
impl[hook][name] = implementations[hook];
}
}
export function invoke(hook, ...args) {
const hookImpl = impl[hook];
if (!hookImpl) {
return {};
}
const result = {};
for (const name in hookImpl) {
result[name] = hookImpl[name](...args);
}
return result;
}
export function invokeFlat(hook, ...args) {
return fromObject(invoke(hook, ...args));
}

View File

@ -1,5 +1,6 @@
export {arrayUnique, flatten} from './array';
export {arrayUnique, flatten, fromObject as arrayFromObject} from './array';
export {EventEmitterMixin as EventEmitter} from './event-emitter';
export {invoke as invokeHook, invokeFlat as invokeHookFlat} from './hook/registry';
export {merge} from './merge';
export {
mergeDiff,