Yeoman copy function doesn't work after prompting - javascript

i am fiddleing around with yeoman and want to write my first generator for a simple html5 boilerplate. My problem is, that the two functions in my generator work well on their own but not together and i don't know why. I checked some generators from the yeoman page, but i don't see what i am doing wrong. I hope you can help me. This is my code:
'use strict';
var generators = require('yeoman-generator');
var yosay = require('yosay');
module.exports = generators.Base.extend({
initializing: function(){
this.log(yosay("\'Allo \'allo I will create your HTML5 Boilerplate..."));
},
prompting: function() {
var done = this.async();
this.prompt({
type: 'input',
name: 'name',
message: 'Your project name',
//Defaults to the project's folder name if the input is skipped
default: this.appname
}, function(answers) {
this.props = answers
this.log(answers.name);
done();
}.bind(this));
},
writing: function(){
this.fs.copyTpl(
this.templatePath('_page/_index.html'),
this.destinationPath('index.html'),
{ title: "answers.name" }
);
},
});
Thanks in advance!

Try using the Promises version of the prompting function, as shown on yeoman.io.
Example:
prompting: function() {
return this.prompt({
type: 'input',
name: 'name',
message: 'Your project name',
//Defaults to the project's folder name if the input is skipped
default: this.appname
}).then(function(answers) {
this.props = answers
this.log(answers.name);
}.bind(this));
},
Changes:
add return before this.prompt().
change this.prompt(prompts, callback); to this.prompt(prompts).then(callback);

Related

Apply Sqlite/Any SQL Database Migrations with Electron [Windows, Mac]

My Scenario,
I am working on a desktop based application. Where My big challenge is keeping data into relational DB(Offline) and sync accordingly(Company have their own syncing algorithm). I am using Electron and VueJS as client side. For building the desktop app I'm using electron-builder. I am able to write migrations with raw SQL or various ORM.
What I want?
While I'll install into a desktop, I want to create the database file and apply all the migrations on the client's computer. I just don't know that part how to do that. I also looked into Electron Builder Docs. But didn't understand. I need an example, any idea.
Please help me. Thanks
After doing a lot of research I found an awesome solution provided by sequalize.js. I found a library Umzug Github. Let's look at the implementation...
/**
* Created by Ashraful Islam
*/
const path = require('path');
const Umzug = require('umzug');
const database = /* Imported my database config here */;
const umzug = new Umzug({
storage: 'sequelize',
storageOptions: {
sequelize: database
},
// see: https://github.com/sequelize/umzug/issues/17
migrations: {
params: [
database.getQueryInterface(), // queryInterface
database.constructor, // DataTypes
function () {
throw new Error('Migration tried to use old style "done" callback. Please upgrade to "umzug" and return a promise instead.');
}
],
path: './migrations',
pattern: /\.js$/
},
logging: function () {
console.log.apply(null, arguments);
}
});
function logUmzugEvent(eventName) {
return function (name, migration) {
console.log(`${name} ${eventName}`);
}
}
function runMigrations() {
return umzug.up();
}
umzug.on('migrating', logUmzugEvent('migrating'));
umzug.on('migrated', logUmzugEvent('migrated'));
umzug.on('reverting', logUmzugEvent('reverting'));
umzug.on('reverted', logUmzugEvent('reverted'));
module.exports = {
migrate: runMigrations
};
Idea behind the scene
I clearly declare the migration directory. Also, define the file matching pattern. Umzug just read files from there and run the DB migration. An example migration file is following...
// 000_Initial.js
"use strict";
module.exports = {
up: function(migration, DataTypes) {
return migration.createTable('Sessions', {
sid: {
type: DataTypes.STRING,
allowNull: false
},
data: {
type: DataTypes.STRING,
allowNull: false
},
createdAt: {
type: DataTypes.DATE
},
updatedAt: {
type: DataTypes.DATE
}
}).then(function() {
return migration.addIndex('Sessions', ['sid']);
});
},
down: function(migration, DataTypes) {
return migration.dropTable('Sessions');
}
};

Yeoman task not copying directory

I'm trying to build a simple yeoman task that copies a template directory into the destination directory where the user is running the command. The prompt method is working but nothing is being written or copied. Any idea where I'm going wrong here?
'use strict';
//Require dependencies
var yeoman = require('yeoman-generator');
var chalk = require('chalk');
var yosay = require('yosay');
module.exports = class extends yeoman {
//Ask for user input
prompting() {
var done = this.async();
this.prompt({
type: 'input',
name: 'name',
message: 'Your project name',
//Defaults to the project's folder name if the input is skipped
default: this.appname
}, function(answers) {
this.props = answers
this.log(answers.name);
done();
}.bind(this));
}
//Writing Logic here
writing() {
this.fs.copyTpl(
this.templatePath('testfile'),
this.destinationPath('testfile')
);
}
};
The prompt method doesn't take a callback since release 1.0
Instead you want this.prompt([...]).then(callback)

