Skip to content

Commit

Permalink
feat(cli): Add support for Prettier (#2684)
Browse files Browse the repository at this point in the history
  • Loading branch information
daffl authored Jul 3, 2022
1 parent d114557 commit 83aa8f9
Show file tree
Hide file tree
Showing 7 changed files with 97 additions and 34 deletions.
2 changes: 1 addition & 1 deletion packages/cli/src/app/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ export const generate = (ctx: AppGeneratorArguments) =>
)
.then(
install<AppGeneratorContext>(({ language, framework, devDependencies, dependencyVersions }) => {
devDependencies.push('nodemon', 'axios', 'mocha', 'cross-env')
devDependencies.push('nodemon', 'axios', 'mocha', 'cross-env', 'prettier')

if (language === 'ts') {
devDependencies.push(
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/app/templates/client.tpl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ const template = ({}: AppGeneratorContext) =>
`import { feathers } from '@feathersjs/feathers'
import type { Service, TransportConnection, Params } from '@feathersjs/feathers'
// A mapping of client side services
export interface ServiceTypes {
// A mapping of client side services
}
export const createClient = <Configuration = any> (connection: TransportConnection<ServiceTypes>) => {
Expand Down
2 changes: 2 additions & 0 deletions packages/cli/src/app/templates/package.json.tpl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const jsPackageJson = (lib: string) => ({
scripts: {
start: `node ${lib}`,
dev: `nodemon ${lib}/`,
prettier: 'npx prettier "**/*.js" --write',
mocha: 'cross-env NODE_ENV=test mocha test/ --recursive --exit',
test: 'npm run mocha'
}
Expand All @@ -16,6 +17,7 @@ const tsPackageJson = (lib: string) => ({
dev: `nodemon -x ts-node ${lib}/index.ts`,
compile: 'shx rm -rf lib/ && tsc',
start: 'npm run compile && node lib/',
prettier: 'npx prettier "**/*.ts" --write',
mocha:
'cross-env NODE_ENV=test mocha test/ --require ts-node/register --recursive --extension .ts --exit',
test: 'npm run mocha'
Expand Down
14 changes: 14 additions & 0 deletions packages/cli/src/app/templates/prettierrc.tpl.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { generator, toFile, writeJSON } from '@feathershq/pinion'
import { AppGeneratorContext } from '../index'
import { PRETTIERRC } from '../../commons'

export const generate = (ctx: AppGeneratorContext) =>
generator(ctx).then(
writeJSON<AppGeneratorContext>(
(ctx) => ({
...PRETTIERRC,
parser: ctx.language === 'ts' ? 'typescript' : 'babel'
}),
toFile('.prettierrc')
)
)
76 changes: 61 additions & 15 deletions packages/cli/src/commons.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { PackageJson } from 'type-fest'
import { readFile, writeFile } from 'fs/promises'
import {
Callable,
PinionContext,
Expand All @@ -10,7 +11,7 @@ import {
Location
} from '@feathershq/pinion'
import * as ts from 'typescript'
import prettier from 'prettier'
import prettier, { Options as PrettierOptions } from 'prettier'
import path from 'path'

export type DependencyVersions = { [key: string]: string }
Expand Down Expand Up @@ -144,35 +145,80 @@ export const getJavaScript = (typescript: string, options: ts.TranspileOptions =
...options.compilerOptions
}
})
const code = fixLocalImports(restoreNewLines(transpiled.outputText))

return prettier.format(code, {
semi: false,
parser: 'babel',
singleQuote: true
})
return fixLocalImports(restoreNewLines(transpiled.outputText))
}

const getFileName = async <C extends PinionContext & { language: 'js' | 'ts' }>(
target: Callable<string, C>,
ctx: C
) => `${await getCallable(target, ctx)}.${ctx.language}`

/**
* The default configuration for prettifying files
*/
export const PRETTIERRC: PrettierOptions = {
tabWidth: 2,
useTabs: false,
printWidth: 110,
semi: false,
trailingComma: 'none',
singleQuote: true
}

/*
* Format a source file using Prettier. Will use the local configuration, the settings set in
* `options` or a default configuration
*
* @param target The file to prettify
* @param options The Prettier options
* @returns The updated context
*/
export const prettify =
<C extends PinionContext & { language: 'js' | 'ts' }>(
target: Callable<string, C>,
options: PrettierOptions = PRETTIERRC
) =>
async (ctx: C) => {
const fileName = await getFileName(target, ctx)
const config = (await prettier.resolveConfig(ctx.cwd)) || options
const content = (await readFile(fileName)).toString()

try {
await writeFile(
fileName,
await prettier.format(content, {
parser: ctx.language === 'ts' ? 'typescript' : 'babel',
...config
})
)
} catch (error: any) {
throw new Error(`Error prettifying ${fileName}: ${error.message}`)
}

return ctx
}

/**
* Render a source file template for the language set in the context.
*
* @param templates The JavaScript and TypeScript template to render
* @param toFile The target filename without extension (will be added based on language)
* @param target The target filename without extension (will be added based on language)
* @returns The updated context
*/
export const renderSource =
<C extends PinionContext & { language: 'js' | 'ts' }>(
template: Callable<string, C>,
toFile: Callable<string, C>,
target: Callable<string, C>,
options?: { force: boolean }
) =>
async (ctx: C) => {
const { language } = ctx
const fileName = await getCallable<string, C>(toFile, ctx)
const fileName = await getFileName(target, ctx)
const content = language === 'js' ? getJavaScript(await getCallable<string, C>(template, ctx)) : template
const renderer = renderTemplate(content, `${fileName}.${language}`, options)
const renderer = renderTemplate(content, fileName, options)

return renderer(ctx)
return renderer(ctx).then(prettify(target))
}

/**
Expand All @@ -195,8 +241,8 @@ export const injectSource =
const { language } = ctx
const source =
language === 'js' && transpile ? getJavaScript(await getCallable<string, C>(template, ctx)) : template
const toFile = await getCallable<string, C>(target, ctx)
const injector = inject(source, location, `${toFile}.${language}`)
const fileName = await getFileName(target, ctx)
const injector = inject(source, location, fileName)

return injector(ctx)
return injector(ctx).then(prettify(target))
}
21 changes: 11 additions & 10 deletions packages/cli/src/connection/templates/knex.tpl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export const ${database} = (app: Application) => {
const config = app.get('${database}')
const db = knex(config!)
app.set('${database}Client', db);
app.set('${database}Client', db)
}
`

Expand All @@ -30,18 +30,19 @@ const config = app.get('${database}')
${language === 'js' ? 'export default config' : 'module.exports = config'}
`

const configurationTemplate = ({ database }: ConnectionGeneratorContext) => ` ${database}: {
type: 'object',
properties: {
client: { type: 'string' },
connection: { type: 'string' }
}
},`

const configurationTemplate = ({ database }: ConnectionGeneratorContext) => `${database}: {
type: 'object',
properties: {
client: { type: 'string' },
connection: { type: 'string' }
}
},`
const importTemplate = ({ database }: ConnectionGeneratorContext) =>
`import { ${database} } from './${database}'`
const configureTemplate = ({ database }: ConnectionGeneratorContext) => `app.configure(${database})`

const toAppFile = toFile<ConnectionGeneratorContext>(({ lib }) => [lib, 'app'])
const toConfig = toFile<ConnectionGeneratorContext>(({ lib }) => [lib, 'configuration'])

export const generate = (ctx: ConnectionGeneratorContext) =>
generator(ctx)
Expand All @@ -68,7 +69,7 @@ export const generate = (ctx: ConnectionGeneratorContext) =>
injectSource(
configurationTemplate,
before('authentication: authenticationSettingsSchema'),
toFile<ConnectionGeneratorContext>(({ lib }) => [lib, 'configuration']),
toConfig,
false
)
)
Expand Down
14 changes: 7 additions & 7 deletions packages/cli/test/commons.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { strictEqual } from 'assert'
import { getJavaScript } from '../src/commons'

describe('common tests', () => {
it('getJavaScript returns transpiled and prettified JavaScript', () => {
it('getJavaScript returns transpiled JavaScript', () => {
const transpiled = getJavaScript(
`import bla from 'bla'
import something from './file'
Expand All @@ -20,15 +20,15 @@ const otherThing: string = "Hello"

strictEqual(
transpiled,
`import bla from 'bla'
import something from './file.js'
`import bla from 'bla';
import something from './file.js';
function test(arg) {
bla(something)
function test(arg) {
bla(something);
}
// This is a comment
const otherThing = 'Hello'
// This is a comment
const otherThing = "Hello";
`
)
})
Expand Down

0 comments on commit 83aa8f9

Please # to comment.