sails generate <something>: where are the docs on 'generate'? - node.js

sails generate controller <name> and model and api and others.
What are the others? What are the options? What are the commandline options?
Insert here the obligatory "I've websearched high and low" but the only thing I can come up with is github entries for individual generators in various states of ignorement.
So, abstractly, where's the documentation on the generate command?

The default generators shipped with Sails are documented here, in the command line interface section of the reference section of the Sails documentation. Where options are accepted I believe this section of the documentation references them, with sails new having the most option usage options.
At the time of writing they include new, api, model, controller, adapter, and generator.
More community created generators can be added, generally by modifying the .sailsrc file to include npm package. Here's an example from the sails-auth docs.
{
"generators": {
"modules": {
"auth-api": "sails-auth"
}
}
}
If you want to know more about making your own generators and what goes into that you'd probably want to check out the sails-generate-generator repo and docs.

Related

No code suggestions for global defined variables in VSCode in a node.js server project

I have to deal with a node.js server project that uses global variables for common APIs. For instance in the entry point server.js there is a Firebase variable for the real-time database that is stored like this:
fireDB = admin.database();
I wasn't aware that this is possible and I would consider this a bad approach, but now I have to deal with it.
I'm not really interested to re-write any of the many calls to this variable in all those files, rather I would find a way to make fireDB show me suggestions only by changing this variable or installing an extension.
I tried to define it on top of the file as var fireDB, but then suggestions only work in the same file, not in others.
When I set a dot behind admin.database() the suggestions work, when I write fireDB. I get no suggestions, yet the call seems to be possible. Suggestions need to work in other files, too. How can I get this to work?
WARNING: MAKE SURE YOU UNDERSTAND THE PROBLEMS WITH GLOBALS BEFORE USING THEM IN A PROJECT
The above warning/disclaimer is mostly for anyone starting a new project that might happen across this answer.
With that out of the way, create a new .d.ts file and put it somewhere with a descriptive name. For example, globals.d.ts at the top level of the directory. Then just populate it with the following (I don't have any experience with firebase, so I had to make some assumptions about which module you're using, etc.):
globals.d.ts
import { database } from "firebase-admin";
declare global {
var fireDB: database.Database;
}
IntelliSense should then recognize fireDB as a global of the appropriate type in the rest of your JavaScript project.
Why does this work? IntelliSense uses TypeScript even if you're working with a JS project. Many popular JS packages includes a .d.ts file where typings are declared, which allows IntelliSense to suggest something useful when you type require('firebase-admin').database(), for example.
IntelliSense will also automatically create typings internally when you do something "obvious", e.g. with literals:
const MY_OBJ = { a: 1, b: "hello"};
MY_OBJ. // IntelliSense can already autocomplete properties "a" and "b" here
Global autocompletion isn't one of those "obvious" things, however, probably because of all the problems with global variables. I'd also guess it'd be difficult to efficiently know what order your files will run in (and hence when a global might be declared). Thus, you need to explicitly declare your global typings.
If you're interested in further augmenting the capabilities of IntelliSense within your JS project, you can also use comments to explicitly create typings:
/**
* #param {String[]} arrayOfStrings
*/
function asAnExample(arrayOfStrings) {
arrayOfStrings. // IntelliSense recognizes this as an array and will provide suggestions for it
}
See this TypeScript JSDoc reference for more on that.

How to modify NodeJS built-in global objects?

