UNPKG

@swell/cli

Version:

Swell's command line interface/utility

114 lines (113 loc) 4.4 kB
import * as fs from 'node:fs'; import * as path from 'node:path'; import { filePathExists, writeFile } from '../apps/index.js'; import { envDtsTemplate, integrationTestTemplate, mockRequestTemplate, setupGlobalsTemplate, swellClientTemplate, tsconfigTemplate, unitTestTemplate, vitestConfigTemplate, } from './tests/templates/index.js'; const TEST_DEV_DEPENDENCIES = { '@cloudflare/vitest-pool-workers': 'latest', vitest: 'latest', '@swell/app-types': 'latest', }; async function writeTextFile(filePath, contents, overwrite) { if (!overwrite && filePathExists(filePath)) { return { created: false, skipped: true }; } await writeFile(filePath, contents); return { created: true, skipped: false }; } function updatePackageJson(appPath) { const pkgPath = path.join(appPath, 'package.json'); if (!filePathExists(pkgPath)) { return { updated: false, warning: 'package.json not found. Run `npm init` first.', }; } let pkgRaw; try { pkgRaw = fs.readFileSync(pkgPath, 'utf8'); } catch (error) { return { updated: false, warning: `Could not read package.json: ${error instanceof Error ? error.message : String(error)}`, }; } let pkg; try { pkg = JSON.parse(pkgRaw); } catch (error) { return { updated: false, warning: `Could not parse package.json: ${error instanceof Error ? error.message : String(error)}`, }; } const devDeps = (pkg.devDependencies || {}); const deps = (pkg.dependencies || {}); devDeps['@cloudflare/vitest-pool-workers'] = devDeps['@cloudflare/vitest-pool-workers'] || TEST_DEV_DEPENDENCIES['@cloudflare/vitest-pool-workers']; devDeps.vitest = devDeps.vitest || TEST_DEV_DEPENDENCIES.vitest; if (!devDeps['@swell/app-types'] && !deps['@swell/app-types']) { devDeps['@swell/app-types'] = TEST_DEV_DEPENDENCIES['@swell/app-types']; } pkg.devDependencies = devDeps; const scripts = (pkg.scripts || {}); scripts.test = scripts.test || 'vitest run'; pkg.scripts = scripts; try { const next = `${JSON.stringify(pkg, null, 2)}\n`; fs.writeFileSync(pkgPath, next, 'utf8'); return { updated: true }; } catch (error) { return { updated: false, warning: `Could not write package.json: ${error instanceof Error ? error.message : String(error)}`, }; } } function validatePrerequisites(appPath) { const warnings = []; const tsconfigPath = path.join(appPath, 'tsconfig.json'); if (!filePathExists(tsconfigPath)) { warnings.push('tsconfig.json not found. test/tsconfig.json extends it; create one or tests may not compile.'); } return warnings; } async function createTestsScaffold(options) { const { appPath, appId, overwrite } = options; const result = { createdFiles: [], skippedFiles: [], packageJsonUpdated: false, warnings: [], }; const prereqWarnings = validatePrerequisites(appPath); result.warnings.push(...prereqWarnings); const trackFile = async (relativePath, contents) => { const fullPath = path.join(appPath, relativePath); const writeResult = await writeTextFile(fullPath, contents, overwrite); if (writeResult.created) { result.createdFiles.push(relativePath); } else if (writeResult.skipped) { result.skippedFiles.push(relativePath); } }; await trackFile('vitest.config.ts', vitestConfigTemplate({ appId })); await trackFile('test/tsconfig.json', tsconfigTemplate()); await trackFile('test/env.d.ts', envDtsTemplate()); await trackFile('test/setup-globals.ts', setupGlobalsTemplate()); await trackFile('test/helpers/swell-client.ts', swellClientTemplate()); await trackFile('test/helpers/mock-request.ts', mockRequestTemplate({ appId })); await trackFile('test/unit/example.test.ts', unitTestTemplate()); await trackFile('test/integration/example.test.ts', integrationTestTemplate()); const pkgResult = updatePackageJson(appPath); result.packageJsonUpdated = pkgResult.updated; if (pkgResult.warning) { result.warnings.push(pkgResult.warning); } return result; } export { createTestsScaffold };