Skip to content

Commit

Permalink
Merge pull request #26 from kitesjs/api-discover
Browse files Browse the repository at this point in the history
Api discover
  • Loading branch information
vunb authored Sep 11, 2019
2 parents bb7f52c + 146d2e4 commit c0c0836
Show file tree
Hide file tree
Showing 12 changed files with 131 additions and 57 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ package-lock.json
prod.config.json
dev.config.json
test*.js
test*.ts

# bundle
packages/**/*.d.ts
Expand Down
10 changes: 0 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,6 @@ Template-based Web Application Framework

**Kites** is a framework providing `dynamic applications` assembling and `Template-based` extracting. Namely it contains a lot of templates and extensions to help building a new application quickly.

Take a look at this:

```ts
@Launcher({
imports?: [], // ... kites extensions manually imported here
discover?: Array<string> | string | boolean; // autodiscover extensions in app's child directories or given path
})
class App {}
```

Features
=======

Expand Down
2 changes: 1 addition & 1 deletion kites.config.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"logger": {
"console": {
"transport": "console",
"level": "info"
"level": "debug"
}

},
Expand Down
2 changes: 2 additions & 0 deletions packages/core/engine/kites-instance.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ describe('kites engine', () => {
const app = await engine({
discover: true,
extensionsLocationCache: false,
// discover extensions from appDirectory (by default)
appDirectory: rootDirectory,
rootDirectory: rootDirectory
}).init();

Expand Down
38 changes: 17 additions & 21 deletions packages/core/engine/kites-instance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import * as path from 'path';
import { Logger, transports } from 'winston';

import { EventEmitter } from 'events';
import { ExtensionsManager } from '../extensions/extensions-manager';
import { DiscoverOptions, ExtensionsManager } from '../extensions/extensions-manager';
import { createLogger } from '../logger';
import { EventCollectionEmitter } from './event-collection';

Expand All @@ -26,14 +26,13 @@ export type KitesReadyCallback = (kites: IKites) => void;
export interface IKitesOptions {
[key: string]: any;
providers?: Array<Type<any>>;
discover?: boolean | string; // string for path discovery
discover?: DiscoverOptions; // options for discovery
loadConfig?: boolean;
rootDirectory?: string;
appDirectory?: string;
parentModuleDirectory?: string;
env?: string;
logger?: any;
mode?: string;
cacheAvailableExtensions?: any;
tempDirectory?: string;
extensionsLocationCache?: boolean;
Expand All @@ -52,7 +51,7 @@ export interface IKites {
logger: Logger;
container: Container;
afterConfigLoaded(fn: KitesReadyCallback): IKites;
discover(option?: string | boolean): IKites;
discover(option: DiscoverOptions): IKites;
use(extension: KitesExtension | ExtensionDefinition | ExtensionDefinition[]): IKites;
init(): Promise<IKites>;
}
Expand Down Expand Up @@ -111,6 +110,7 @@ export class KitesInstance extends EventEmitter implements IKites {
// EXAMPLE 1: kites.discover(true)
// EXAMPLE 2: kites.discover(false)
// EXAMPLE 3: kites.discover('/path/to/discover')
// EXAMPLE 4: kites.discover([true, 2, '/path/to/discover', '/path2'])
discover: false,
env: process.env.NODE_ENV || 'development',
logger: {
Expand Down Expand Up @@ -195,15 +195,8 @@ export class KitesInstance extends EventEmitter implements IKites {
/**
* Enable auto discover extensions
*/
discover(option: string | boolean) {
if (typeof option === 'string') {
this.options.discover = true;
this.options.rootDirectory = option;
} else if (typeof option === 'boolean') {
this.options.discover = option;
} else {
this.options.discover = true;
}
discover(option: DiscoverOptions) {
this.options.discover = option;
return this;
}

Expand Down Expand Up @@ -241,7 +234,7 @@ export class KitesInstance extends EventEmitter implements IKites {
this._silentLogs(this.logger);
}

this._initOptions();
await this._initOptions();
this.logger.info(`Initializing ${this.name}@${this.version} in mode "${this.options.env}"${this.options.loadConfig ? ', using configuration file ' + this.options.configFile : ''}`);

await this.extensionsManager.init();
Expand All @@ -254,10 +247,10 @@ export class KitesInstance extends EventEmitter implements IKites {
return this;
}

private _initOptions() {
private async _initOptions() {
if (this.options.loadConfig) {
this._loadConfig();
this.fnAfterConfigLoaded(this);
await this._loadConfig();
await this.fnAfterConfigLoaded(this);
}

return this._configureWinstonTransports(this.options.logger);
Expand All @@ -269,16 +262,17 @@ export class KitesInstance extends EventEmitter implements IKites {
});
}

private _loadConfig() {
var nconf = require('nconf');
private async _loadConfig() {
const config = await import('nconf');
const nconf = new config.Provider();

let nfn = nconf.argv()
.env({
separator: ':'
})
.env({
separator: '_'
})
.defaults(this.options);
});

if (!this.options.configFile) {

Expand Down Expand Up @@ -306,6 +300,8 @@ export class KitesInstance extends EventEmitter implements IKites {
}
}

// 'if nothing else': 'use this value'
nconf.defaults(this.options);
this.options = nconf.get();
}

Expand Down
9 changes: 5 additions & 4 deletions packages/core/extensions/discover.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@ import { discover } from './discover';

describe('Discover extensions', () => {
it('should load an extension', async () => {
const rootDirectory = join(__dirname, '../test');
const location = join(__dirname, '../test');
const logger = createLogger('discover');
let extensions: any = await discover({
logger: createLogger('discover'),
rootDirectory: rootDirectory
logger,
rootDirectory: [location]
});
console.log('rootDirectory: ', rootDirectory);
logger.info('Discovery location: ' + location);
expect(extensions.length).eq(1);
});
});
16 changes: 14 additions & 2 deletions packages/core/extensions/discover.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,22 @@ import * as path from 'path';
import { Logger } from 'winston';
import * as cache from './location-cache';

/**
* Discover options can be:
* + boolean: true/false
* + string: '/path/to/discover'
* + array: [true, 2, '/path/to/discover', '/path2']
*/
export type DiscoverOptions = string | boolean | [boolean, number, ...string[]];

/**
* Options to discover
*/
export interface IDiscoverOptions {
readonly logger: Logger;
readonly rootDirectory: any;
readonly mode?: any;
readonly depth?: number;
readonly rootDirectory: string[];
readonly env?: any;
readonly cacheAvailableExtensions?: any;
readonly tempDirectory?: any;
readonly extensionsLocationCache?: any;
Expand Down
41 changes: 32 additions & 9 deletions packages/core/extensions/extensions-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ import * as _ from 'lodash';
import * as os from 'os';
import * as path from 'path';
import { IKites } from '..';
import { discover } from './discover';
import { discover, DiscoverOptions } from './discover';
import { ExtensionDefinition, ExtensionOptions, KitesExtension } from './extensions';
import sorter from './sorter';

export class ExtensionsManager extends EventEmitter {
class ExtensionsManager extends EventEmitter {
protected kites: IKites;
protected availableExtensions: KitesExtension[];
protected usedExtensions: KitesExtension[];
Expand Down Expand Up @@ -49,18 +49,37 @@ export class ExtensionsManager extends EventEmitter {
*/
async init() {
this.availableExtensions = [];
// auto discover extensions
if (this.kites.options.discover || (this.kites.options.discover !== false && this.usedExtensions.length === 0)) {

let autodiscover = false;
if (typeof this.kites.options.discover === 'undefined') {
this.kites.options.discover = [false, 0];
} else if (typeof this.kites.options.discover === 'boolean') {
this.kites.options.discover = [this.kites.options.discover, 2, this.kites.options.appDirectory];
} else if (typeof this.kites.options.discover === 'string') {
this.kites.options.discover = [true, 2, this.kites.options.discover];
} else if (this.kites.options.discover.length < 2) {
throw new Error('Discover options as array requires at least 2 elements! Example: [true, 2]');
}

// autodiscover extensions
autodiscover = this.kites.options.discover.shift() as boolean;

if (autodiscover) {
let depth = this.kites.options.discover.shift() as number;
let directories = this.kites.options.discover as string[];
let extensions = await discover({
cacheAvailableExtensions: this.kites.options.cacheAvailableExtensions,
extensionsLocationCache: this.kites.options.extensionsLocationCache,
logger: this.kites.logger,
mode: this.kites.options.mode,
rootDirectory: this.kites.options.rootDirectory,
env: this.kites.options.env,
depth: depth,
rootDirectory: directories,
tempDirectory: this.kites.options.tempDirectory,
});
this.kites.logger.debug('Discovered ' + extensions.length + ' extensions');
this.kites.logger.debug('Autodiscover ' + extensions.length + ' extensions!');
this.availableExtensions = this.availableExtensions.concat(extensions);
} else {
this.kites.logger.debug('Autodiscover is not enabled!');
}
// filter extensions will be loaded?
this.availableExtensions = this.availableExtensions.concat(this.usedExtensions);
Expand All @@ -71,7 +90,6 @@ export class ExtensionsManager extends EventEmitter {

this.availableExtensions.sort(sorter);
return this.useMany(this.availableExtensions);

}

/**
Expand Down Expand Up @@ -130,7 +148,7 @@ export class ExtensionsManager extends EventEmitter {
let errorMsg;

if (!extension.name) {
errorMsg = `Error when loading anonymous extension${extension.directory != null ? ` at ${extension.directory}` : ''}${os.EOL}${e.stack}`;
errorMsg = `Error when loading anonymous extension ${extension.directory != null ? ` at ${extension.directory}` : ''}${os.EOL}${e.stack}`;
} else {
errorMsg = `Error when loading extension ${extension.name}${os.EOL}${e.stack}`;
}
Expand All @@ -141,3 +159,8 @@ export class ExtensionsManager extends EventEmitter {
}

}

export {
ExtensionsManager,
DiscoverOptions
};
48 changes: 48 additions & 0 deletions packages/core/extensions/fs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,51 @@ export function walkSync(rootPath: string, fileName: string, exclude?: string |

return results;
}

/**
* Discovery file list with depth level
* @param dirname Folder to scan extensions
* @param filename Pattern for searching
* @param depth max level to discover
* @param exclude pattern to exclude searching
*/
export function walkSyncLevel(dirname: string[], filename: string, depth: number = 2, exclude?: string) {
// console.log('Start searching: ', dirname);

function readFiles(candidate: string, level: number): string[] {
// console.log('Find in: ', candidate);

let results: string[] = [];
let list: string[];
try {
list = fs.readdirSync(candidate);
} catch (err) {
// no permissions to read folder for example
// just skip it
list = [];
}

for (const item of list) {
let fullname = path.join(candidate, item);
if (fullname.indexOf(exclude as string) < 0) {
if (fs.statSync(fullname).isDirectory()) {
if (level < depth) {
const next = readFiles(fullname, level + 1);
results = results.concat(next);
}
} else if (item === filename) {
results.push(fullname);
}
}
}

return results;
}

let vResults = [];
for (const item of dirname) {
vResults = vResults.concat(readFiles(item, 0));
}

return vResults;
}
2 changes: 1 addition & 1 deletion packages/core/extensions/location-cache.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ describe('Location cache', () => {
const rootDirectory = join(__dirname, '../test');
let extensions: any = await cache.get({
logger: createLogger('location-cache'),
rootDirectory: rootDirectory
rootDirectory: [rootDirectory]
});
console.log('Found: ', extensions, rootDirectory);
expect(extensions.length).eq(1);
Expand Down
Loading

0 comments on commit c0c0836

Please sign in to comment.