From 107034cd0c27a52665c9998771e8263a103f392c Mon Sep 17 00:00:00 2001 From: winches <329487092@qq.com> Date: Sun, 31 Mar 2024 14:00:37 +0800 Subject: [PATCH] feat: doctor add core tailwind and app check --- package.json | 1 + pnpm-lock.yaml | 31 +++------- src/actions/doctor-action.ts | 109 ++++++++++++++++++++++++++++++++++- src/constants/required.ts | 23 +++++++- src/helpers/check.ts | 87 ++++++++++++++++++++++++++-- src/helpers/match.ts | 45 +++++++++++++++ src/helpers/package.ts | 4 +- src/helpers/utils.ts | 22 +++++++ src/index.ts | 2 + 9 files changed, 288 insertions(+), 36 deletions(-) create mode 100644 src/helpers/match.ts diff --git a/package.json b/package.json index 6549a5f..520f2ad 100644 --- a/package.json +++ b/package.json @@ -54,6 +54,7 @@ "async-retry": "1.3.3", "chalk": "5.3.0", "commander": "11.0.0", + "fast-glob": "3.3.2", "gradient-string": "2.0.2", "ora": "8.0.1", "prompts": "2.4.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6dd4366..c493c22 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -14,6 +14,9 @@ dependencies: commander: specifier: 11.0.0 version: 11.0.0 + fast-glob: + specifier: 3.3.2 + version: 3.3.2 gradient-string: specifier: 2.0.2 version: 2.0.2 @@ -594,12 +597,10 @@ packages: dependencies: '@nodelib/fs.stat': 2.0.5 run-parallel: 1.2.0 - dev: true /@nodelib/fs.stat@2.0.5: resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} engines: {node: '>= 8'} - dev: true /@nodelib/fs.walk@1.2.8: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} @@ -607,14 +608,13 @@ packages: dependencies: '@nodelib/fs.scandir': 2.1.5 fastq: 1.15.0 - dev: true /@pkgr/utils@2.4.2: resolution: {integrity: sha512-POgTXhjrTfbTV63DiFXav4lBHiICLKKwDeaKn9Nphwj7WH6m0hMMCaJkMyRWjgtPFyRKRVoMXXjczsTQRDEhYw==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} dependencies: cross-spawn: 7.0.3 - fast-glob: 3.3.1 + fast-glob: 3.3.2 is-glob: 4.0.3 open: 9.1.0 picocolors: 1.0.0 @@ -1047,7 +1047,6 @@ packages: engines: {node: '>=8'} dependencies: fill-range: 7.0.1 - dev: true /bundle-name@3.0.0: resolution: {integrity: sha512-PKA4BeSvBpQKQ8iPOGCSiell+N8P+Tf1DlwqmYhpe2gAhKPHn8EYOxVT+ShuGmhg8lN8XiSlS80yiExKXrURlw==} @@ -1594,7 +1593,7 @@ packages: eslint: 8.50.0 eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.7.2)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.50.0) eslint-plugin-import: 2.28.1(@typescript-eslint/parser@6.7.2)(eslint-import-resolver-typescript@3.6.1)(eslint@8.50.0) - fast-glob: 3.3.1 + fast-glob: 3.3.2 get-tsconfig: 4.7.2 is-core-module: 2.13.0 is-glob: 4.0.3 @@ -1879,8 +1878,8 @@ packages: resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==} dev: true - /fast-glob@3.3.1: - resolution: {integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==} + /fast-glob@3.3.2: + resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} engines: {node: '>=8.6.0'} dependencies: '@nodelib/fs.stat': 2.0.5 @@ -1888,7 +1887,6 @@ packages: glob-parent: 5.1.2 merge2: 1.4.1 micromatch: 4.0.5 - dev: true /fast-json-stable-stringify@2.1.0: resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} @@ -1902,7 +1900,6 @@ packages: resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==} dependencies: reusify: 1.0.4 - dev: true /file-entry-cache@6.0.1: resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} @@ -1916,7 +1913,6 @@ packages: engines: {node: '>=8'} dependencies: to-regex-range: 5.0.1 - dev: true /find-up@4.1.0: resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} @@ -2054,7 +2050,6 @@ packages: engines: {node: '>= 6'} dependencies: is-glob: 4.0.3 - dev: true /glob-parent@6.0.2: resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} @@ -2112,7 +2107,7 @@ packages: dependencies: array-union: 2.1.0 dir-glob: 3.0.1 - fast-glob: 3.3.1 + fast-glob: 3.3.2 ignore: 5.2.4 merge2: 1.4.1 slash: 3.0.0 @@ -2328,7 +2323,6 @@ packages: /is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} - dev: true /is-fullwidth-code-point@3.0.0: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} @@ -2345,7 +2339,6 @@ packages: engines: {node: '>=0.10.0'} dependencies: is-extglob: 2.1.1 - dev: true /is-inside-container@1.0.0: resolution: {integrity: sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==} @@ -2375,7 +2368,6 @@ packages: /is-number@7.0.0: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} - dev: true /is-obj@2.0.0: resolution: {integrity: sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==} @@ -2731,7 +2723,6 @@ packages: /merge2@1.4.1: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} - dev: true /micromatch@4.0.5: resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} @@ -2739,7 +2730,6 @@ packages: dependencies: braces: 3.0.2 picomatch: 2.3.1 - dev: true /mimic-fn@2.1.0: resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} @@ -3055,7 +3045,6 @@ packages: /picomatch@2.3.1: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} - dev: true /pidtree@0.6.0: resolution: {integrity: sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==} @@ -3118,7 +3107,6 @@ packages: /queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} - dev: true /quick-lru@4.0.1: resolution: {integrity: sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==} @@ -3237,7 +3225,6 @@ packages: /reusify@1.0.4: resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} - dev: true /rfdc@1.3.0: resolution: {integrity: sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==} @@ -3269,7 +3256,6 @@ packages: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} dependencies: queue-microtask: 1.2.3 - dev: true /safe-array-concat@1.0.1: resolution: {integrity: sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q==} @@ -3613,7 +3599,6 @@ packages: engines: {node: '>=8.0'} dependencies: is-number: 7.0.0 - dev: true /tr46@1.0.1: resolution: {integrity: sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==} diff --git a/src/actions/doctor-action.ts b/src/actions/doctor-action.ts index b4a3dd8..7480ad3 100644 --- a/src/actions/doctor-action.ts +++ b/src/actions/doctor-action.ts @@ -1,12 +1,16 @@ import chalk from 'chalk'; -import { checkRequiredContentInstalled } from '@helpers/check'; +import { checkApp, checkRequiredContentInstalled, checkTailwind } from '@helpers/check'; import { Logger, type PrefixLogType } from '@helpers/logger'; import { getPackageInfo } from '@helpers/package'; +import { findFiles } from '@helpers/utils'; import { resolver } from 'src/constants/path'; +import { DOCS_APP_SETUP, DOCS_INSTALLED, DOCS_TAILWINDCSS_SETUP } from 'src/constants/required'; interface DoctorActionOptions { packagePath?: string; + tailwindPath?: string; + appPath?: string; } interface ProblemRecord { @@ -16,11 +20,28 @@ interface ProblemRecord { } export async function doctorAction(options: DoctorActionOptions) { - const { packagePath = resolver('package.json') } = options; + const { + appPath = findFiles('**/app.tsx')[0], + packagePath = resolver('package.json'), + tailwindPath = findFiles('**/tailwind.config.js') + } = options; + const tailwindPaths = [tailwindPath].flat(); const { allDependenciesKeys, currentComponents, isAllComponents } = await getPackageInfo(packagePath); + /** ======================== Output when there is no components installed ======================== */ + if (!currentComponents.length && !isAllComponents) { + Logger.prefix( + 'error', + `❌Sorry there are no ${chalk.underline( + 'NextUI components' + )} in your project\nPlace check the NextUI document: https://nextui.org/docs/guide/installation#global-installation` + ); + + return; + } + /** ======================== Problem record ======================== */ const problemRecord: ProblemRecord[] = []; @@ -33,7 +54,6 @@ export async function doctorAction(options: DoctorActionOptions) { Logger.warn('you have installed redundant dependencies, please remove them'); Logger.newLine(); Logger.info('The redundant dependencies are:'); - Logger.newLine(); currentComponents.forEach((component) => { Logger.info(`- ${component.package}`); }); @@ -49,6 +69,89 @@ export async function doctorAction(options: DoctorActionOptions) { allDependenciesKeys ); + if (!isCorrectInstalled) { + problemRecord.push({ + level: 'error', + name: 'missingDependencies', + outputFn: () => { + Logger.error('you have not installed the required dependencies'); + Logger.newLine(); + Logger.info('The required dependencies are:'); + missingDependencies.forEach((dependency) => { + Logger.info(`- ${dependency}`); + }); + Logger.newLine(); + Logger.info(`Please check the detail in the NextUI document: ${DOCS_INSTALLED}`); + } + }); + } + + // Check whether tailwind.config.js is correct + if (!tailwindPaths.length) { + problemRecord.push({ + level: 'error', + name: 'missingTailwind', + outputFn: () => { + Logger.error('you have not created the tailwind.config.js'); + Logger.error(`Please check the detail in the NextUI document: ${DOCS_TAILWINDCSS_SETUP}`); + } + }); + } else { + for (const tailwindPath of tailwindPaths) { + const [isCorrectTailwind, ...errorInfo] = checkTailwind('all', tailwindPath); + + if (!isCorrectTailwind) { + problemRecord.push({ + level: 'error', + name: 'incorrectTailwind', + outputFn: () => { + Logger.error('your tailwind.config.js is incorrect'); + Logger.info('The missing part is:'); + errorInfo.forEach((info) => { + Logger.info(`- need added ${info}`); + }); + Logger.error(`Please check the detail in the NextUI document: ${DOCS_APP_SETUP}`); + } + }); + } + } + } + + // Check whether the app.tsx is correct + if (!appPath) { + problemRecord.push({ + level: 'error', + name: 'missingApp', + outputFn: () => { + Logger.error('Cannot find the app.tsx file'); + Logger.error("You should specify appPath through 'doctor --appPath=yourAppPath'"); + } + }); + } else { + const [isAppCorrect, ...errorInfo] = checkApp('all', appPath); + + if (!isAppCorrect) { + problemRecord.push({ + level: 'error', + name: 'incorrectApp', + outputFn: () => { + Logger.error('your app.tsx is incorrect'); + Logger.info('The missing part is:'); + errorInfo.forEach((info) => { + Logger.info(`- need added ${info}`); + }); + Logger.error(`Please check the detail in the NextUI document: ${DOCS_INSTALLED}`); + } + }); + } + } + } else if (currentComponents.length) { + // Individual components check + const [isCorrectInstalled, ...missingDependencies] = checkRequiredContentInstalled( + 'partial', + allDependenciesKeys + ); + if (!isCorrectInstalled) { problemRecord.push({ level: 'error', diff --git a/src/constants/required.ts b/src/constants/required.ts index 9a7ef99..4f3ac99 100644 --- a/src/constants/required.ts +++ b/src/constants/required.ts @@ -1,3 +1,22 @@ -export const ALL_COMPONENTS = '@nextui-org/react'; export const FRAMER_MOTION = 'framer-motion'; -export const ALL_COMPONENTS_REQUIRED = [ALL_COMPONENTS, FRAMER_MOTION] as const; +export const TAILWINDCSS = 'tailwindcss'; +export const NEXT_UI = '@nextui-org/react'; +export const THEME_UI = '@nextui-org/theme'; +export const SYSTEM_UI = '@nextui-org/system'; +export const ALL_COMPONENTS_REQUIRED = [NEXT_UI, FRAMER_MOTION] as const; + +export const DOCS_INSTALLED = 'https://nextui.org/docs/guide/installation#global-installation'; +export const DOCS_TAILWINDCSS_SETUP = + 'https://nextui.org/docs/guide/installation#tailwind-css-setup'; +export const DOCS_APP_SETUP = 'https://nextui.org/docs/guide/installation#provider-setup'; + +// Record the required content of tailwind.config.js +export const tailwindRequired = { + content: '@nextui-org/theme/dist/**/*.{js,ts,jsx,tsx}', + darkMode: 'darkMode: "class"', + plugins: 'nextui()' +} as const; + +export const appRequired = { + import: 'NextUIProvider' +}; diff --git a/src/helpers/check.ts b/src/helpers/check.ts index 66a07b1..8bae392 100644 --- a/src/helpers/check.ts +++ b/src/helpers/check.ts @@ -1,6 +1,18 @@ import type { SAFE_ANY } from './type'; -import { ALL_COMPONENTS, FRAMER_MOTION } from 'src/constants/required'; +import { readFileSync } from 'fs'; + +import { + FRAMER_MOTION, + NEXT_UI, + SYSTEM_UI, + TAILWINDCSS, + THEME_UI, + appRequired, + tailwindRequired +} from 'src/constants/required'; + +import { getMatchArray, getMatchImport } from './match'; export type CheckType = 'all' | 'partial'; @@ -16,19 +28,82 @@ export function checkRequiredContentInstalled( type: CheckType, dependenciesKeys: Set ): CheckResult { + const result = [] as unknown as CheckResult; + if (type === 'all') { - const hasAllComponents = dependenciesKeys.has(ALL_COMPONENTS); + const hasAllComponents = dependenciesKeys.has(NEXT_UI); const hasFramerMotion = dependenciesKeys.has(FRAMER_MOTION); - const result = [] as unknown as CheckResult; + const hasTailwind = dependenciesKeys.has(TAILWINDCSS); if (hasAllComponents && hasFramerMotion) { return [true]; } - !hasAllComponents && result.push(ALL_COMPONENTS); + !hasAllComponents && result.push(NEXT_UI); + !hasFramerMotion && result.push(FRAMER_MOTION); + !hasTailwind && result.push(TAILWINDCSS); + } else if (type === 'partial') { + const hasFramerMotion = dependenciesKeys.has(FRAMER_MOTION); + const hasTailwind = dependenciesKeys.has(TAILWINDCSS); + const hasSystemUI = dependenciesKeys.has(SYSTEM_UI); + const hasThemeUI = dependenciesKeys.has(THEME_UI); + + if (hasFramerMotion && hasSystemUI && hasThemeUI) { + return [true]; + } !hasFramerMotion && result.push(FRAMER_MOTION); + !hasSystemUI && result.push(SYSTEM_UI); + !hasThemeUI && result.push(THEME_UI); + !hasTailwind && result.push(TAILWINDCSS); + } + + return [false, ...result]; +} + +export function checkTailwind(type: CheckType, tailwindPath: string): CheckResult { + const result = [] as unknown as CheckResult; + + if (type === 'all') { + const tailwindContent = readFileSync(tailwindPath, 'utf-8'); + + const contentMatch = getMatchArray('content', tailwindContent); + const pluginsMatch = getMatchArray('plugins', tailwindContent); + + // Check if the required content is added Detail: https://nextui.org/docs/guide/installation#global-installation + const isDarkModeCorrect = new RegExp(tailwindRequired.darkMode).test(tailwindContent); + const isContentCorrect = contentMatch.some((content) => + content.includes(tailwindRequired.content) + ); + const isPluginsCorrect = pluginsMatch.some((plugins) => + plugins.includes(tailwindRequired.plugins) + ); + + if (isDarkModeCorrect && isContentCorrect && isPluginsCorrect) { + return [true]; + } + + !isDarkModeCorrect && result.push(tailwindRequired.darkMode); + !isContentCorrect && result.push(tailwindRequired.content); + !isPluginsCorrect && result.push(tailwindRequired.plugins); + } + + return [false, ...result]; +} + +export function checkApp(type: CheckType, appPath: string): CheckResult { + const result = [] as unknown as CheckResult; + + if (type === 'all') { + const appContent = readFileSync(appPath, 'utf-8'); + + const importArray = getMatchImport(appContent); + const isAppCorrect = importArray.some(([key]) => key!.includes(appRequired.import)); + + if (isAppCorrect) { + return [true]; + } - return [false, ...result]; + !isAppCorrect && result.push(appRequired.import); } - return [false]; + return [false, ...result]; } diff --git a/src/helpers/match.ts b/src/helpers/match.ts new file mode 100644 index 0000000..84f8285 --- /dev/null +++ b/src/helpers/match.ts @@ -0,0 +1,45 @@ +/** + * Get the content of the key in the target string. + * @example getMatchImport('import {test} from "source"') => [['test', 'source']] + * @param str + */ +export function getMatchImport(str: string) { + const importRegexAll = /import {?\s*([\w\W]+?)\s*}? from ['"](.+)['"]/g; + + const matchAll = str.match(importRegexAll) ?? []; + const result: string[][] = []; + + for (const item of matchAll) { + result.push(matchImport(item)); + } + + return result.length ? result : []; + + function matchImport(itemImport: string) { + const importRegex = /import {?\s*([\w\W]+?)\s*}? from ['"](.+)['"]/; + const match = itemImport.match(importRegex) ?? []; + + return [match[1] ?? '', match[2] ?? '']; + } +} + +/** + * Get the array content of the key in the target string. + * @example getMatchArray('key', 'key: [a, b, c]') => ['a', 'b', 'c'] + * @param key + * @param target + */ +export function getMatchArray(key: string, target: string) { + const mixinReg = new RegExp(`\\s*${key}:\\s\\[([\\w\\W]*?)\\]\\s*`); + + if (mixinReg.test(target)) + return ( + target + .match(mixinReg)?.[1] + ?.split(/,\n/) + .map((i) => i.trim()) + .filter(Boolean) ?? [] + ); + + return []; +} diff --git a/src/helpers/package.ts b/src/helpers/package.ts index f1ab349..e553320 100644 --- a/src/helpers/package.ts +++ b/src/helpers/package.ts @@ -1,7 +1,7 @@ import { readFileSync } from 'fs'; import { type NextUIComponents, nextUIComponents } from 'src/constants/component'; -import { ALL_COMPONENTS } from 'src/constants/required'; +import { NEXT_UI } from 'src/constants/required'; import { Logger } from './logger'; @@ -36,7 +36,7 @@ export async function getPackageInfo(packagePath: string) { return false; } ) as NextUIComponents; - const isAllComponents = allDependenciesKeys.has(ALL_COMPONENTS); + const isAllComponents = allDependenciesKeys.has(NEXT_UI); return { allDependencies, diff --git a/src/helpers/utils.ts b/src/helpers/utils.ts index 2291290..956d010 100644 --- a/src/helpers/utils.ts +++ b/src/helpers/utils.ts @@ -1,5 +1,9 @@ import type { PascalCase } from './type'; +import fg, { type Options } from 'fast-glob'; + +import { ROOT } from 'src/constants/path'; + import { Logger } from './logger'; export function getCommandDescAndLog(log: string, desc: string) { @@ -19,3 +23,21 @@ export function PasCalCase(str: T) { .map((s) => s.charAt(0).toUpperCase() + s.slice(1)) .join('') as PascalCase; } + +/** + * Find files by glob pattern. + * @param glob + * @param options + */ +export const findFiles = (glob: string, options?: Options) => { + const file = fg.sync(`${glob}`, { + absolute: true, + cwd: ROOT, + deep: 5, + ignore: ['node_modules/**', 'dist/**', 'build/**', 'coverage/**', 'public/**', 'out/**'], + onlyFiles: true, + ...options + }); + + return file; +}; diff --git a/src/index.ts b/src/index.ts index d4d94c2..14e4834 100644 --- a/src/index.ts +++ b/src/index.ts @@ -49,6 +49,8 @@ nextui .command('doctor') .description('Check whether exist problem in user project') .option('-p --packagePath [string]', 'The path to the package.json file') + .option('-tw --tailwindPath [string]', 'The path to the tailwind.config.js file') + .option('-app --appPath [string]', 'The path to the app.tsx file') .action(doctorAction); nextui.parseAsync(process.argv).catch(async (reason) => {