How to check if directory exists using Yeoman?

I am asking the user for a directory name, and then if the directory exists I want to ask them if they want to archive it. However I am not sure what function I can use inside Yeoman to achieve this. Here is my code.
prompting: function () {
return this.prompt([{
type: 'input',
name: 'project_directory',
message: 'What is the project directory name?'
}, {
type: 'confirm',
name: 'archive',
message: 'That project already exists. Do you want to archive it?',
when: function (answers) {
var destDir = 'project/' + answers.project_directory.replace(/[^0-9a-zA-Z\-.]/g, "").toLowerCase();
var fso = new ActiveXObject("Scripting.FileSystemObject");
//Return true if the folder exists
return (fso.FolderExists(destDir));
}
}]).then(function (answers) {
}.bind(this));
}
Yeoman doesn't provide any built-in methods to verify if a file or a directory exists.
But Yeoman is just Node.js, it's just JavaScript.
So you actually want to ask how to detect if a directory exist with Node.
If you inherited from Generator, you have this.fs object that has exists() method.
module.exports = class extends Generator {
/* ... */
default() {
this.alreadyCopied = this.fs.exists(this.destination('myfile.txt'));
}
}
Actually, as mentioned by Simon Boudrias, Yeoman doesn't provide a built-in method for it, but you can do the following:
var Generator = require('yeoman-generator');
var fs = require('fs');
module.exports = class extends Generator{
checkIfFolderExists(){
fs.stat('YourDirectoryHere'), function(error, stats){
if(stats!=undefined && stats.isDirectory()){
// your directory already exists.
}else{
// create your directory.
}
}) ;
}
}

Ember Data belongsTo async relationship omitted from createRecord() save() serialization

