diff --git a/packages/core/adder/execute.ts b/packages/core/adder/execute.ts index 66eabae6..78a9fbf2 100644 --- a/packages/core/adder/execute.ts +++ b/packages/core/adder/execute.ts @@ -2,7 +2,7 @@ import path from 'node:path'; import * as pc from 'picocolors'; import { serializeJson } from '@svelte-cli/ast-tooling'; import { commonFilePaths, format, writeFile } from '../files/utils'; -import { type ProjectType, createProject, detectSvelteDirectory } from '../utils/create-project'; +import { createProject, detectSvelteDirectory } from '../utils/create-project'; import { createOrUpdateFiles } from '../files/processors'; import { getPackageJson } from '../utils/common'; import { @@ -36,6 +36,8 @@ import { displayNextSteps } from './nextSteps'; import { spinner, log, cancel } from '@svelte-cli/clack-prompts'; import { executeCli } from '../utils/cli'; +export type ProjectType = 'svelte' | 'kit'; + export type AdderDetails = { config: AdderConfig; checks: AdderCheckConfig; @@ -132,15 +134,13 @@ async function executePlan( // create project if required if (executionPlan.createProject) { const cwd = executionPlan.commonCliOptions.path ?? executionPlan.workingDirectory; - const supportKit = adderDetails.some((x) => x.config.metadata.environments.kit); - const supportSvelte = adderDetails.some((x) => x.config.metadata.environments.svelte); - const { projectCreated, directory } = await createProject(cwd, supportKit, supportSvelte); + const { projectCreated, directory } = await createProject(cwd); if (!projectCreated) return; executionPlan.workingDirectory = directory; } const workspace = createEmptyWorkspace(); - await populateWorkspaceDetails(workspace, executionPlan.workingDirectory); + populateWorkspaceDetails(workspace, executionPlan.workingDirectory); const projectType: ProjectType = workspace.kit.installed ? 'kit' : 'svelte'; // select appropriate adders @@ -218,7 +218,7 @@ async function executePlan( const adderId = config.metadata.id; const adderWorkspace = createEmptyWorkspace(); - await populateWorkspaceDetails(adderWorkspace, executionPlan.workingDirectory); + populateWorkspaceDetails(adderWorkspace, executionPlan.workingDirectory); if (executionPlan.cliOptionsByAdderId) { for (const [key, value] of Object.entries(executionPlan.cliOptionsByAdderId[adderId])) { addPropertyToWorkspaceOption(adderWorkspace, key, value); @@ -252,7 +252,7 @@ async function executePlan( } // reload workspace as adders might have changed i.e. dependencies - await populateWorkspaceDetails(workspace, executionPlan.workingDirectory); + populateWorkspaceDetails(workspace, executionPlan.workingDirectory); let installStatus; if (!remoteControlled && !executionPlan.commonCliOptions.skipInstall) @@ -281,8 +281,8 @@ async function processInlineAdder( workspace: Workspace, isInstall: boolean ) { - const pkgPath = await installPackages(config, workspace); - const updatedOrCreatedFiles = await createOrUpdateFiles(config.files, workspace); + const pkgPath = installPackages(config, workspace); + const updatedOrCreatedFiles = createOrUpdateFiles(config.files, workspace); await runHooks(config, workspace, isInstall); const changedFiles = [pkgPath, ...updatedOrCreatedFiles]; @@ -318,11 +318,11 @@ export function determineWorkingDirectory(directory: string | undefined): string return cwd; } -export async function installPackages( +export function installPackages( config: InlineAdderConfig, workspace: Workspace -): Promise { - const { text: originalText, data } = await getPackageJson(workspace); +): string { + const { text: originalText, data } = getPackageJson(workspace); for (const dependency of config.packages) { if (dependency.condition && !dependency.condition(workspace)) { @@ -347,11 +347,7 @@ export async function installPackages( if (data.dependencies) data.dependencies = alphabetizeProperties(data.dependencies); if (data.devDependencies) data.devDependencies = alphabetizeProperties(data.devDependencies); - await writeFile( - workspace, - commonFilePaths.packageJsonFilePath, - serializeJson(originalText, data) - ); + writeFile(workspace, commonFilePaths.packageJsonFilePath, serializeJson(originalText, data)); return commonFilePaths.packageJsonFilePath; } diff --git a/packages/core/adder/postconditions.ts b/packages/core/adder/postconditions.ts index a0da6511..5df71a0b 100644 --- a/packages/core/adder/postconditions.ts +++ b/packages/core/adder/postconditions.ts @@ -1,3 +1,4 @@ +import dedent from 'dedent'; import * as pc from 'picocolors'; import { messagePrompt } from '../utils/prompts'; import { fileExistsWorkspace, readFile } from '../files/utils'; @@ -7,12 +8,12 @@ import type { OptionDefinition } from './options'; export type PreconditionParameters = { workspace: Workspace; - fileExists: (path: string) => Promise; - fileContains: (path: string, expectedContent: string) => Promise; + fileExists: (path: string) => void; + fileContains: (path: string, expectedContent: string) => void; }; export type Postcondition = { name: string; - run: (params: PreconditionParameters) => Promise; + run: (params: PreconditionParameters) => Promise | void; }; export async function checkPostconditions( @@ -41,20 +42,20 @@ export async function checkPostconditions( return unmetPostconditions; } -async function fileExists(path: string, workspace: Workspace) { - if (await fileExistsWorkspace(workspace, path)) return; +function fileExists(path: string, workspace: Workspace) { + if (fileExistsWorkspace(workspace, path)) return; throw new Error(`File "${path}" does not exists`); } -async function fileContains( +function fileContains( path: string, workspace: Workspace, expectedContent: string -): Promise { - await fileExists(path, workspace); +): void { + fileExists(path, workspace); - const content = await readFile(workspace, path); + const content = readFile(workspace, path); if (content && content.includes(expectedContent)) return; throw new Error(`File "${path}" does not contain "${expectedContent}"`); @@ -62,8 +63,11 @@ async function fileContains( export function printUnmetPostconditions(unmetPostconditions: string[]): void { const postconditionList = unmetPostconditions.map((x) => pc.yellow(`- ${x}`)).join('\n'); - const additionalText = `Postconditions are not supposed to fail. -Please open an issue providing the full console output: -https://github.com/sveltejs/cli/issues/new/choose`; + const additionalText = dedent` + Postconditions are not supposed to fail. + Please open an issue providing the full console output: + https://github.com/sveltejs/cli/issues/new/choose + `; + messagePrompt('Postconditions not met', `${postconditionList}\n\n${additionalText}`); } diff --git a/packages/core/adder/preconditions.ts b/packages/core/adder/preconditions.ts index 05072087..5c0cf099 100644 --- a/packages/core/adder/preconditions.ts +++ b/packages/core/adder/preconditions.ts @@ -1,10 +1,9 @@ import * as pc from 'picocolors'; import { booleanPrompt, endPrompts, messagePrompt } from '../utils/prompts'; import { executeCli } from '../utils/cli'; -import type { AdderDetails } from './execute'; +import type { AdderDetails, ProjectType } from './execute'; import type { Precondition } from './config'; import type { OptionDefinition } from './options'; -import type { ProjectType } from '../utils/create-project'; function getGlobalPreconditions( executingCli: string, diff --git a/packages/core/files/processors.ts b/packages/core/files/processors.ts index 18d85d63..7f5e7bd8 100644 --- a/packages/core/files/processors.ts +++ b/packages/core/files/processors.ts @@ -86,10 +86,10 @@ export type FileTypes = * @param workspace * @returns a list of paths of changed or created files */ -export async function createOrUpdateFiles( +export function createOrUpdateFiles( files: Array>, workspace: Workspace -): Promise { +): string[] { const changedFiles = []; for (const fileDetails of files) { try { @@ -97,13 +97,13 @@ export async function createOrUpdateFiles( continue; } - const exists = await fileExistsWorkspace(workspace, fileDetails.name(workspace)); + const exists = fileExistsWorkspace(workspace, fileDetails.name(workspace)); let content = ''; if (!exists) { content = ''; } else { - content = await readFile(workspace, fileDetails.name(workspace)); + content = readFile(workspace, fileDetails.name(workspace)); } if (fileDetails.contentType == 'script') { @@ -120,7 +120,7 @@ export async function createOrUpdateFiles( content = handleHtmlFile(content, fileDetails, workspace); } - await writeFile(workspace, fileDetails.name(workspace), content); + writeFile(workspace, fileDetails.name(workspace), content); changedFiles.push(fileDetails.name(workspace)); } catch (e) { if (e instanceof Error) diff --git a/packages/core/files/utils.ts b/packages/core/files/utils.ts index 81fceefd..27f56eb3 100644 --- a/packages/core/files/utils.ts +++ b/packages/core/files/utils.ts @@ -1,61 +1,43 @@ -import fs from 'node:fs/promises'; +import fs from 'node:fs'; import path from 'node:path'; import { executeCli } from '../utils/cli'; import type { WorkspaceWithoutExplicitArgs } from '../utils/workspace'; -export async function readFile( - workspace: WorkspaceWithoutExplicitArgs, - filePath: string -): Promise { +export function readFile(workspace: WorkspaceWithoutExplicitArgs, filePath: string): string { const fullFilePath = getFilePath(workspace.cwd, filePath); - if (!(await fileExistsWorkspace(workspace, filePath))) { + if (!fileExistsWorkspace(workspace, filePath)) { return ''; } - const buffer = await fs.readFile(fullFilePath); - const text = buffer.toString(); + const text = fs.readFileSync(fullFilePath, 'utf8'); return text; } -export async function writeFile( +export function writeFile( workspace: WorkspaceWithoutExplicitArgs, filePath: string, content: string -): Promise { +): void { const fullFilePath = getFilePath(workspace.cwd, filePath); const fullDirectoryPath = path.dirname(fullFilePath); if (content && !content.endsWith('\n')) content += '\n'; - if (!(await directoryExists(fullDirectoryPath))) { - await fs.mkdir(fullDirectoryPath, { recursive: true }); + if (!fs.existsSync(fullDirectoryPath)) { + fs.mkdirSync(fullDirectoryPath, { recursive: true }); } - await fs.writeFile(fullFilePath, content); + fs.writeFileSync(fullFilePath, content, 'utf8'); } -export async function fileExistsWorkspace( +export function fileExistsWorkspace( workspace: WorkspaceWithoutExplicitArgs, filePath: string -): Promise { +): boolean { const fullFilePath = getFilePath(workspace.cwd, filePath); - return await fileExists(fullFilePath); -} - -export async function fileExists(filePath: string): Promise { - try { - await fs.access(filePath, fs.constants.F_OK); - return true; - // eslint-disable-next-line @typescript-eslint/no-unused-vars - } catch (error) { - return false; - } -} - -export async function directoryExists(directoryPath: string): Promise { - return await fileExists(directoryPath); + return fs.existsSync(fullFilePath); } export function getFilePath(cwd: string, fileName: string): string { @@ -76,11 +58,7 @@ export const commonFilePaths = { svelteConfigFilePath: 'svelte.config.js' }; -export async function findUp( - searchPath: string, - fileName: string, - maxDepth?: number -): Promise { +export function findUp(searchPath: string, fileName: string, maxDepth?: number): boolean { // partially sourced from https://github.com/privatenumber/get-tsconfig/blob/9e78ec52d450d58743439358dd88e2066109743f/src/utils/find-up.ts#L5 let depth = 0; while (!maxDepth || depth < maxDepth) { @@ -88,7 +66,7 @@ export async function findUp( try { // `access` throws an exception if the file could not be found - await fs.access(configPath); + fs.accessSync(configPath); return true; } catch { const parentPath = path.dirname(searchPath); diff --git a/packages/core/utils/common.ts b/packages/core/utils/common.ts index b1504f40..6f2481a9 100644 --- a/packages/core/utils/common.ts +++ b/packages/core/utils/common.ts @@ -12,11 +12,11 @@ export type Package = { keywords?: string[]; }; -export async function getPackageJson(workspace: WorkspaceWithoutExplicitArgs): Promise<{ +export function getPackageJson(workspace: WorkspaceWithoutExplicitArgs): { text: string; data: Package; -}> { - const packageText = await readFile(workspace, commonFilePaths.packageJsonFilePath); +} { + const packageText = readFile(workspace, commonFilePaths.packageJsonFilePath); if (!packageText) { return { text: '', diff --git a/packages/core/utils/create-project.ts b/packages/core/utils/create-project.ts index 82a76a31..b510a116 100644 --- a/packages/core/utils/create-project.ts +++ b/packages/core/utils/create-project.ts @@ -1,7 +1,7 @@ import fs from 'node:fs'; import path from 'node:path'; import * as p from './prompts'; -import { commonFilePaths, directoryExists, fileExists } from '../files/utils'; +import { commonFilePaths } from '../files/utils'; import { getPackageJson } from './common'; import { createEmptyWorkspace } from './workspace'; import { spinner } from '@svelte-cli/clack-prompts'; @@ -14,21 +14,21 @@ export async function detectSvelteDirectory(directoryPath: string): Promise { +): void { workspace.cwd = workingDirectory; const tsConfigFileName = 'tsconfig.json'; const viteConfigFileName = 'vite.config.ts'; - let usesTypescript = await fileExists(path.join(workingDirectory, viteConfigFileName)); + let usesTypescript = fs.existsSync(path.join(workingDirectory, viteConfigFileName)); if (remoteControl.isRemoteControlled()) { // while executing tests, we only look into the direct `workingDirectory` // as we might detect the monorepo `tsconfig.json` otherwise. - usesTypescript ||= await fileExists(path.join(workingDirectory, tsConfigFileName)); + usesTypescript ||= fs.existsSync(path.join(workingDirectory, tsConfigFileName)); } else { - usesTypescript ||= await findUp(workingDirectory, tsConfigFileName); + usesTypescript ||= findUp(workingDirectory, tsConfigFileName); } - const { data: packageJson } = await getPackageJson(workspace); + const { data: packageJson } = getPackageJson(workspace); if (packageJson.devDependencies) { workspace.typescript.installed = usesTypescript; workspace.prettier.installed = 'prettier' in packageJson.devDependencies; @@ -100,14 +101,12 @@ export async function populateWorkspaceDetails( } } - await parseSvelteConfigIntoWorkspace(workspace); + parseSvelteConfigIntoWorkspace(workspace); } -export async function parseSvelteConfigIntoWorkspace( - workspace: WorkspaceWithoutExplicitArgs -): Promise { +export function parseSvelteConfigIntoWorkspace(workspace: WorkspaceWithoutExplicitArgs): void { if (!workspace.kit.installed) return; - const configText = await readFile(workspace, commonFilePaths.svelteConfigFilePath); + const configText = readFile(workspace, commonFilePaths.svelteConfigFilePath); const ast = parseScript(configText); const editor = getJsAstEditor(ast);