refactor: new trait source pattern

This commit is contained in:
cha0s 2019-04-14 20:10:44 -05:00
parent 8da18b115b
commit bd9e0a4461
4 changed files with 62 additions and 50 deletions

View File

@ -1,53 +1,58 @@
const glob = require('glob');
const {getOptions} = require('loader-utils');
const path = require('path');
const glob = require('glob');
// Dynamically require all traits.
module.exports = (source) => {
const nodeModulesPath = path.resolve(
__dirname, 'node_modules',
);
const traitPaths = [
{
pathGlob: path.resolve(
nodeModulesPath,
'@avocado',
'entity',
'traits',
'*.js'
),
replacer: (dirname) => {
return dirname.replace(`${nodeModulesPath}/`, '');
},
},
{
pathGlob: path.resolve(__dirname, 'common', 'traits', '*.js'),
replacer: (dirname) => {
return dirname.replace(__dirname, '.');
},
},
];
let lines = [];
traitPaths.forEach(({pathGlob, replacer}) => {
const files = glob.sync(pathGlob);
const modules = files.map((file) => {
let dirname = path.dirname(file);
dirname = replacer(dirname);
const basename = path.basename(file, '.js');
return `${dirname}/${basename}`;
module.exports = function(source) {
const options = getOptions(this);
if (!options.paths) {
options.paths = [];
}
// Search avocado.
options.paths.push(path.resolve(
__dirname, 'node_modules', '@avocado',
));
// Get all trait source paths.
const sourcePaths = [];
options.paths.forEach((path) => {
const files = glob.sync(`${path}/**/*.trait.js`, {
follow: true,
});
const moduleLines = modules.map((module_) => {
const basename = path.basename(module_);
const parts = basename.split('-');
const className = parts.reduce((className, part) => {
const firstLetter = part.charAt(0).toUpperCase();
const rest = part.substr(1).toLowerCase();
return className + firstLetter + rest;
}, '');
return `import {${className}} from '${module_}';\nregisterTrait(${className});\n`;
});
lines = lines.concat(moduleLines);
sourcePaths.push(...files);
});
lines.unshift(`import {registerTrait} from '@avocado/entity/trait-registry';\n`);
return lines.join('\n');
// Build import definitions.
const importDefinitions = sourcePaths.map((sourcePath) => {
const relativePath = path.relative(__dirname, sourcePath);
const basename = path.basename(relativePath, '.trait.js');
const parts = relativePath.split('/');
// Chop off basename.
parts.pop();
// Module or local?
let importDirectory;
if ('node_modules' === parts[0]) {
importDirectory = `${parts.slice(1).join('/')}`;
}
else {
importDirectory = `./${parts.join('/')}`
}
const importPath = `${importDirectory}/${basename}.trait`;
// Extract class name.
const baseparts = basename.split('-');
const className = baseparts.reduce((className, part) => {
const firstLetter = part.charAt(0).toUpperCase();
const rest = part.substr(1).toLowerCase();
return className + firstLetter + rest;
}, '');
// Import and register.
return [
`import {${className}} from '${importPath}';`,
`registerTrait(${className});`,
].join('\n');
});
// Import trait registry first.
return [
`import {registerTrait} from '@avocado/entity/trait-registry'`,
'',
...importDefinitions
].join('\n');
}

View File

@ -18,9 +18,16 @@ const config = {
},
{
test: /register-traits.js/,
use: {
loader: './generate-trait-defs',
},
use: [
{
loader: './generate-trait-defs',
options: {
paths: [
path.resolve(__dirname, 'common'),
],
}
},
],
},
],
},