Skip to content

Instantly share code, notes, and snippets.

@jpravetz
Created May 9, 2018 01:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jpravetz/39b5c86a4c8b8501ea9472993f2b7315 to your computer and use it in GitHub Desktop.
Save jpravetz/39b5c86a4c8b8501ea9472993f2b7315 to your computer and use it in GitHub Desktop.
Aurelia CLI Task to Generate Webpack-compatible index.js files under the src/resources folder
import gulp from 'gulp';
import project from '../aurelia.json';
import fs from 'fs';
import Path from 'path';
import util from 'util';
/**
* Task generates webpack compatible index.js files under the src/resources folder,
* recursively descending and including every file that is found.
* To exclude files in a particular folder, add their names to a .resourceignore file in that
* folder.
*/
const MODE = {
skipEmptyFolder: false,
config: true,
resources: false,
local: {
config: true,
resource: false
}
};
const REGEX = {
index: /^index.(js|mjs|ts)$/i,
js: /\.(js|mjs|ts)$/i,
html: /\.(ejs|pug|jade|html)$/i,
base: /([^\/\.]+)\.[a-zA-Z0-9]+$/,
sep: /[,\s]+/
};
function fileBase (path) {
let m = path.match(REGEX.base);
if (m && m[1]) {
return m[1];
}
}
function toCamelCase (str) {
return str.split('-').map(function (word, index) {
if (index === 0) {
return word.toLowerCase();
}
return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
}).join('');
}
/**
* Reads the list of files to exclude, found in folder/.resourceignore file.
* This file should contain a white-space delimited list of file names, minus their extensions.
* @param root
* @returns {Promise<any>}
*/
function readExclusions (root) {
return new Promise((resolve, reject) => {
let ignorePath = Path.resolve(root, '.resourceignore');
fsStat(ignorePath)
.then((stat) => {
if (stat.isFile()) {
return fsReadFile(ignorePath)
.then((resp) => {
if (resp) {
let exclusions = String(resp).trim().split(REGEX.sep);
resolve(exclusions);
}
resolve([]);
})
.catch((err) => {
resolve([]);
});
} else {
resolve([]);
}
})
.catch((err) => {
resolve([]);
});
});
}
const fsStat = util.promisify(fs.stat);
const fsReaddir = util.promisify(fs.readdir);
const fsReadFile = util.promisify(fs.readFile);
const fsWriteFile = util.promisify(fs.writeFile);
function runOnFolder (root, level) {
let exclusions = [];
let imports = [];
let resources = {};
return Promise.resolve()
.then(() => {
return readExclusions(root);
})
.then((resp) => {
exclusions = resp;
return fsReaddir(root);
})
.then((files) => {
let jobs = [];
files.forEach(file => {
let path = Path.resolve(root, file);
let job = fsStat(path)
.then((stat) => {
if (stat.isDirectory()) {
imports.push(file);
return runOnFolder(path);
} else if (stat.isFile() && !REGEX.index.test(file)) {
let base = fileBase(file);
if (!exclusions.includes(base)) {
['js', 'html'].forEach(type => {
if (REGEX[type].test(file)) {
resources[base] = resources[base] ? resources[base] : {};
resources[base][type] = true;
}
});
}
}
});
jobs.push(job);
});
return Promise.all(jobs);
})
.then((resp) => {
let len = Object.keys(resources).length;
if (MODE.skipEmptyFolder && !imports.length && !len) {
console.log('Skipping folder ', root);
return Promise.resolve();
}
let buf = Buffer.alloc(4096);
let offset = 0;
if (len) {
offset += buf.write('import {PLATFORM} from \'aurelia-pal\';\n\n', offset);
}
if (imports.length) {
imports.forEach(name => {
offset += buf.write(`import ${toCamelCase(name)} from './${name}/index';\n`, offset);
});
offset += buf.write('\n', offset);
}
if (MODE.resource) {
if (len) {
offset += buf.write('let resources = [\n', offset);
let idx = 0;
Object.keys(resources).forEach(key => {
let comma = (++idx < len) ? ',' : '';
let resource = resources[key].js ? key : `${key}.pug`;
offset += buf.write(` PLATFORM.moduleName('./${resource}')${comma}\n`, offset);
});
offset += buf.write('];\n', offset);
} else {
offset += buf.write('let resources = [];\n', offset);
}
if (MODE.resources) {
offset += buf.write('\nexport default resources;\n', offset);
}
}
if (MODE.config) {
offset += buf.write('const configure = function (config) {\n', offset);
if (len) {
Object.keys(resources).forEach(key => {
let resource = resources[key].js ? key : `${key}.pug`;
offset += buf.write(` config.globalResources(PLATFORM.moduleName('./${resource}'));\n`, offset);
});
}
imports.forEach(name => {
offset += buf.write(` ${toCamelCase(name)}(config);\n`, offset);
});
offset += buf.write('};\n', offset);
offset += buf.write('\nexport default configure;\n', offset);
}
// if( imports.length ) {
// imports.forEach(name => {
// offset += buf.write(`${name}.forEach(\n`, offset);
// });
// }
let indexFile = Path.resolve(root, 'index.js');
console.log('Generating ', indexFile);
return fsWriteFile(indexFile, buf.slice(0, offset));
});
}
function runMaker (done) {
let path = Path.resolve(project.paths.root, project.paths.resources);
runOnFolder(path, 0)
.then((resp) => {
done();
})
.catch((err) => {
done(err);
});
}
const run = gulp.series(runMaker);
export {run as default};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment