@vida-global/scaffold
v1.0.1
Published
Installs a Vida package's files into a service and generates controllers and models
Keywords
Readme
@vida-global/scaffold
Two commands a Vida service runs to put new files in place. vida:install copies
a package's files out of node_modules and into the service. vida:generate
writes a new controller or a new model.
Both commands resolve every path from the directory the npm script runs in, which is the service.
Install
Add the two scripts to the service package.json:
"vida:install": "node node_modules/@vida-global/scaffold/scripts/install.js",
"vida:generate": "node node_modules/@vida-global/scaffold/scripts/generate.js",vida:install takes an argument, and npm run needs -- before it. Without
the -- npm keeps the argument and the command sees nothing. vida:generate
takes no arguments and asks its questions instead.
vida:install
npm run vida:install -- oauth
npm run vida:install -- oauth --databaseId billingTakes the package name without its scope. The command adds @vida-global/ and
reads node_modules/@vida-global/oauth.
Copies four directories from the root of the installed package:
| In the package | In the service |
|---|---|
| config/db/migrations/ | config/db/migrations/ |
| models/ | models/ |
| controllers/ | controllers/ |
| lib/controllers/ | lib/controllers/ |
Models, controllers and mixins keep their paths. A file the service already has is left alone.
A migration is renamed on the way in, to <timestamp>_<name>_<hash>.js. The
timestamp is the time of the run, stepped by one for each later file, so the
package's own order survives and the migrations sort after everything already in
the service. The hash is eight characters of a SHA-256 of the package name and
the source file name, and it is how a second run recognises a migration it has
already copied. Renaming a copied migration by hand breaks that check.
--databaseId adds the segment core reads to pick a named database connection.
The command prints the files it created and the files it skipped. It does not
run the migrations. Run npm run db:migrate yourself.
Nothing else is wired up for you. A copied model is not added to
models/index.js, and no permission rule is added to lib/server/authorizer.js.
Shipping files from a package
Put the four directories in the package at the paths in the table above.
Migrations go in config/db/migrations, which is where npm run
db:create-migration writes them in a package as well as in a service.
Everything in those directories is published unless .npmignore excludes it.
A shipped controller must require the service's base class. Write
require('../lib/server') and extend AbstractController, counting the ../
steps for the path the controller lands in. That works in any fork of
node-service-template.
Adding behavior to the base controller
lib/server/abstractController.js belongs to the service, and every package
installed into that service would want to change the same file. So the command
does not copy it, and a package must not ship one.
Export a mixin object instead, holding any of InstanceMethods,
StaticMethods, Accessors and StaticAccessors. The service then adds one
line to its own base controller:
AbstractController.loadMixin(require('@vida-global/oauth').controllerMixin);loadMixin is a static on VidaServerController, which core already uses on
itself to attach callbacks, routing and validation. Several packages can each
add their own line, and the service decides which ones it wants.
Adding that line is a manual step. Say so in the package README, because
vida:install will not mention it.
vida:generate
npm run vida:generateTakes no arguments. It asks for what it needs, one question at a time:
What do you want to generate? [controller, model] model
Model class name, for example PbxProfile: PbxProfile
Add CRUD endpoints for it? [y, n] y
Directory under controllers, blank for the root: api/v2/sipA controller answer asks only for the path and name under controllers, such
as api/v2/sip/pbxProfiles. The last segment becomes the class name, so that
one writes PbxProfilesController, its mixin, and its test.
A model answer writes the model, its test, and a migration holding an empty
createTable call with the table name filled in. Saying yes to CRUD adds a
controller with the five actions, its mixin, and its test.
Because every answer is typed, this command cannot run unattended. There is no flag form.
The generated queries filter nothing. list<Model> returns every row in the
table and fetch<Model> finds a row by its id alone. The command has no field
list, so it cannot know what either one should be limited to. Add that to the
mixin before the endpoints serve traffic.
A file the service already has is left alone, and the rest are still written. Both commands print the files they created and the files they skipped.
A migration carries the time it was written, so a second run can never match the first one by name. A model run looks for a migration whose description already matches the model and reuses that name, which is what lets a second run leave it alone.
Layout
scripts/install.js entry point for vida:install
scripts/generate.js entry point for vida:generate
lib/install/ copies a package's files into the service
lib/generate/ writes new controller and model files
lib/conventions/ derives class names, file names and table names
lib/prompt/ asks the questions vida:generate needs answered
lib/report/ what a command created and skipped, and how it prints
lib/templates/ the text of every emitted file
test/ mirrors lib/