I'd like to add an important functionality that I can use at work without using require() every time. So, I thought modifying built-in objects can make this happen but I could not locate the locations of those objects to do the modification.
Are those objects in NodeJS binary? Would that mean I have to fork the whole NodeJS repo to make this happen?
Please, I don't want to use prototype editing etc which are same as require. I need to have native feeling.
First off, I agree with an earlier comment that this sounds like a bit of an XY problem where we could better help you if you describe what problem you're really trying to solve. Portable node.js programs that work anywhere or work with any future versions of node.js don't rely on some sort of custom configured environment in order to run. They use the built-in capabilities of node.js and they require/import in external things they want to add to the environment.
Are those objects in NodeJS binary?
Yes, they are in the executable.
Would that mean I have to fork the whole NodeJS repo to make this happen?
Yes.
Please, I don't want to use prototype editing etc which are same as require. I need to have native feeling.
"Native feeling"? This sounds like you haven't really bought into the node.js module architecture. It is different than many other environments. It's easy to get used to over time. IMO, it would really be better to go with the flow and architecture of the platform rather than make some custom version of node.js just to save one line of typing in your startup code.
And, the whole concept of adding a number of globals you can use anywhere pretty much shows that you haven't fully understood the design, architectural, code reuse and testability advantages of the module design baked into node.js. If you had, you wouldn't be trying to write a lot of code that can't be reused in other ways that you don't anticipate now.
That said, in searching through the node.js source code on Github, I found this source file node.js which is where lots of things are added to the node.js global object such as setTimeout(), clearTimeout(), setImmediate(), clearImmediate() and so on. So, that source file seems to be where node.js is setting up the global object. If you wanted to add your own things there, that's one place where it would be done.
To provide a sample of that code (you can see the link above for the complete code):
if (!config.noBrowserGlobals) {
// Override global console from the one provided by the VM
// to the one implemented by Node.js
// https://console.spec.whatwg.org/#console-namespace
exposeNamespace(global, 'console', createGlobalConsole(global.console));
const { URL, URLSearchParams } = require('internal/url');
// https://url.spec.whatwg.org/#url
exposeInterface(global, 'URL', URL);
// https://url.spec.whatwg.org/#urlsearchparams
exposeInterface(global, 'URLSearchParams', URLSearchParams);
const {
TextEncoder, TextDecoder
} = require('internal/encoding');
// https://encoding.spec.whatwg.org/#textencoder
exposeInterface(global, 'TextEncoder', TextEncoder);
// https://encoding.spec.whatwg.org/#textdecoder
exposeInterface(global, 'TextDecoder', TextDecoder);
// https://html.spec.whatwg.org/multipage/webappapis.html#windoworworkerglobalscope
const timers = require('timers');
defineOperation(global, 'clearInterval', timers.clearInterval);
defineOperation(global, 'clearTimeout', timers.clearTimeout);
defineOperation(global, 'setInterval', timers.setInterval);
defineOperation(global, 'setTimeout', timers.setTimeout);
defineOperation(global, 'queueMicrotask', queueMicrotask);
// Non-standard extensions:
defineOperation(global, 'clearImmediate', timers.clearImmediate);
defineOperation(global, 'setImmediate', timers.setImmediate);
}
This code is built into the node.js executable so the only way I know of to directly modify it (without hackish patching of the executable itself) would be to modify the file and then rebuild node.js for your platform into a custom build.
On a little more practical note, you can also use the -r module command line argument to tell node.js to run require(module) before starting your main script. So, you could make a different way of starting node.js from a shell file that always passes the -r fullPathToYourModule argument to node.js so it will always run your startup module that adds things to the global object.
Again, you'd be doing this just to save one line of typing in your startup file. It is really worth doing that?

Creating JHipster blueprint to extend the field type prompt

