diff --git a/packages/cli-helpers/src/auth/authFiles.ts b/packages/cli-helpers/src/auth/authFiles.ts index c64f48f8141a..6602a9089c7d 100644 --- a/packages/cli-helpers/src/auth/authFiles.ts +++ b/packages/cli-helpers/src/auth/authFiles.ts @@ -24,76 +24,76 @@ interface FilesArgs { * } * ``` */ -export const apiSideFiles = ({ basedir, webAuthn }: FilesArgs) => { +export const apiSideFiles = async ({ basedir, webAuthn }: FilesArgs) => { const apiSrcPath = getPaths().api.src const apiBaseTemplatePath = path.join(basedir, 'templates', 'api') const templateDirectories = fs.readdirSync(apiBaseTemplatePath) - const filesRecord = templateDirectories.reduce>( - (acc, dir) => { - const templateFiles = fs.readdirSync(path.join(apiBaseTemplatePath, dir)) - const filePaths = templateFiles - .filter((fileName) => { - const fileNameParts = fileName.split('.') - // Remove all webAuthn files. We'll handle those in the next step - return ( - fileNameParts.length <= 3 || fileNameParts.at(-3) !== 'webAuthn' - ) - }) - .map((fileName) => { - // remove "template" from the end, and change from {ts,tsx} to {js,jsx} for - // JavaScript projects - let outputFileName = fileName.replace(/\.template$/, '') - if (!isTypeScriptProject()) { - outputFileName = outputFileName.replace(/\.ts(x?)$/, '.js$1') - } - - if (!webAuthn) { - return { templateFileName: fileName, outputFileName } - } - - // Insert "webAuthn." before the second to last part - const webAuthnFileName = fileName - .split('.') - .reverse() - .map((part, i) => (i === 1 ? 'webAuthn.' + part : part)) - .reverse() - .join('.') - - // Favor the abc.xyz.webAuthn.ts.template file if it exists, otherwise - // just go with the "normal" filename - if (templateFiles.includes(webAuthnFileName)) { - return { templateFileName: webAuthnFileName, outputFileName } - } else { - return { templateFileName: fileName, outputFileName } - } - }) - .map((f) => { - const templateFilePath = path.join( - apiBaseTemplatePath, - dir, - f.templateFileName - ) - const outputFilePath = path.join(apiSrcPath, dir, f.outputFileName) - - return { templateFilePath, outputFilePath } - }) - - filePaths.forEach((paths) => { - const content = fs.readFileSync(paths.templateFilePath, 'utf8') - - acc = { - ...acc, - [paths.outputFilePath]: isTypeScriptProject() - ? content - : transformTSToJS(paths.outputFilePath, content), + const filesRecord = await templateDirectories.reduce< + Promise> + >(async (accP, dir) => { + const templateFiles = fs.readdirSync(path.join(apiBaseTemplatePath, dir)) + const filePaths = templateFiles + .filter((fileName) => { + const fileNameParts = fileName.split('.') + // Remove all webAuthn files. We'll handle those in the next step + return fileNameParts.length <= 3 || fileNameParts.at(-3) !== 'webAuthn' + }) + .map((fileName) => { + // remove "template" from the end, and change from {ts,tsx} to {js,jsx} for + // JavaScript projects + let outputFileName = fileName.replace(/\.template$/, '') + if (!isTypeScriptProject()) { + outputFileName = outputFileName.replace(/\.ts(x?)$/, '.js$1') + } + + if (!webAuthn) { + return { templateFileName: fileName, outputFileName } } + + // Insert "webAuthn." before the second to last part + const webAuthnFileName = fileName + .split('.') + .reverse() + .map((part, i) => (i === 1 ? 'webAuthn.' + part : part)) + .reverse() + .join('.') + + // Favor the abc.xyz.webAuthn.ts.template file if it exists, otherwise + // just go with the "normal" filename + if (templateFiles.includes(webAuthnFileName)) { + return { templateFileName: webAuthnFileName, outputFileName } + } else { + return { templateFileName: fileName, outputFileName } + } + }) + .map((f) => { + const templateFilePath = path.join( + apiBaseTemplatePath, + dir, + f.templateFileName + ) + const outputFilePath = path.join(apiSrcPath, dir, f.outputFileName) + + return { templateFilePath, outputFilePath } }) - return acc - }, - {} - ) + const acc = await accP + let nextAcc = {} + + for (const paths of filePaths) { + const content = fs.readFileSync(paths.templateFilePath, 'utf8') + + nextAcc = { + ...acc, + [paths.outputFilePath]: isTypeScriptProject() + ? content + : await transformTSToJS(paths.outputFilePath, content), + } + } + + return nextAcc + }, Promise.resolve({})) return filesRecord } diff --git a/packages/cli-helpers/src/auth/authTasks.ts b/packages/cli-helpers/src/auth/authTasks.ts index c4d515c7e6d2..8c90351d4a93 100644 --- a/packages/cli-helpers/src/auth/authTasks.ts +++ b/packages/cli-helpers/src/auth/authTasks.ts @@ -362,7 +362,7 @@ export const createWebAuth = (basedir: string, webAuthn: boolean) => { return { title: `Creating web/src/auth.${ext}`, - task: (ctx: AuthGeneratorCtx) => { + task: async (ctx: AuthGeneratorCtx) => { // @MARK - finding unused file name here, // We should only use an unused filename, if the user is CHOOSING not to replace the existing provider @@ -399,7 +399,7 @@ export const createWebAuth = (basedir: string, webAuthn: boolean) => { template = isTSProject ? template - : transformTSToJS(authFileName, template) + : await transformTSToJS(authFileName, template) fs.writeFileSync(authFileName, template) }, @@ -448,7 +448,7 @@ export const generateAuthApiFiles = ( // The keys in `filesRecord` are the full paths to where the file contents, // which is the values in `filesRecord`, will be written. - let filesRecord = apiSideFiles({ basedir, webAuthn }) + let filesRecord = await apiSideFiles({ basedir, webAuthn }) // Always overwrite files in force mode, no need to prompt let existingFiles: ExistingFiles = 'FAIL' diff --git a/packages/cli-helpers/src/lib/index.ts b/packages/cli-helpers/src/lib/index.ts index 1bc77ed61bea..a90bce84bdc3 100644 --- a/packages/cli-helpers/src/lib/index.ts +++ b/packages/cli-helpers/src/lib/index.ts @@ -52,9 +52,11 @@ export const transformTSToJS = (filename: string, content: string) => { /** * This returns the config present in `prettier.config.js` of a Redwood project. */ -export const prettierOptions = () => { +export const getPrettierOptions = async () => { try { - const options = require(path.join(getPaths().base, 'prettier.config.js')) + const options = await import( + path.join(getPaths().base, 'prettier.config.js') + ) if (options.tailwindConfig?.startsWith('.')) { // Make this work with --cwd @@ -70,10 +72,10 @@ export const prettierOptions = () => { } } -export const prettify = ( +export const prettify = async ( templateFilename: string, renderedTemplate: string -): string => { +): Promise => { // We format .js and .css templates, we need to tell prettier which parser // we're using. // https://prettier.io/docs/en/options.html#parser @@ -88,8 +90,10 @@ export const prettify = ( return renderedTemplate } + const prettierOptions = await getPrettierOptions() + return format(renderedTemplate, { - ...prettierOptions(), + ...prettierOptions, parser, }) } diff --git a/packages/cli/src/commands/experimental/setupRscHandler.js b/packages/cli/src/commands/experimental/setupRscHandler.js index b0ae3a54959c..2dbddc3eb0ce 100644 --- a/packages/cli/src/commands/experimental/setupRscHandler.js +++ b/packages/cli/src/commands/experimental/setupRscHandler.js @@ -303,7 +303,7 @@ export const handler = async ({ force, verbose }) => { writeFile( tsconfigPath, - prettify('tsconfig.json', JSON.stringify(tsconfig, null, 2)), + await prettify('tsconfig.json', JSON.stringify(tsconfig, null, 2)), { overwriteExisting: true, } diff --git a/packages/cli/src/commands/setup/graphql/features/fragments/fragmentsHandler.ts b/packages/cli/src/commands/setup/graphql/features/fragments/fragmentsHandler.ts index b9bb28c41b50..fc7ec0b03670 100644 --- a/packages/cli/src/commands/setup/graphql/features/fragments/fragmentsHandler.ts +++ b/packages/cli/src/commands/setup/graphql/features/fragments/fragmentsHandler.ts @@ -5,7 +5,11 @@ import execa from 'execa' import { Listr } from 'listr2' import { format } from 'prettier' -import { colors, prettierOptions, setTomlSetting } from '@redwoodjs/cli-helpers' +import { + colors, + getPrettierOptions, + setTomlSetting, +} from '@redwoodjs/cli-helpers' import { getConfig, getPaths } from '@redwoodjs/project-config' import type { Args } from './fragments' @@ -67,8 +71,10 @@ export async function handler({ force }: Args) { const appPath = getPaths().web.app const source = fs.readFileSync(appPath, 'utf-8') + const prettierOptions = await getPrettierOptions() + const prettifiedApp = format(source, { - ...prettierOptions(), + ...prettierOptions, parser: 'babel-ts', }) diff --git a/packages/cli/src/commands/setup/graphql/features/trustedDocuments/trustedDocumentsHandler.ts b/packages/cli/src/commands/setup/graphql/features/trustedDocuments/trustedDocumentsHandler.ts index e3e959ee9493..a3a60a9d2d09 100644 --- a/packages/cli/src/commands/setup/graphql/features/trustedDocuments/trustedDocumentsHandler.ts +++ b/packages/cli/src/commands/setup/graphql/features/trustedDocuments/trustedDocumentsHandler.ts @@ -5,7 +5,7 @@ import execa from 'execa' import { Listr } from 'listr2' import { format } from 'prettier' -import { prettierOptions, setTomlSetting } from '@redwoodjs/cli-helpers' +import { getPrettierOptions, setTomlSetting } from '@redwoodjs/cli-helpers' import { getConfig, getPaths, resolveFile } from '@redwoodjs/project-config' import { runTransform } from '../fragments/runTransform.js' @@ -62,8 +62,10 @@ export async function handler({ force }: { force: boolean }) { const source = fs.readFileSync(graphqlPath, 'utf-8') + const prettierOptions = await getPrettierOptions() + const prettifiedApp = format(source, { - ...prettierOptions(), + ...prettierOptions, parser: 'babel-ts', }) diff --git a/packages/cli/src/commands/setup/monitoring/sentry/sentryHandler.ts b/packages/cli/src/commands/setup/monitoring/sentry/sentryHandler.ts index 607a6d28a506..f0db2436f939 100644 --- a/packages/cli/src/commands/setup/monitoring/sentry/sentryHandler.ts +++ b/packages/cli/src/commands/setup/monitoring/sentry/sentryHandler.ts @@ -54,7 +54,7 @@ export const handler = async ({ force }: Args) => { }, { title: 'Implementing the Envelop plugin', - task: (ctx) => { + task: async (ctx) => { const graphqlHandlerPath = path.join( rwPaths.api.functions, `graphql.${extension}` @@ -95,13 +95,13 @@ export const handler = async ({ force }: Args) => { fs.writeFileSync( graphqlHandlerPath, - prettify('graphql.ts', contentLines.join('\n')) + await prettify('graphql.ts', contentLines.join('\n')) ) }, }, { title: "Replacing Redwood's Error boundary", - task: () => { + task: async () => { const contentLines = fs .readFileSync(rwPaths.web.app) .toString() @@ -136,7 +136,7 @@ export const handler = async ({ force }: Args) => { fs.writeFileSync( rwPaths.web.app, - prettify('App.tsx', contentLines.join('\n')) + await prettify('App.tsx', contentLines.join('\n')) ) }, }, diff --git a/packages/cli/src/lib/index.js b/packages/cli/src/lib/index.js index 835b6ea8d7a7..f5ccb4bb0353 100644 --- a/packages/cli/src/lib/index.js +++ b/packages/cli/src/lib/index.js @@ -81,7 +81,7 @@ export const generateTemplate = (templateFilename, { name, ...rest }) => { } } -export const prettify = (templateFilename, renderedTemplate) => { +export const prettify = async (templateFilename, renderedTemplate) => { // We format .js and .css templates, we need to tell prettier which parser // we're using. // https://prettier.io/docs/en/options.html#parser @@ -97,8 +97,10 @@ export const prettify = (templateFilename, renderedTemplate) => { return renderedTemplate } + const prettierOptions = await getPrettierOptions() + return format(renderedTemplate, { - ...prettierOptions(), + ...prettierOptions, parser, }) } @@ -228,9 +230,12 @@ export const getConfig = () => { /** * This returns the config present in `prettier.config.js` of a Redwood project. */ -export const prettierOptions = () => { +export const getPrettierOptions = async () => { try { - return require(path.join(getPaths().base, 'prettier.config.js')) + const prettierOptions = await import( + path.join(getPaths().base, 'prettier.config.js') + ) + return prettierOptions } catch (e) { // If we're in our vitest environment we want to return a consistent set of prettier options // such that snapshots don't change unexpectedly. diff --git a/packages/codemods/src/codemods/v0.39.x/updateBabelConfig/updateBabelConfig.ts b/packages/codemods/src/codemods/v0.39.x/updateBabelConfig/updateBabelConfig.ts index 863bfb8aad61..b1325c779f0e 100644 --- a/packages/codemods/src/codemods/v0.39.x/updateBabelConfig/updateBabelConfig.ts +++ b/packages/codemods/src/codemods/v0.39.x/updateBabelConfig/updateBabelConfig.ts @@ -51,7 +51,7 @@ export const removeBabelConfig = async () => { const newConfig = `module.exports = ${JSON.stringify(otherConfig)}` - fs.writeFileSync(webBabelConfigPath, prettify(newConfig)) + fs.writeFileSync(webBabelConfigPath, await prettify(newConfig)) } } } diff --git a/packages/codemods/src/codemods/v2.3.x/tsconfigForRouteHooks/tsconfigForRouteHooks.ts b/packages/codemods/src/codemods/v2.3.x/tsconfigForRouteHooks/tsconfigForRouteHooks.ts index bd30a857a289..d081b8d8d097 100644 --- a/packages/codemods/src/codemods/v2.3.x/tsconfigForRouteHooks/tsconfigForRouteHooks.ts +++ b/packages/codemods/src/codemods/v2.3.x/tsconfigForRouteHooks/tsconfigForRouteHooks.ts @@ -41,7 +41,7 @@ export default async function addApiAliasToTsConfig() { ts.sys.writeFile( webConfigPath, // @NOTE: prettier will remove trailing commas, but whatever - prettify(JSON.stringify(updatedConfig), { parser: 'json' }) + await prettify(JSON.stringify(updatedConfig), { parser: 'json' }) ) } else { throw new Error( diff --git a/packages/codemods/src/codemods/v2.x.x/configureFastify/configureFastify.yargs.ts b/packages/codemods/src/codemods/v2.x.x/configureFastify/configureFastify.yargs.ts index 8180f0901c6e..a55f573bf45a 100644 --- a/packages/codemods/src/codemods/v2.x.x/configureFastify/configureFastify.yargs.ts +++ b/packages/codemods/src/codemods/v2.x.x/configureFastify/configureFastify.yargs.ts @@ -36,7 +36,7 @@ export const handler = () => { // They don't show up in tests cause we run prettier. Let's do the same here. fs.writeFileSync( API_SERVER_CONFIG_PATH, - prettify(fs.readFileSync(API_SERVER_CONFIG_PATH, 'utf-8')) + await prettify(fs.readFileSync(API_SERVER_CONFIG_PATH, 'utf-8')) ) setOutput('All done!') @@ -51,7 +51,7 @@ export const handler = () => { 'server.config.js' ) - fs.writeFileSync(NEW_API_SERVER_CONFIG_PATH, prettify(text)) + fs.writeFileSync(NEW_API_SERVER_CONFIG_PATH, await prettify(text)) setOutput( 'Done! No server.config.js found, so we updated your project to use the latest version.' diff --git a/packages/codemods/src/lib/prettify.ts b/packages/codemods/src/lib/prettify.ts index 7a2927f24e85..a3023f6332a5 100644 --- a/packages/codemods/src/lib/prettify.ts +++ b/packages/codemods/src/lib/prettify.ts @@ -4,21 +4,26 @@ import { format } from 'prettier' import { getPaths } from '@redwoodjs/project-config' -const getPrettierConfig = () => { +const getPrettierConfig = async () => { try { - return require(path.join(getPaths().base, 'prettier.config.js')) + const prettierConfig = await import( + path.join(getPaths().base, 'prettier.config.js') + ) + return prettierConfig } catch (e) { return undefined } } -const prettify = (code: string, options: Record = {}) => - format(code, { +const prettify = async (code: string, options: Record = {}) => { + const prettierConfig = await getPrettierConfig() + return format(code, { singleQuote: true, semi: false, - ...getPrettierConfig(), + ...prettierConfig(), parser: 'babel', ...options, }) +} export default prettify diff --git a/packages/internal/src/ts2js.ts b/packages/internal/src/ts2js.ts index 31e483801e00..fb2a05a56e5e 100644 --- a/packages/internal/src/ts2js.ts +++ b/packages/internal/src/ts2js.ts @@ -33,12 +33,12 @@ export const convertTsScriptsToJs = (cwd = getPaths().base) => { * @param {string} cwd - Current directory * @param {string[]} files - Collection of files to convert */ -export const convertTsFilesToJs = (cwd: string, files: string[]) => { +export const convertTsFilesToJs = async (cwd: string, files: string[]) => { if (files.length === 0) { console.log('No TypeScript files found to convert to JS in this project.') } for (const f of files) { - const code = transformTSToJS(f) + const code = await transformTSToJS(f) if (code) { fs.writeFileSync( path.join(cwd, f.replace('.tsx', '.jsx').replace('.ts', '.js')), @@ -117,9 +117,12 @@ export const transformTSToJS = (file: string) => { return prettify(result.code, filename.replace(/\.ts$/, '.js')) } -export const prettierConfig = () => { +export const getPrettierConfig = async () => { try { - return require(path.join(getPaths().base, 'prettier.config.js')) + const prettierConfig = await import( + path.join(getPaths().base, 'prettier.config.js') + ) + return prettierConfig } catch (e) { return undefined } @@ -152,15 +155,17 @@ const prettierParser = (filename: string) => { * @param {string} code * @param {string} filename */ -export const prettify = (code: string, filename: string) => { +export const prettify = async (code: string, filename: string) => { const parser = prettierParser(filename) // Return unformatted code if we could not determine the parser. if (typeof parser === 'undefined') { return code } + const prettierConfig = await getPrettierConfig() + return format(code, { - ...prettierConfig(), + ...prettierConfig, parser, }) }