Skip to content

Commit

Permalink
Issue #386 [Enhancement][WIP] Use target-configurator package
Browse files Browse the repository at this point in the history
  • Loading branch information
t2ym committed Sep 9, 2020
1 parent 29f35bc commit a01b4b9
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 205 deletions.
218 changes: 13 additions & 205 deletions demo-config/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,223 +3,25 @@
Copyright (c) 2020 Tetsuya Mori <t2y3141592@gmail.com>. All rights reserved.
*/
const path = require('path');
const fs = require('fs');
const GulpDefaultRegistry = require('undertaker-registry');
const { GulpDefaultRegistry, Configurable } = require('target-configurator');

class TargetConfig extends GulpDefaultRegistry {
constructor() {
super();
}
init(gulpInst) {
super.init(gulpInst);
this.gulp = gulpInst;
this._configure();
this._resolveConfig();
}
get(name) {
let task = super.get(name);
if (!task) {
task = this.task(name); // register plugin
}
return task;
}
set(name, fn) {
let boundFn = fn.bind(this);
boundFn.displayName = fn.displayName;
boundFn.description = fn.description;
boundFn.flags = fn.flags;
return super.set(name, boundFn);
}
resolveConfiguratorPath(pluginName) {
let configuratorJs = 'configurator.js';
let pluginConfiguratorPath = path.resolve(targetConfig.path.hook, targetConfig.path.plugins, pluginName, configuratorJs); // local
if (fs.existsSync(pluginConfiguratorPath)) {
return pluginConfiguratorPath;
}
if (this['thin-hook'].pluginScope) {
let packageName = pluginName.split('/')[0] === this['thin-hook'].pluginScope
? pluginName
: path.join(this['thin-hook'].pluginScope, pluginName);
try {
pluginConfiguratorPath = require.resolve(path.join(packageName, configuratorJs)); // @thin-hook scope
if (fs.existsSync(pluginConfiguratorPath)) {
return pluginConfiguratorPath;
}
}
catch (e) {}
}
if (pluginName.startsWith('@')) { // scoped
let packageNameSplit = pluginName.split('/');
let packageName;
switch (packageNameSplit.length) {
case 1: // "@plugin-scope"
packageName = path.join(pluginName, 'default'); // "@plugin-scope/default"
break;
case 2: // "@plugin-scope/name"
packageName = pluginName;
break;
default: // "@plugin-scope/name/..."
if (packageNameSplit[packageNameSplit.length - 1] === configuratorJs) {
// "@plugin-scope/name/configurator.js"
packageNameSplit.pop();
packageName = packageNameSplit.join('/');
}
else {
// "@plugin-scope/name/subdir"
packageName = pluginName;
}
break;
}
try {
pluginConfiguratorPath = require.resolve(path.join(packageName, configuratorJs)); // scoped plugin
if (fs.existsSync(pluginConfiguratorPath)) {
return pluginConfiguratorPath;
}
}
catch (e) {}
}
throw new Error(`targetConfig.resolveConfiguratorPath: failed to resolve pluginName "${pluginName}"`);
}
// register gulp task
// Note: this function must be called via task() so that this is the targetConfig object
task(pluginName) {
const targetConfig = this;
const configuratorPath = this.resolveConfiguratorPath(pluginName);
const plugin = require(configuratorPath);
if (plugin.name !== pluginName) {
throw new Error(`task("${pluginName}"): plugin.name === ${plugin.name} does not match`);
}
if (typeof plugin.init === 'function') {
plugin.init.call(targetConfig, targetConfig);
}
return this.gulp.task(pluginName,
this.gulp.series(
Object.assign((done) => {
if (Array.isArray(plugin.dependencies)) {
plugin.dependencies.forEach(dependency => {
if(!(targetConfig[dependency] && targetConfig[dependency].done)) {
throw new Error(`plugin task "${pluginName}": dependent task "${dependency}" has not completed`);
}
});
}
done();
}, { displayName: `${pluginName} check dependencies` }),
// Note: task function is bound to targetConfig since gulp.series() bypasses registry.set(name, fn)
Object.assign(plugin.configurator.call(targetConfig, targetConfig).bind(targetConfig), { displayName: `${pluginName} configurator` }),
Object.assign((done) => {
targetConfig[pluginName] = targetConfig[pluginName] || {};
targetConfig[pluginName].done = true;
done();
}, { displayName: `${pluginName} done` }),
)
);
}
// get thin-hook package path even from within thin-hook package
static hookPath = (() => {
try {
let hookJs = require.resolve('thin-hook');
if (hookJs) {
return path.dirname(hookJs);
}
}
catch (e) {}
let dirname = __dirname;
let packageName;
while (!packageName) {
let packagePath = path.resolve(dirname, 'package.json');
if (fs.existsSync(packagePath)) {
let _package = require(packagePath);
packageName = _package.name;
break;
}
dirname = path.resolve(dirname, '..');
if (dirname === '/') {
break;
}
}
if (packageName === 'thin-hook') {
return dirname;
}
else {
return path.resolve(__dirname, '..');
}
})();
static needResolution = Symbol('need resolution');
static basePath = module.parent.path;
static configPath = __dirname;
// delayed resolution of configurations
_resolveConfig() {
for (let config in this) {
if (this[config] && typeof this[config] === 'object' && this[config][TargetConfig.needResolution]) {
for (let key in this[config]) {
if (typeof this[config][key] === 'function') {
this[config][key] = this[config][key].call(this);
}
}
}
}
}
// generate arguments for concurrently
getConcurrentlyArguments(commands, ...names) {
let args = names.map(command => `"${commands[command]}"`);
return `--names "${names.join(',')}" ${args.join(' ')}`;
}
// reverse [ fullPath, urlPath ] mappings
reverseMappings(mappings) {
// [ urlPath, fullPath ] in directory path names
let _mappings = JSON.parse(JSON.stringify(mappings)); // clone
_mappings.sort((a, b) => {
let _a = a[1] + (a[1].endsWith('/') ? '' : '/');
let _b = b[1] + (b[1].endsWith('/') ? '' : '/');
if (_a.length < _b.length) {
if (_b.startsWith(_a)) {
// a > b
return 1;
}
}
else if (_a.length > _b.length) {
if (_a.startsWith(_b)) {
// a < b
return -1;
}
}
return _a.localeCompare(_b);
});
return _mappings.map(([ fullPath, urlPath ]) => [ urlPath, fullPath ]);
}
// map a path with provided mappings
mapper(mappings, _path) {
let result;
for (let [ original, mapped ] of mappings) {
if (_path.startsWith(original + '/')) {
result = path.join(mapped, _path.substring(original.length + '/'.length));
break;
}
}
if (!result) {
throw new Error(`targetConfig.mapper(): "${_path}" cannot be mapped`);
}
return result;
}
class TargetConfig extends Configurable(GulpDefaultRegistry, 'thin-hook') {
// configure itself step by step
_configure() {
this.path = {
base: TargetConfig.basePath,
super._configure();
Object.assign(this.path, {
root: 'demo',
config: path.relative(TargetConfig.basePath, TargetConfig.configPath),
backend: 'demo-backend',
frontend: 'demo-frontend',
keys: 'demo-keys',
components: 'bower_components',
encodedIndexHtml: 'index.html',
decodedIndexHtml: 'original-index.html',
hook: TargetConfig.hookPath,
plugins: 'plugins',
};
hook: TargetConfig.packagePath,
});
Object.assign(this, { // dependent on this.path
'thin-hook': {
hook: require(path.resolve(this.path.hook, 'hook.js')),
pluginScope: '@thin-hook',
hook: require('../hook.js'/*path.resolve(this.path.hook, 'hook.js')*/),
},
url: {
[TargetConfig.needResolution]: true,
Expand Down Expand Up @@ -298,6 +100,12 @@ class TargetConfig extends GulpDefaultRegistry {
"frontend-modules": `cd ${path.resolve(this.path.base, this.path.root)} && npm install`,
"frontend-modules-locked": `cd ${path.resolve(this.path.base, this.path.root)} && npm ci`,
},
keys: {
noUpdate: true,
},
'automation-secret': {
serverSecret: /*null*/'DummyServerSecretOnlyForDebugging',
},
});
Object.assign(this, { // scoped plugins
'@thin-hook/examples': {
Expand Down
9 changes: 9 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@
"scenarist": "^1.1.8",
"selenium-standalone": "^6.15.3",
"strip-bom": "^3.0.0",
"target-configurator": "^0.1.1",
"through2": "^2.0.3",
"transform-loader": "^0.2.4",
"tty-browserify": "0.0.0",
Expand Down

0 comments on commit a01b4b9

Please sign in to comment.