I have already created a test blueprint that works, so I kinda got the idea, but I would like to make sure that I am approaching this correctly.
I want to extend the field type prompt to offer custom types alongside String, int, boolean etc.
This means I need to modify the templates, like templates/src/main/java/package/domain/Entity.java.ejs
My blueprint only had generators/client and generators/entity-client, so I guess I have to:
create generators/entity-server
create index.js
create files.js (can I copy that from here https://github.com/jhipster/generator-jhipster/blob/master/generators/entity-server/files.js ?)
create the templates in entity-server/templates
create generators/entity
copy and modify generators/entity/prompts.js: do I have to just write a new prompts.js, or do I have to copy over everything in generators/entity and only change what I would like to change ?
For the templates, can I copy them from the JHipster repo ?
Should I ? If not, why not and what is the alternative ?
If copying them is the right move, do I have to copy everything ? Or just the ones I want to modify ? (I haven't checked yet if I will need to modify everything)
When JHipster is updated, I suppose either I manually merge the new files, or I risk that slowly my code will differ more and more from the JHipster code ?
Is there a simpler method to achieve what I am trying to do ?
It would be nice if I could just say I want to add TypeX and TypeY to that prompt and provide limited templates that only cover those types, like a template for the import, one for the field, and one for the setter and getter, and if only the import is provided, a generic template is used.
I'll try to answer to all your questions.
First to create Blueprint I suggest to use https://github.com/jhipster/generator-jhipster-blueprint even in another folder and copy all you need for your current project. I think it's easier and you could choose which generator you want to add e.g. entity-server and entity.
Prompts phase
If you want to modify prompt phase you can merge your phase with the JHipster one like that
get prompting() {
const phaseFromJHipster = super._prompting();
const phaseFromMe = {
askForTheme: prompts.askForTheme,
setMySharedConfigOptions() {
this.configOptions.theme = this.theme;
}
};
return { ...phaseFromJHipster, ...phaseFromMe };
}
(source: https://github.com/avdev4j/samSuffit/tree/master/generators/client)
But by doing this you can't modify existing questions, for this case you should copy all existing questions into your blueprint.
Templates management
Your blueprint is linked with a JHipster version. As I used to say (in my talks) is that you should copy and modify templates from JHipster except for configuration files because it's a bit tricky to handle. For them, I prefer to use JHipster API like 'replaceContent()' or the needle API which allowed you to insert some code into some files (like a dependency in the pom.xml file).
Of course you can use the way you want, but with experiences I prefer to control my templates and merge them when I upgrade the JHipster version.
You should only copy the templates you want to modify, merge JHipster and your writing phase. JHipster use yeoman, which use memfs to handle file generation. Every files are created in memory and dumped at the final step. You can easily override a file without performance compromise.
get writing() {
const phaseFromJHipster = super._writing();
/* eslint-disable */
const phaseFromSam = {
writeSamFiles() {
if (this.clientFramework === 'angularX') {
return writeAngularFiles.call(this);
}
}
};
/* eslint-enable */
return { ...phaseFromJHipster, ...phaseFromSam };
}
JHipster upgrade
I suggest you to check templates when upgrading JHipster and apply modifications if needed. Otherwise, you could have bugs. Also, I suggest to set a definitive (like 6.1.0) version of JHipster in your blueprint package.json.
As far I know there is no way to do what you want to do. I'm thinking of a way to modify prompts easily without copying all other questions, if you want to contribute ;).
You can check my blueprint sample I use to show in my talks:
https://github.com/avdev4j/samSuffit/
I hope It can help you can, feel free to ask more.
regards,

Best way to define custom functions in loopback api

What is the best way to define custom functions in loopback api that can be used in models defined ?
For example a basic express application can have functions in helper folder on root directory, but doing same in loopback is not recommended and does not maintain loopback way.
Any help would be highly appreciated.
This is very well documented.
Custom logic can be placed in
boot scripts
middlewares
models:
remote methods
remote hooks
operation hooks
application-decoupled logic can very well be put in helper folders, separate folders at root level, etc. There is nothing wrong with modularizing your program this way, it is actually a good thing.
As mentioned by others, the Loopback documentation answers your question like this:
Adding logic to models - adding remote methods, remote hooks and operation hooks.
Defining boot scripts - writing scripts (in the /server/boot directory) that run when the application starts.
Defining middleware - adding custom middleware to the application .
That's a great answer if you have custom functions for a particular model, boot script, or middleware. And as Dharmendra Yadav said, mixins can be another option:
You can use mixins to perform different common actions on models such as observing changes using operation hooks and adding model attributes.
But what about code that simply doesn't fit into any of those categories?
I don't have experience with a lot of web frameworks, but one framework I have used is Grails, which is very opinionated and gives you a place for just about everything. And if your code doesn't fit into any of those categories, they give you a place for that too:
src/main/groovy - Supporting sources
So when I ran into this same problem in Loopback, I just created a src directory under server and that's where I put some helper classes that don't seem to fit anywhere else. And I include them as needed:
const HelperClass = require('../src/HelperClass');
HelperClass.helperFunction()...
Of course you can name the folder however you'd like: src, helpers, support, whatever. And then put it under common or server as appropriate.
The best way to define functions in loopback i found is to use mixins. Here is the sample way of doing so..
https://loopback.io/doc/en/lb3/Defining-mixins.html
You can inherit these defined mixins into your models through .json of your model with {mixins:yourmixin.js}, nice and easy.
Here's some sample code to get you headed in the right direction.
mynewmodel.js
http://domain/api/mynewmodel/myfunc.js
function myfunc(data, callback) {
// ** Put your code here **
console.log('myfunc');
}
function remoteMethod(model) {
model.remoteMethod(
'myfunc',
{
http: { verb: 'post' },
accepts: { arg: 'data', type: 'data' },
returns: [
{ arg: 'returndata', type: 'data' }
]
}
)
}
UPDATE
Generally your js files go in common/models

Swap out repositories with a flag

I have an IRepository< T > interface with many T's and several implementations (on-demand DB, web service, etc.). I use AutoFac to register IRepository's for many T's depending on the kind of repository I want for each T.
I also have a .NET-caching-based implementation that looks for T's in cache and then calls a 'real' IRepository.Find to resolve a cache miss. It is constructed something like this:
new CachingRepository(realRepository, cacheImplementation);
I would like to use a configuration flag to decide if AutoFac serves up caching-based IRepository's or the 'real things.' It seems like 'realRepository' comes from asking AutoFac to resolve IRepository < T > but then what do clients get when they ask to resolve the same interface? I want them to get the CachingRepository if the flag is set.
I can't get my head around how to implement this flag-based resolution. Any ideas?
Simplest Option: Conditional Registration Delegate
There are a number of ways to do this. Using your cache setting in a registration delegate is probably the simplest (and illustrates the power of delegate registrations):
var builder = new ContainerBuilder();
bool cache = GetCacheConfigSetting(); //Up to you where this setting is.
builder.Register(c => cache ? (IRepository<string>)new CachingRepository<string>(new RealRepos<string>(), new CacheImpl()) : new RealRepos<string>());
The code above will only read the cache config once. You could also include the GetCacheConfigSetting() in the registration delegate. This would result in the setting being checked on every Resolve (assuming InstancePerDependency).
Other Options: Autofac Decorators and Modules
There are some more advanced features of Autofac that you may also find useful. The cache class in your question is an example of the Decorator Pattern. Autofac has explicit support for decorators. It also has a nice model for structuring your registrations and managing configuration information, called Modules.

Resources