diff --git a/src/code_transformer/main.ts b/src/code_transformer/main.ts index e670eaa7..f8b7083c 100644 --- a/src/code_transformer/main.ts +++ b/src/code_transformer/main.ts @@ -9,7 +9,15 @@ import { join } from 'node:path' import { fileURLToPath } from 'node:url' -import { CodeBlockWriter, Node, Project, SourceFile, SyntaxKind } from 'ts-morph' +import { + CodeBlockWriter, + FormatCodeSettings, + Node, + Project, + QuoteKind, + SourceFile, + SyntaxKind, +} from 'ts-morph' import { RcFileTransformer } from './rc_file_transformer.js' import type { AddMiddlewareEntry, EnvValidationDefinition } from '../types.js' @@ -31,16 +39,19 @@ export class CodeTransformer { /** * Settings to use when persisting files */ - #editorSettings = { + #editorSettings: FormatCodeSettings = { indentSize: 2, convertTabsToSpaces: true, trimTrailingWhitespace: true, + // @ts-expect-error SemicolonPreference doesn't seem to be re-exported from ts-morph + semicolons: 'remove', } constructor(cwd: URL) { this.#cwd = cwd this.#project = new Project({ tsConfigFilePath: join(fileURLToPath(this.#cwd), 'tsconfig.json'), + manipulationSettings: { quoteKind: QuoteKind.Single }, }) } @@ -177,6 +188,42 @@ export class CodeTransformer { await file.save() } + /** + * Add a new Japa plugin in the `tests/bootstrap.ts` file + */ + async addJapaPlugin( + pluginCall: string, + importDeclaration: { isNamed: boolean; module: string; identifier: string } + ) { + /** + * Get the `tests/bootstrap.ts` source file + */ + const testBootstrapUrl = fileURLToPath(new URL('./tests/bootstrap.ts', this.#cwd)) + const file = this.#project.getSourceFileOrThrow(testBootstrapUrl) + + /** + * Add the import declaration + */ + file.addImportDeclaration({ + ...(importDeclaration.isNamed + ? { namedImports: [importDeclaration.identifier] } + : { defaultImport: importDeclaration.identifier }), + moduleSpecifier: importDeclaration.module, + }) + + /** + * Insert the plugin call in the `plugins` array + */ + const pluginsArray = file + .getVariableDeclaration('plugins') + ?.getInitializerIfKind(SyntaxKind.ArrayLiteralExpression) + + if (pluginsArray) pluginsArray.addElement(pluginCall) + + file.formatText(this.#editorSettings) + await file.save() + } + /** * Add new env variable validation in the * `env.ts` file diff --git a/tests/__snapshots__/code_transformer.spec.ts.cjs b/tests/__snapshots__/code_transformer.spec.ts.cjs index 0566dcca..244c90fc 100644 --- a/tests/__snapshots__/code_transformer.spec.ts.cjs +++ b/tests/__snapshots__/code_transformer.spec.ts.cjs @@ -354,3 +354,25 @@ export default defineConfig({ }) "` +exports[`Code transformer | addJapaPlugin > addJapaPlugin with named import 1`] = `" +import app from '@adonisjs/core/services/app' +import { assert } from '@japa/assert' +import { fooPlugin } from '@adonisjs/foo/plugin/japa' + +export const plugins: Config['plugins'] = [ + assert(), + fooPlugin(app) +] +"` + +exports[`Code transformer | addJapaPlugin > addJapaPlugin with default import 1`] = `" +import app from '@adonisjs/core/services/app' +import { assert } from '@japa/assert' +import fooPlugin from '@adonisjs/foo/plugin/japa' + +export const plugins: Config['plugins'] = [ + assert(), + fooPlugin() +] +"` + diff --git a/tests/code_transformer.spec.ts b/tests/code_transformer.spec.ts index ba2c9fb4..317baa1f 100644 --- a/tests/code_transformer.spec.ts +++ b/tests/code_transformer.spec.ts @@ -506,3 +506,55 @@ test.group('Code transformer | addPreloadFile', (group) => { assert.equal(occurrences, 1) }) }) + +test.group('Code transformer | addJapaPlugin', (group) => { + group.each.setup(async ({ context }) => setupFakeAdonisproject(context.fs)) + + test('add named import', async ({ assert, fs }) => { + await fs.create( + 'tests/bootstrap.ts', + ` + import app from '@adonisjs/core/services/app' + import { assert } from '@japa/assert' + + export const plugins: Config['plugins'] = [ + assert(), + ]` + ) + + const transformer = new CodeTransformer(fs.baseUrl) + + await transformer.addJapaPlugin('fooPlugin(app)', { + module: '@adonisjs/foo/plugin/japa', + identifier: 'fooPlugin', + isNamed: true, + }) + + const file = await fs.contents('tests/bootstrap.ts') + assert.snapshot(file).match() + }) + + test('add default import', async ({ assert, fs }) => { + await fs.create( + 'tests/bootstrap.ts', + ` + import app from '@adonisjs/core/services/app' + import { assert } from '@japa/assert' + + export const plugins: Config['plugins'] = [ + assert(), + ]` + ) + + const transformer = new CodeTransformer(fs.baseUrl) + + await transformer.addJapaPlugin('fooPlugin()', { + module: '@adonisjs/foo/plugin/japa', + identifier: 'fooPlugin', + isNamed: false, + }) + + const file = await fs.contents('tests/bootstrap.ts') + assert.snapshot(file).match() + }) +})