Skip to content

Commit

Permalink
Run prettier on project. (#6)
Browse files Browse the repository at this point in the history
* Create command to setup prettier.

* Add eslint path (#15)
  • Loading branch information
geekiam23 authored Aug 18, 2023
1 parent c91bc42 commit 030b4b1
Show file tree
Hide file tree
Showing 13 changed files with 490 additions and 281 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"author": "thoughtbot, Inc.",
"license": "MIT",
"dependencies": {
"@thoughtbot/eslint-config": "thoughtbot/eslint-config#eslint-configs",
"@thoughtbot/eslint-config": "^1.0.2",
"chalk": "^5.2.0",
"commander": "^10.0.1",
"eslint": "^8.45.0",
Expand Down
26 changes: 13 additions & 13 deletions src/cli.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
import { program } from "commander";
import buildAction from "./util/buildAction";
import { program } from 'commander';
import buildAction from './util/buildAction';

export default function runCli() {
program
.name("thoughtbelt")
.name('thoughtbelt')
.description(
"Perform React Native and Expo setup and redundant tasks without your pants falling down!"
'Perform React Native and Expo setup and redundant tasks without your pants falling down!',
)

.command("eslint")
.description("Configure ESLint")
.action(buildAction(import("./commands/eslint")));
.command('eslint')
.description('Configure ESLint')
.action(buildAction(import('./commands/eslint')));

program
.command("prettier")
.description("Configure Prettier")
.action(buildAction(import("./commands/prettier")));
.command('prettier')
.description('Configure Prettier')
.action(buildAction(import('./commands/prettier')));

program
.command("typescript")
.description("Install and configure TypeScript")
.action(buildAction(import("./commands/typescript")));
.command('typescript')
.description('Install and configure TypeScript')
.action(buildAction(import('./commands/typescript')));

program.showHelpAfterError().parse();
}
Expand Down
40 changes: 38 additions & 2 deletions src/commands/eslint.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,39 @@
export default function runEslint() {
console.log("ESLint!");
import { log } from 'console';
import path from 'path';
import { fileURLToPath, URL } from 'url';
import chalk from 'chalk';
import * as eta from 'eta';
import fs from 'fs-extra';
import addDependency from '../util/addDependency';
import getProjectDir from '../util/getProjectDir';
import isEslintConfigured from '../util/isEslintConfigured';
import isPackageInstalled from '../util/isPackageInstalled';
import writeFile from '../util/writeFile';

const dirname = fileURLToPath(new URL('.', import.meta.url));

export default async function runEslint() {
const projectDir = await getProjectDir();

if (await isEslintConfigured()) {
log('eslint config already exists');
} else {
const hasTypeScript = await isPackageInstalled('typescript');

const eslintConfigTemplate = await fs.readFile(
path.join(dirname, 'templates', 'eslintrc.js.eta'),
);

const fileContents = eta.render(eslintConfigTemplate.toString(), {
typescript: hasTypeScript,
});

await writeFile(path.join(projectDir, '.eslintrc.js'), fileContents, {
format: true,
});

await addDependency('@thoughtbot/eslint-config', { dev: true });

log(chalk.green('🎉 ESLint successfully configured'));
}
}
8 changes: 8 additions & 0 deletions src/commands/templates/eslintrc.js.eta
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module.exports = {
"extends": [
"@thoughtbot/eslint-config/native",
<% if(it.typescript) { %>
"@thoughtbot/eslint-config/typescript"
<% } %>
],
};
38 changes: 19 additions & 19 deletions src/commands/typescript.ts
Original file line number Diff line number Diff line change
@@ -1,39 +1,39 @@
import chalk from "chalk";
import { log } from "console";
import * as eta from "eta";
import fs from "fs-extra";
import path from "path";
import { fileURLToPath, URL } from "url";
import addDependency from "../util/addDependency";
import getProjectDir from "../util/getProjectDir";
import getProjectType from "../util/getProjectType";
import writeFile from "../util/writeFile";
import { log } from 'console';
import path from 'path';
import { fileURLToPath, URL } from 'url';
import chalk from 'chalk';
import * as eta from 'eta';
import fs from 'fs-extra';
import addDependency from '../util/addDependency';
import getProjectDir from '../util/getProjectDir';
import getProjectType from '../util/getProjectType';
import writeFile from '../util/writeFile';

// for manual testing, change this to another name so doesn't conflict
// with project's tsconfig.json
const tsConfig = "tsconfig.json";
const dirname = fileURLToPath(new URL(".", import.meta.url));
const tsConfig = 'tsconfig.json';
const dirname = fileURLToPath(new URL('.', import.meta.url));

export default async function addTypescript() {
const projectDir = await getProjectDir();

if (await fs.exists(path.join(projectDir, tsConfig))) {
log(
chalk.yellow(
"tsconfig.json already exists, exiting.\nIf you would like to perform a fresh TypeScript install, delete this file and rerun the script.\n"
)
'tsconfig.json already exists, exiting.\nIf you would like to perform a fresh TypeScript install, delete this file and rerun the script.\n',
),
);
return;
}

await addDependency("typescript @types/react", { dev: true });
await addDependency('typescript @types/react', { dev: true });

const projectType = await getProjectType();
const template = await fs.readFile(
path.join(dirname, "templates", "tsconfig.json.eta")
path.join(dirname, 'templates', 'tsconfig.json.eta'),
);
const fileContents = eta.render(template.toString(), {
expo: projectType === "expo-bare" || projectType === "expo-managed",
expo: projectType === 'expo-bare' || projectType === 'expo-managed',
});

await writeFile(path.join(projectDir, tsConfig), fileContents, {
Expand All @@ -42,7 +42,7 @@ export default async function addTypescript() {

log(
chalk.green(
"\n🎉 TypeScript successfully configured\nConsider renaming your existing JS files as .ts or .tsx.\n"
)
'\n🎉 TypeScript successfully configured\nConsider renaming your existing JS files as .ts or .tsx.\n',
),
);
}
14 changes: 7 additions & 7 deletions src/util/addDependency.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { exec } from "child_process";
import * as fs from "fs-extra";
import * as path from "path";
import getProjectDir from "./getProjectDir";
import { exec } from 'child_process';
import * as path from 'path';
import * as fs from 'fs-extra';
import getProjectDir from './getProjectDir';

export default async function addDependency(deps: string, { dev = false }) {
const isYarn = await fs.exists(path.join(await getProjectDir(), "yarn.lock"));
const isYarn = await fs.exists(path.join(await getProjectDir(), 'yarn.lock'));

if (isYarn) {
exec(`yarn add ${dev ? "--dev" : ""} ${deps}`);
exec(`yarn add ${dev ? '--dev' : ''} ${deps}`);
} else {
exec(`npm install ${dev ? "--save-dev" : "--save"} ${deps}`);
exec(`npm install ${dev ? '--save-dev' : '--save'} ${deps}`);
}
}
2 changes: 1 addition & 1 deletion src/util/formatFile.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { exec } from "child_process";
import { exec } from 'child_process';

export default async function formatFile(filePath: string) {
exec(`npx prettier --write '${filePath}'`);
Expand Down
12 changes: 7 additions & 5 deletions src/util/getProjectDir.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import fs from "fs-extra";
import path from "path";
import path from 'path';
import fs from 'fs-extra';

export default async function getProjectDir(base: string = process.cwd()): Promise<string> {
export default async function getProjectDir(
base: string = process.cwd(),
): Promise<string> {
let previous = null;
let dir = base;

do {
try {
// This will throw if there is no package.json in the directory
// eslint-disable-next-line no-await-in-loop
await fs.readFile(path.join(dir, "package.json"));
await fs.readFile(path.join(dir, 'package.json'));

// if didn't throw, package.json exists, return dir
return dir;
Expand All @@ -22,6 +24,6 @@ export default async function getProjectDir(base: string = process.cwd()): Promi
} while (dir !== previous);

throw new Error(
"No project found. Ensure you are inside of a project directory with a package.json file."
'No project found. Ensure you are inside of a project directory with a package.json file.',
);
}
23 changes: 23 additions & 0 deletions src/util/isEslintConfigured.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import path from 'path';
import fsExtra from 'fs-extra';
import getProjectDir from './getProjectDir';
import readPackageJson from './readPackageJson';

export default async function isEslintConfigured() {
const packageJson = await readPackageJson();

const projectDir = await getProjectDir();

const hasEslintConfigInPackageJson = Object.prototype.hasOwnProperty.call(
packageJson,
'eslint',
);
const hasEslintrcJsFile = await fsExtra.exists(
path.join(projectDir, '.eslintrc.js'),
);
const hasEslintJsonFile = await fsExtra.exists(
path.join(projectDir, '.eslintrc.json'),
);

return hasEslintConfigInPackageJson || hasEslintrcJsFile || hasEslintJsonFile;
}
15 changes: 15 additions & 0 deletions src/util/isPackageInstalled.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import readPackageJson from './readPackageJson';

export default async function isPackageInstalled(packageName: string) {
const packageJson = await readPackageJson();

const isPackageInDevdependencies = Object.prototype.hasOwnProperty.call(
packageJson.dependencies,
packageName,
);
const isPackageInDependencies = Object.prototype.hasOwnProperty.call(
packageJson.devDependencies,
packageName,
);
return isPackageInDevdependencies || isPackageInDependencies;
}
18 changes: 9 additions & 9 deletions src/util/isPrettierConfigured.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import fsExtra from "fs-extra";
import path from "path";
import getProjectDir from "./getProjectDir";
import readPackageJson from "./readPackageJson";
import path from 'path';
import fsExtra from 'fs-extra';
import getProjectDir from './getProjectDir';
import readPackageJson from './readPackageJson';

export default async function isPrettierConfigured() {
const packageJson = await readPackageJson();
Expand All @@ -10,19 +10,19 @@ export default async function isPrettierConfigured() {

const hasPrettierConfigInPackageJson = Object.prototype.hasOwnProperty.call(
packageJson,
"prettier"
'prettier',
);
const hasPrettierrcJsFile = await fsExtra.exists(
path.join(projectDir, "prettierrc.js")
path.join(projectDir, 'prettierrc.js'),
);
const hasPrettierrcFile = await fsExtra.exists(
path.join(projectDir, ".prettierrc")
path.join(projectDir, '.prettierrc'),
);
const hasPrettierrcJsonFile = await fsExtra.exists(
path.join(projectDir, ".prettierrc.json")
path.join(projectDir, '.prettierrc.json'),
);
const hasPrettierConfigFile = await fsExtra.exists(
path.join(projectDir, ".prettier.config.js")
path.join(projectDir, '.prettier.config.js'),
);

return (
Expand Down
10 changes: 5 additions & 5 deletions src/util/readPackageJson.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import fs from "fs-extra";
import path from "path";
import { PackageJson } from "../types";
import getProjectDir from "./getProjectDir";
import path from 'path';
import fs from 'fs-extra';
import { PackageJson } from '../types';
import getProjectDir from './getProjectDir';

export default async function readPackageJson() {
const rootDir = await getProjectDir();
const pkg = await fs.readFile(path.join(rootDir, "package.json"));
const pkg = await fs.readFile(path.join(rootDir, 'package.json'));
return JSON.parse(pkg.toString()) as PackageJson;
}
Loading

0 comments on commit 030b4b1

Please sign in to comment.