Skip to content

Commit

Permalink
feat(cli): Add generators for new Knex SQL database adapter (#2673)
Browse files Browse the repository at this point in the history
  • Loading branch information
daffl authored Jun 21, 2022
1 parent 9380fff commit 0fb2c0f
Show file tree
Hide file tree
Showing 26 changed files with 806 additions and 499 deletions.
402 changes: 194 additions & 208 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,14 @@
"url": "https://github.com/feathersjs/feathers/issues"
},
"engines": {
"node": ">= 12"
"node": ">= 14"
},
"scripts": {
"install": "lerna bootstrap",
"publish": "lerna publish && git commit -am \"chore: Update changelog\" && git push origin",
"publish:premajor": "lerna publish premajor --preid pre --pre-dist-tag pre && git commit -am \"chore: Update version and changelog\" && git push origin",
"publish:prerelease": "lerna publish prerelease --preid pre --pre-dist-tag pre --dist-tag pre --force-publish && git commit -am \"chore: Update version and changelog\" && git push origin",
"prettier": "npx prettier \"packages/{,!(node_modules)/**/(src|test|generators)/**/}*.ts\" --write",
"prettier": "npx prettier \"packages/{,!(node_modules)/**/(src|test)/**/}*.ts\" --write",
"eslint": "eslint \"packages/**/*.ts\" --fix",
"lint": "npm run prettier && npm run eslint",
"update-dependencies": "ncu -u && lerna exec -- ncu -u -x node-fetch",
Expand Down
3 changes: 2 additions & 1 deletion packages/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
"access": "public"
},
"dependencies": {
"@feathershq/pinion": "^0.3.1",
"@feathershq/pinion": "^0.3.3",
"chalk": "^4.0.1",
"lodash": "^4.17.21",
"prettier": "^2.7.1"
Expand All @@ -69,6 +69,7 @@
"@feathersjs/feathers": "^5.0.0-pre.22",
"@feathersjs/koa": "^5.0.0-pre.22",
"@feathersjs/mongodb": "^5.0.0-pre.22",
"@feathersjs/knex": "^5.0.0-pre.22",
"@feathersjs/schema": "^5.0.0-pre.22",
"@feathersjs/socketio": "^5.0.0-pre.22",
"@feathersjs/transport-commons": "^5.0.0-pre.22",
Expand Down
97 changes: 17 additions & 80 deletions packages/cli/src/app/index.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,18 @@
import { sep, join } from 'path'
import { PackageJson } from 'type-fest'
import { sep } from 'path'
import chalk from 'chalk'
import {
generator,
prompt,
runGenerators,
loadJSON,
fromFile,
install,
copyFiles,
toFile,
when
} from '@feathershq/pinion'
import { FeathersBaseContext, FeathersAppInfo, initializeBaseContext } from '../commons'
import { generate as authenticationGenerator } from '../authentication'
import { generate as connectionGenerator } from '../connection'

export type DependencyVersions = { [key: string]: string }

const addVersions = (dependencies: string[], versions: DependencyVersions) =>
dependencies.map((dep) => `${dep}@${versions[dep] ? versions[dep] : 'latest'}`)
import { FeathersBaseContext, FeathersAppInfo, initializeBaseContext, addVersions } from '../commons'
import { generate as authenticationGenerator, prompts as authenticationPrompts } from '../authentication'
import { generate as connectionGenerator, prompts as connectionPrompts } from '../connection'

export interface AppGeneratorData extends FeathersAppInfo {
/**
Expand All @@ -42,11 +35,6 @@ export interface AppGeneratorData extends FeathersAppInfo {
* The source folder where files are put
*/
lib: string
/**
* A list dependencies that should be installed with a certain version.
* Used for installing development dependencies during testing.
*/
dependencyVersions?: DependencyVersions
}

export type AppGeneratorContext = FeathersBaseContext &
Expand All @@ -59,16 +47,11 @@ export type AppGeneratorArguments = FeathersBaseContext & Partial<AppGeneratorDa

export const generate = (ctx: AppGeneratorArguments) =>
generator(ctx)
.then(
loadJSON(join(__dirname, '..', '..', 'package.json'), (pkg: PackageJson) => ({
dependencyVersions: {
...pkg.devDependencies,
...ctx.dependencyVersions
},
dependencies: [],
devDependencies: []
}))
)
.then((ctx) => ({
...ctx,
dependencies: [],
devDependencies: []
}))
.then(
prompt<AppGeneratorArguments, AppGeneratorContext>((ctx) => [
{
Expand Down Expand Up @@ -124,66 +107,20 @@ export const generate = (ctx: AppGeneratorArguments) =>
{ value: 'yarn', name: 'Yarn' }
]
},
{
name: 'database',
type: 'list',
when: !ctx.database,
message: 'What is your main database?',
suffix: chalk.grey(' Other databases can be added at any time'),
choices: [
{ value: 'mongodb', name: 'MongoDB' },
{ value: 'knex', name: 'SQL (PostgreSQL, SQLite etc.)', disabled: true }
]
},
{
name: 'connectionString',
type: 'input',
when: (answers: AppGeneratorArguments) => !ctx.connectionString && answers.database !== 'custom',
message: 'Enter your database connection string',
default: (answers: AppGeneratorArguments) => `mongodb://localhost:27017/${answers.name}`
},
{
type: 'checkbox',
name: 'authStrategies',
when: !ctx.authStrategies,
message: 'Which user authentication methods do you want to use?',
suffix: chalk.grey(' Other methods and providers can be added at any time.'),
choices: [
{
name: 'Email + Password',
value: 'local',
checked: true
},
{
name: 'Google',
value: 'google'
},
{
name: 'Facebook',
value: 'facebook'
},
{
name: 'Twitter',
value: 'twitter'
},
{
name: 'GitHub',
value: 'github'
},
{
name: 'Auth0',
value: 'auth0'
}
]
}
...connectionPrompts(ctx),
...authenticationPrompts({
...ctx,
service: 'users',
entity: 'user'
})
])
)
.then(runGenerators(__dirname, 'templates'))
.then(copyFiles(fromFile(__dirname, 'static'), toFile('.')))
.then(initializeBaseContext())
.then(
when<AppGeneratorContext>(
({ authStrategies, database }) => authStrategies.length > 0 && database !== 'custom',
({ authStrategies }) => authStrategies.length > 0,
async (ctx) => {
const { dependencies } = await connectionGenerator(ctx)

Expand Down Expand Up @@ -242,7 +179,7 @@ export const generate = (ctx: AppGeneratorArguments) =>
)
.then(
install<AppGeneratorContext>(({ language, framework, devDependencies, dependencyVersions }) => {
devDependencies.push('nodemon', 'axios', 'mocha')
devDependencies.push('nodemon', 'axios', 'mocha', 'cross-env')

if (language === 'ts') {
devDependencies.push(
Expand Down
1 change: 1 addition & 0 deletions packages/cli/src/app/static/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -116,5 +116,6 @@ dist
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*
.sqlite

lib/
4 changes: 2 additions & 2 deletions packages/cli/src/app/templates/channels.tpl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { generator, toFile } from '@feathershq/pinion'
import { renderSource } from '../../commons'
import { AppGeneratorContext } from '../index'

const template = ({}: AppGeneratorContext) =>
const template = ({ language }: AppGeneratorContext) =>
`import '@feathersjs/transport-commons'
import type { Application, HookContext } from './declarations'
import { logger } from './logger'
Expand All @@ -13,7 +13,7 @@ export const channels = (app: Application) => {
return
}
logger.warn('Publishing all events to all authenticated users. See \`channels.js\` and https://docs.feathersjs.com/api/channels.html for more information.')
logger.warn('Publishing all events to all authenticated users. See \`channels.${language}\` and https://docs.feathersjs.com/api/channels.html for more information.')
app.on('connection', (connection: any) => {
// On a new real-time connection, add it to the anonymous channel
Expand Down
1 change: 0 additions & 1 deletion packages/cli/src/app/templates/config.tpl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ const defaultConfig = ({}: AppGeneratorContext) => ({
host: 'localhost',
port: 3030,
public: './public/',
database: 'type://yourconnectionstring',
paginate: {
default: 10,
max: 50
Expand Down
3 changes: 1 addition & 2 deletions packages/cli/src/app/templates/configuration.tpl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,11 @@ export const configurationSchema = schema({
$id: 'ApplicationConfiguration',
type: 'object',
additionalProperties: false,
required: [ 'database', 'host', 'port', 'public', 'paginate' ],
required: [ 'host', 'port', 'public', 'paginate' ],
properties: {
host: { type: 'string' },
port: { type: 'number' },
public: { type: 'string' },
database: { type: 'string' },
authentication: authenticationSettingsSchema,
paginate: {
type: 'object',
Expand Down
7 changes: 5 additions & 2 deletions packages/cli/src/app/templates/package.json.tpl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ const jsPackageJson = (lib: string) => ({
scripts: {
start: `node ${lib}`,
dev: `nodemon ${lib}/`,
test: 'mocha test/ --recursive --exit'
mocha: 'cross-env NODE_ENV=test mocha test/ --recursive --exit',
test: 'npm run mocha'
}
})

Expand All @@ -15,7 +16,9 @@ const tsPackageJson = (lib: string) => ({
dev: `nodemon -x ts-node ${lib}/index.ts`,
compile: 'shx rm -rf dist/ && tsc',
start: 'npm run compile && node dist/',
test: 'mocha test/ --require ts-node/register --recursive --extension .ts --exit'
mocha:
'cross-env NODE_ENV=test mocha test/ --require ts-node/register --recursive --extension .ts --exit',
test: 'npm run mocha'
}
})

Expand Down
114 changes: 56 additions & 58 deletions packages/cli/src/authentication/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import chalk from 'chalk'
import { generator, runGenerators, prompt, install } from '@feathershq/pinion'
import { FeathersBaseContext } from '../commons'
import { addVersions, FeathersBaseContext, getDatabaseAdapter } from '../commons'
import { generate as serviceGenerator, ServiceGeneratorContext } from '../service/index'

export interface AuthenticationGeneratorContext extends ServiceGeneratorContext {
Expand All @@ -13,68 +13,68 @@ export interface AuthenticationGeneratorContext extends ServiceGeneratorContext
export type AuthenticationGeneratorArguments = FeathersBaseContext &
Partial<Pick<AuthenticationGeneratorContext, 'service' | 'authStrategies' | 'entity'>>

export const prompts = (ctx: AuthenticationGeneratorArguments) => [
{
type: 'checkbox',
name: 'authStrategies',
when: !ctx.authStrategies,
message: 'Which authentication methods do you want to use?',
suffix: chalk.grey(' Other methods and providers can be added at any time.'),
choices: [
{
name: 'Email + Password',
value: 'local',
checked: true
},
{
name: 'Google',
value: 'google'
},
{
name: 'Facebook',
value: 'facebook'
},
{
name: 'Twitter',
value: 'twitter'
},
{
name: 'GitHub',
value: 'github'
},
{
name: 'Auth0',
value: 'auth0'
}
]
},
{
name: 'service',
type: 'input',
when: !ctx.service,
message: 'What is your authentication service name?',
default: 'users'
},
{
name: 'entity',
type: 'input',
when: !ctx.entity,
message: 'What is your authenticated entity name?',
suffix: chalk.grey(' Will be available in params (e.g. params.user)'),
default: 'user'
}
]

export const generate = (ctx: AuthenticationGeneratorArguments) =>
generator(ctx)
.then(
prompt<AuthenticationGeneratorArguments, AuthenticationGeneratorContext>((ctx) => [
{
type: 'checkbox',
name: 'authStrategies',
when: !ctx.authStrategies,
message: 'Which authentication methods do you want to use?',
suffix: chalk.grey(' Other methods and providers can be added at any time.'),
choices: [
{
name: 'Email + Password',
value: 'local',
checked: true
},
{
name: 'Google',
value: 'google'
},
{
name: 'Facebook',
value: 'facebook'
},
{
name: 'Twitter',
value: 'twitter'
},
{
name: 'GitHub',
value: 'github'
},
{
name: 'Auth0',
value: 'auth0'
}
]
},
{
name: 'service',
type: 'input',
when: !ctx.service,
message: 'What is your authentication service name?',
default: 'users'
},
{
name: 'entity',
type: 'input',
when: !ctx.entity,
message: 'What is your authenticated entity name?',
suffix: chalk.grey(' Will be available in params (e.g. params.user)'),
default: 'user'
}
])
)
.then(prompt<AuthenticationGeneratorArguments, AuthenticationGeneratorContext>(prompts))
.then(async (ctx) => {
const serviceContext = await serviceGenerator({
...ctx,
name: ctx.service,
path: ctx.service,
isEntityService: true,
type: ctx.feathers.database
type: getDatabaseAdapter(ctx.feathers.database)
})

return {
Expand All @@ -99,7 +99,5 @@ export const generate = (ctx: AuthenticationGeneratorArguments) =>
}
}

const installer = install<AuthenticationGeneratorContext>(dependencies)

return installer(ctx)
return install<AuthenticationGeneratorContext>(addVersions(dependencies, ctx.dependencyVersions))(ctx)
})
Loading

0 comments on commit 0fb2c0f

Please # to comment.