Skip to content

Commit

Permalink
Merge fc32328 into 7eb50d3
Browse files Browse the repository at this point in the history
  • Loading branch information
hosein2398 committed Nov 1, 2019
2 parents 7eb50d3 + fc32328 commit 4900661
Show file tree
Hide file tree
Showing 15 changed files with 272 additions and 9 deletions.
43 changes: 40 additions & 3 deletions README.md
Expand Up @@ -47,20 +47,28 @@ This will generate `footer` component in `./src/components/footer.vue` and also
## Usage
General usage is like:
```
gue <componentName> [directory] [options]
$ gue --help
Usage: gue <componentName> [direcroty] [options]
Options:
-u, --unit create unit test of the component too
-t, --template <name> define which template to use
-h, --help output usage information
```
* &lt;componentName&gt; is mandatory.
* [directory] is optional, and is a relative path.
If you have a config file this will be a `subdirectory` of your [componentRoot](#options)
If you don't, then this will lead to generation of component in exact `direcroty`
* [options] are optional, only available option is `-u` which will generate test file.
* [options] are optional, available options are `-u` which will generate test file, and `-t` which is used to define which template for components to use.

## Config file
Gue accepts a config file to change default settings. In root directory of project make a file `gue.json`, and Gue will automatically recognize and use it.
#### Options
Here are available options for config file:
* `componentRoot`: root directory which components will be generated in. should be relative path.
* `componentSource`: path to custom component template.
* `componentSource`: path to custom component template. Or an object to define [multiple templates](#using-multiple-custom-templates).
* `unitRoot`: directory which test will be generated in. should be a relative path.
* `unitSource`: path to custom test file template.

Expand Down Expand Up @@ -104,3 +112,32 @@ data() {
</style>
```
To see other examples look at [templates folder](https://github.com/hosein2398/gue/tree/master/src/templates).
##### Using multiple custom templates
You can use multiple custom templates. So `componentSource` can be object (multiple templates) or a string (single template). Multiple templates can be created like:
```
{
"componentSource": {
"component" : "./tmps/component.vue",
"page" : "./tmps/page.vue"
}
}
```
And when using Gue you have to tell it which component template to use:
```
gue menu -t component
gue setting ./pages -t page
```
You can define one of your templates as `default` one, so that you don't have to type `-t` every time. Default component can be specified with `:default` postfix:
```
{
"componentSource": {
"component:default" : "./tmps/component.vue",
"page" : "./tmps/page.vue"
}
}
```
Now if you type any command without `-t`, component template will be used.
```
gue foo
```
Will use `component` template to generate foo component. No need of `-t component`
2 changes: 1 addition & 1 deletion package.json
@@ -1,6 +1,6 @@
{
"name": "vue-gue",
"version": "0.1.0",
"version": "0.2.0",
"description": "Vue component generator",
"repository": {
"url": "https://github.com/hosein2398/gue",
Expand Down
3 changes: 2 additions & 1 deletion src/bin.js
Expand Up @@ -5,7 +5,8 @@ const Gue = require('.');

program
.arguments('<componentName> [direcroty]')
.option('-u, --unit', 'create unit test of the component too');
.option('-u, --unit', 'create unit test of the component too')
.option('-t, --template <name>', 'define which template to use');

const params = program.parse(process.argv);

Expand Down
37 changes: 34 additions & 3 deletions src/index.js
Expand Up @@ -5,6 +5,7 @@ const logger = require('./logger');
const configFile = require('./config');
const cmpTemplate = require('./templates/sample-component');
const unitTemplate = require('./templates/sample-unit');
const {isObject, findDefault, isObjectEmpty} = require('./utils');

class Gue {
constructor(componentName, distDir, options) {
Expand Down Expand Up @@ -47,9 +48,33 @@ class Gue {
}

formatComponent() {
const data = this.componentSource ?
fs.readFileSync(this.componentSource, {encoding: 'utf8'}) :
cmpTemplate;
let data;
if (this.options.template) {
this.checkConfigExist();
if (!isObject(this.componentSource)) {
logger.fatal('When using -t your componentSource must be an object');
}

if (isObject(this.componentSource)) {
if (!(this.options.template in this.componentSource)) {
logger.fatal(`There is no "${this.options.template}" template in componentSource in gue config file`);
}

data = fs.readFileSync(this.componentSource[this.options.template], {encoding: 'utf8'});
}
} else if (isObject(this.componentSource)) {
const defaultTemplate = findDefault(this.componentSource);
if (!defaultTemplate) {
logger.fatal('No default component defined in componentSource object');
}

data = fs.readFileSync(this.componentSource[defaultTemplate], {encoding: 'utf8'});
} else {
data = this.componentSource ?
fs.readFileSync(this.componentSource, {encoding: 'utf8'}) :
cmpTemplate;
}

const rex = /<%NAME%>/g;
return data.replace(rex, this.componentName);
}
Expand Down Expand Up @@ -98,6 +123,12 @@ class Gue {
return true;
}

checkConfigExist() {
if (isObjectEmpty(configFile)) {
logger.fatal('Could not find any config file in root directory');
}
}

run() {
this.generate();
}
Expand Down
7 changes: 7 additions & 0 deletions src/logger.js
Expand Up @@ -40,6 +40,13 @@ class Logger {
);
console.log(e);
}

fatal(e) {
console.log(
box(`⚠️ ${chalk.red(e)}`, {padding: 1})
);
throw new Error(e);
}
}

module.exports = new Logger();
6 changes: 6 additions & 0 deletions src/utils.js
@@ -0,0 +1,6 @@
exports.isObject = obj => obj !== null && obj.constructor.name === 'Object';

exports.isObjectEmpty = obj => !Object.keys(obj).length;

exports.findDefault = obj => Object.keys(obj).find(i => i.split(':').length > 1);

3 changes: 2 additions & 1 deletion test/cleanup.js
Expand Up @@ -11,7 +11,8 @@ for (const file of files) {
'.nyc_output',
'cleanup.js',
'gue.json',
'templates'
'templates',
'conditions'
];
if (doNotRemove.includes(file)) {
continue;
Expand Down
27 changes: 27 additions & 0 deletions test/conditions/default-template/black.vue
@@ -0,0 +1,27 @@
<template>
<div class="black">
here is the test component <%NAME%>
</div>
</template>

export default {
name: "<%NAME%>",
props: [],
mounted() {

},
data() {
return {
test: null
}
},
methods: {

},
computed: {

}
}

<style>
</style>
6 changes: 6 additions & 0 deletions test/conditions/default-template/gue.json
@@ -0,0 +1,6 @@
{
"componentSource": {
"white" : "./white.vue",
"black:default" : "./black.vue"
}
}
27 changes: 27 additions & 0 deletions test/conditions/default-template/white.vue
@@ -0,0 +1,27 @@
<template>
<div class="white">
here is the test component <%NAME%>
</div>
</template>

export default {
name: "<%NAME%>",
props: [],
mounted() {

},
data() {
return {
test: null
}
},
methods: {

},
computed: {

}
}

<style>
</style>
6 changes: 6 additions & 0 deletions test/conditions/right-template/gue.json
@@ -0,0 +1,6 @@
{
"componentSource": {
"some" : "./some/sdf.vue",
"right" : "./right.vue"
}
}
27 changes: 27 additions & 0 deletions test/conditions/right-template/right.vue
@@ -0,0 +1,27 @@
<template>
<div class="right">
here is the test component <%NAME%>
</div>
</template>

export default {
name: "<%NAME%>",
props: [],
mounted() {

},
data() {
return {
test: null
}
},
methods: {

},
computed: {

}
}

<style>
</style>
3 changes: 3 additions & 0 deletions test/conditions/simple-config/gue.json
@@ -0,0 +1,3 @@
{
"componentRoot": "./somewhereYouLike"
}
6 changes: 6 additions & 0 deletions test/conditions/wrong-template/gue.json
@@ -0,0 +1,6 @@
{
"componentSource": {
"some" : "./sefsfsf",
"another" : "./nowhere"
}
}
78 changes: 78 additions & 0 deletions test/index.js
@@ -1,9 +1,12 @@
const fs = require('fs');
const path = require('path');
const tap = require('tap');
const Gue = require('../src');
const defaultVueTemplate = require('../src/templates/sample-component');
const defaultUnitTemplate = require('../src/templates/sample-unit');

const initCwd = process.cwd();

function getContent(dir) {
return fs.readFileSync(dir, {encoding: 'utf8'});
}
Expand All @@ -22,6 +25,20 @@ function formatTest(name, unitPath, tmp) {
return data.replace(rexPath, unitPath);
}

/*
* Since we want to test diffrent config files and config files are
* recognized automatically from root dir, we need to change cwd
* every time. And since config file gets resolved only once when
* you require the module(here ./src module) we need to clear cache of
* require so when we change the directory, the module ./src/config gets
* evaluated again and it recognizes config file in new cwd.
*/
function cleanCacheAndChageCwd(dir) {
delete require.cache[require.resolve('../src/config')];
delete require.cache[require.resolve('../src')];
process.chdir(path.resolve(initCwd, dir));
}

const customVueTemplate = getContent('./templates/myVueTmp.vue');
const customUnitTemplate = getContent('./templates/myUnitTmp.js');

Expand Down Expand Up @@ -120,3 +137,64 @@ tap.test('Custom root dir for test && custom test file', t => {
t.plan(1);
t.equal(getContent(testDir), formatTest(name, '../src/components/ninthTest.vue', customUnitTemplate));
});

tap.test('Should throw when there is -t but componentSource is not object', t => {
cleanCacheAndChageCwd('./conditions/simple-config');
const Gue = require('../src');
const name = 'tenthTest';
const gue = new Gue(name, null, {template: 'foo'});
t.plan(1);
// TODO: check the exact error
t.throw(() => {
gue.generate();
});
});

tap.test('Should throw when template name is not in config', t => {
cleanCacheAndChageCwd('./conditions/wrong-template');
const Gue = require('../src');
const name = 'eleventhTest';
const gue = new Gue(name, null, {template: 'foo'});
t.plan(1);
// TODO: check the exact error
t.throw(() => {
gue.generate();
});
});

tap.test('Should work with multiple templates and choose right one', t => {
cleanCacheAndChageCwd('./conditions/right-template');
const Gue = require('../src');
const name = 'twelvethTest';
// Note that we are now in: ./conditions/right-template
const dir = './src/components/twelvethTest.vue';
const cutomTemplateDir = './right.vue';
const gue = new Gue(name, null, {template: 'right'});
gue.run();
t.plan(1);
t.equal(getContent(dir), formatComponent(name, getContent(cutomTemplateDir)));
});

tap.test('Should throw when componentSource is object but there is not default template(and -t is not passed of course)', t => {
cleanCacheAndChageCwd('./conditions/right-template');
const Gue = require('../src');
const name = 'foo';
const gue = new Gue(name, null, {});
t.plan(1);
t.throw(() => {
gue.generate();
});
});

tap.test('Should recognize default template when there is no -t', t => {
cleanCacheAndChageCwd('./conditions/default-template');
const Gue = require('../src');
const name = 'iBlack';
// Note that we are now in: ./conditions/default-template
const dir = './src/components/iBlack.vue';
const cutomTemplateDir = './black.vue';
const gue = new Gue(name, null, {});
gue.run();
t.plan(1);
t.equal(getContent(dir), formatComponent(name, getContent(cutomTemplateDir)));
});

0 comments on commit 4900661

Please sign in to comment.