Edit 11/16/14: Version Information
DEBUG: Ember : 1.7.0 ember-1.7.0.js:14463
DEBUG: Ember Data : 1.0.0-beta.10+canary.30d6bf849b ember-1.7.0.js:14463
DEBUG: Handlebars : 1.1.2 ember-1.7.0.js:14463
DEBUG: jQuery : 1.10.2
I'm beating my head against a wall trying to do something that I think should be fairly straightforward with ember and ember-data, but I haven't had any luck so far.
Essentially, I want to use server data to populate a <select> dropdown menu. When the form is submitted, a model should be created based on the data the user chooses to select. The model is then saved with ember data and forwarded to the server with the following format:
{
"File": {
"fileName":"the_name.txt",
"filePath":"/the/path",
"typeId": 13,
"versionId": 2
}
}
The problem is, the typeId and versionId are left out when the model relationship is defined as async like so:
App.File = DS.Model.extend({
type: DS.belongsTo('type', {async: true}),
version: DS.belongsTo('version', {async: true}),
fileName: DS.attr('string'),
filePath: DS.attr('string')
});
The part that is confusing me, and probably where my mistakes lie, is the controller:
App.FilesNewController = Ember.ObjectController.extend({
needs: ['files'],
uploadError: false,
// These properties will be given by the binding in the view to the
//<select> inputs.
selectedType: null,
selectedVersion: null,
files: Ember.computed.alias('controllers.files'),
actions: {
createFile: function() {
this.createFileHelper();
}
},
createFileHelper: function() {
var selectedType = this.get('selectedType');
var selectedVersion = this.get('selectedVersion');
var file = this.store.createRecord('file', {
fileName: 'the_name.txt',
filePath: '/the/path'
});
var gotDependencies = function(values) {
//////////////////////////////////////
// This only works when async: false
file.set('type', values[0])
.set('version', values[1]);
//////////////////////////////////////
var onSuccess = function() {
this.transitionToRoute('files');
}.bind(this);
var onFail = function() {
this.set('uploadError', true);
}.bind(this);
file.save().then(onSuccess, onFail);
}.bind(this);
Ember.RSVP.all([
selectedType,
selectedVersion
]).then(gotDependencies);
}
});
When async is set to false, ember handles createRecord().save() POST requests correctly.
When async is true, ember handles GET requests perfectly with multiple requests, but does NOT add the belongsTo relationships to the file JSON during createRecord().save(). Only the basic properties are serialized:
{"File":{"fileName":"the_name.txt","filePath":"/the/path"}}
I realize this question has been asked before but I have not found a satisfactory answer thus far and I have not found anything that suits my needs. So, how do I get the belongsTo relationship to serialize properly?
Just to be sure that everything is here, I will add the custom serialization I have so far:
App.ApplicationSerializer = DS.RESTSerializer.extend({
serializeIntoHash: function(data, type, record, options) {
var root = Ember.String.capitalize(type.typeKey);
data[root] = this.serialize(record, options);
},
keyForRelationship: function(key, type){
if (type === 'belongsTo') {
key += "Id";
}
if (type === 'hasMany') {
key += "Ids";
}
return key;
}
});
App.FileSerializer = App.ApplicationSerializer.extend(DS.EmbeddedRecordsMixin, {
attrs: {
type: { serialize: 'id' },
version: { serialize: 'id' }
}
});
And a select:
{{ view Ember.Select
contentBinding="controller.files.versions"
optionValuePath="content"
optionLabelPath="content.versionStr"
valueBinding="controller.selectedVersion"
id="selectVersion"
classNames="form-control"
prompt="-- Select Version --"}}
If necessary I will append the other routes and controllers (FilesRoute, FilesController, VersionsRoute, TypesRoute)
EDIT 11/16/14
I have a working solution (hack?) that I found based on information in two relevant threads:
1) How should async belongsTo relationships be serialized?
2) Does async belongsTo support related model assignment?
Essentially, all I had to do was move the Ember.RSVP.all() to after a get() on the properties:
createFileHelper: function() {
var selectedType = this.get('selectedType');
var selectedVersion = this.get('selectedVersion');
var file = this.store.createRecord('file', {
fileName: 'the_name.txt',
filePath: '/the/path',
type: null,
version: null
});
file.set('type', values[0])
.set('version', values[1]);
Ember.RSVP.all([
file.get('type'),
file.get('version')
]).then(function(values) {
var onSuccess = function() {
this.transitionToRoute('files');
}.bind(this);
var onFail = function() {
alert("failure");
this.set('uploadError', true);
}.bind(this);
file.save().then(onSuccess, onFail);
}.bind(this));
}
So I needed to get() the properties that were belongsTo relationships before I save the model. I don't know is whether this is a bug or not. Maybe someone with more knowledge about emberjs can help shed some light on that.
See the question for more details, but the generic answer that I worked for me when saving a model with a belongsTo relationship (and you specifically need that relationship to be serialized) is to call .get() on the properties and then save() them in then().
It boils down to this:
var file = this.store.createRecord('file', {
fileName: 'the_name.txt',
filePath: '/the/path',
type: null,
version: null
});
// belongsTo set() here
file.set('type', selectedType)
.set('version', selectedVersion);
Ember.RSVP.all([
file.get('type'),
file.get('version')
]).then(function(values) {
var onSuccess = function() {
this.transitionToRoute('files');
}.bind(this);
var onFail = function() {
alert("failure");
this.set('uploadError', true);
}.bind(this);
// Save inside then() after I call get() on promises
file.save().then(onSuccess, onFail);
}.bind(this));

Gulp prompt to decide which tasks to run?

I have just discovered the gulp-prompt task. While it makes it easy to prompt the user in different ways, the examples don't hint at how to make use of the user's input. For instance I would like to offer two setups (e.g. CDN-hosted or local assets) to the user and run my tasks conditionally. How can you do that in Gulp? This could save me from looking into a Yeoman generator.
Exemple
...
...
var inject = require('gulp-inject');
var cdnizer = require('gulp-cdnizer');
gulp.task('mytask', function(){
var target = gulp.src('./src/index.html');
return gulp.src('*')
.pipe(prompt.prompt({
type: 'input',
name: 'type',
message: 'What you like to do? [cdn/assets]'
}, function(res){
var sources;
if(res.type === 'cdn'){
sources = ...
target.pipe(inject(sources))
.pipe(gulp.dest('./src'));
}else{
target.pipe(cdnizer({...});
}
}));
});
This is another implementation. It will ask you to choose the task with a keyboard
gulp.task('default', function() {
var taskNames = [];
for (var taskName in gulp.tasks) {
if (gulp.tasks.hasOwnProperty(taskName)) {
taskNames.push(taskName);
}
}
return gulp.src('*').pipe(
prompt.prompt({
type: 'checkbox',
name: 'tasks',
message: 'Choose task name',
choices: taskNames
}, function(res){
//value is in res.task (the name option gives the key)
console.log(res);
res.tasks.forEach(function(taskName){
console.log(taskName);
gulp.tasks[taskName].fn();
});
}));
});

Categories