From 6332d08ab345470643566175a8b308792e23ced9 Mon Sep 17 00:00:00 2001 From: theBGuy <60308670+theBGuy@users.noreply.github.com> Date: Sat, 4 Jan 2025 14:36:31 -0500 Subject: [PATCH] Handle automatically detecting formatter and reformatting after cleaning --- readme.md | 4 +++- src/index.ts | 11 ++++++++++- src/utils.ts | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+), 2 deletions(-) create mode 100644 src/utils.ts diff --git a/readme.md b/readme.md index 5f4f980..b373af8 100644 --- a/readme.md +++ b/readme.md @@ -1,4 +1,5 @@ # RN Native Stylesheet Cleaner + ![NPM Downloads](https://img.shields.io/npm/d18m/rn-native-stylesheet-cleaner) This project is a utility tool designed to clean and optimize React Native stylesheets. It helps in removing unused styles and organizing the stylesheet for better readability and maintainability. @@ -48,6 +49,7 @@ This will scan your project for stylesheets, identify unused styles, and clean t - `-d, --directory `: Directory to parse (default: `src`) - `-i, --include `: File patterns to include (default: `**/*.{jsx,tsx}`) - `-e, --exclude `: File patterns to exclude (default: `''`) +- `--no-format`: Run the cleaner without reformatting the output. - `--dry-run`: Run the cleaner without making any changes, just to see what would be cleaned. - `--verbose`: Output detailed information during the cleaning process. @@ -59,7 +61,7 @@ rn-native-stylesheet-cleaner --dry-run --verbose ## Warning -Note: The formatting of the outputted code will be removed during the cleaning process. You will need to reformat the code after running the RN Native Stylesheet Cleaner. It is recommended to use a code formatter like Prettier to reformat your code. +Note: The formatting of the outputted code will be initially removed during the cleaning process. However, if you have Prettier or Biome installed, the code will be reformatted automatically. The reformatting behavior is still experimental, and extra whitespace may still be stripped. You can turn off this behavior by using the `--no-format` flag if you prefer to handle formatting manually. ## Contributing diff --git a/src/index.ts b/src/index.ts index af14357..69d52d6 100644 --- a/src/index.ts +++ b/src/index.ts @@ -6,6 +6,7 @@ import { Command } from "commander"; import { minimatch } from "minimatch"; import ts from "typescript"; import { version } from "../package.json"; +import { detectFormatter, formatFile } from "./utils"; const program = new Command(); @@ -14,6 +15,7 @@ program .option("-d, --directory ", "directory to parse", "src") .option("-i, --include ", "file patterns to include", "**/*.{jsx,tsx}") .option("-e, --exclude ", "file patterns to exclude", "") + .option("--no-format", "run without formatting the output") .option("--dry-run", "run without making any changes") .option("--verbose", "output detailed information") .parse(process.argv); @@ -31,6 +33,8 @@ const includePatterns: string = options.include; const excludePatterns: string = options.exclude; const isDryRun = options.dryRun; const isVerbose = options.verbose; +const noFormat = options.noFormat; +const formatter = detectFormatter(process.cwd()); const log = (message?: any, ...optionalParams: any[]) => { if (isVerbose) { @@ -38,6 +42,8 @@ const log = (message?: any, ...optionalParams: any[]) => { } }; +log(formatter ? `${formatter} detected` : "No formatter detected; skipping formatting."); + const parseFile = (filePath: string) => { const sourceCode = fs.readFileSync(filePath, "utf-8"); const isTsx = filePath.endsWith(".tsx"); @@ -57,7 +63,7 @@ const parseFile = (filePath: string) => { } ts.forEachChild(sourceFile, visitReferences); - const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed }); + const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed, removeComments: false }); const transformer = (context: ts.TransformationContext) => { return (node: ts.Node): ts.Node => { @@ -118,6 +124,9 @@ const parseFile = (filePath: string) => { if (hasChanges) { if (!isDryRun) { fs.writeFileSync(filePath, updatedCode, "utf-8"); + if (!noFormat) { + formatFile(filePath, formatter); + } log(`Updated file: ${filePath}`); } else { log(`Dry run: ${filePath} would be updated`); diff --git a/src/utils.ts b/src/utils.ts new file mode 100644 index 0000000..63661de --- /dev/null +++ b/src/utils.ts @@ -0,0 +1,47 @@ +import { execSync } from "node:child_process"; +import fs from "node:fs"; +import path from "node:path"; + +const findConfigFile = (dir: string, filenames: string[]) => { + for (const filename of filenames) { + const filePath = path.join(dir, filename); + if (fs.existsSync(filePath)) { + return filePath; + } + } + return null; +}; + +export const detectFormatter = (directory: string) => { + const prettierConfigs = [".prettierrc", ".prettierrc.js", ".prettierrc.json", "prettier.config.js"]; + const biomeConfigs = ["biome.json", "biome.jsonc", "biome.config.json"]; + + const prettierConfigPath = findConfigFile(directory, prettierConfigs); + if (prettierConfigPath) return "prettier"; + + const biomeConfigPath = findConfigFile(directory, biomeConfigs); + if (biomeConfigPath) return "biome"; + + return null; +}; + +const formatWithBiome = (filePath: string) => { + execSync(`npx biome format --write ${filePath}`, { stdio: "inherit" }); +}; + +export const formatFile = (filePath: string, formatter: string | null) => { + try { + if (formatter === "prettier") { + const prettier = require("prettier"); + const prettierConfig = prettier.resolveConfig.sync(filePath) || {}; + prettierConfig.parser = filePath.endsWith(".tsx") ? "tsx" : "babel"; + const code = fs.readFileSync(filePath, "utf-8"); + const formattedCode = prettier.format(code, prettierConfig); + fs.writeFileSync(filePath, formattedCode, "utf-8"); + } else if (formatter === "biome") { + formatWithBiome(filePath); + } + } catch (err) { + console.error(err); + } +};