diff --git a/src/commands/add/dep.ts b/src/commands/add/dep.ts index 8bf6b7d..b0a06fb 100644 --- a/src/commands/add/dep.ts +++ b/src/commands/add/dep.ts @@ -14,10 +14,16 @@ export default class Dep extends BaseAddCommand { static flags = { ...BaseCommand.flags, - dev: flags.boolean({ default: false, char: 'D', description: 'install as a dev dependency' }), + dev: flags.boolean({ + default: false, + char: 'D', + description: 'install as a dev dependency', + }), }; - static args = [{ name: 'dep', description: 'The dependency to install', required: true }]; + static args = [ + { name: 'dep', description: 'The dependency to install', required: true }, + ]; async run() { if (!this.hasDirPackageJson()) { @@ -28,7 +34,10 @@ export default class Dep extends BaseAddCommand { flags: { dev }, } = this.parse(Dep); - if ((dev && this.hasDevDependencyInPackageJson(dep)) || this.hasDependencyInPackageJson(dep)) { + if ( + (dev && this.hasDevDependencyInPackageJson(dep)) || + this.hasDependencyInPackageJson(dep) + ) { if (this.hasDevDependencyInPackageJson(dep)) { this.error(`${dep} is already installed in this project.`); } diff --git a/src/commands/add/prettier.ts b/src/commands/add/prettier.ts index e1cdd89..eae6a6e 100644 --- a/src/commands/add/prettier.ts +++ b/src/commands/add/prettier.ts @@ -85,9 +85,13 @@ export default class Prettier extends BaseAddCommand { trailingComma: 'all', }; - await filesystem.write(filesystem.path('.', '.prettierrc'), prettierRcFile, { - jsonIndent: 2, - }); + await filesystem.write( + filesystem.path('.', '.prettierrc'), + prettierRcFile, + { + jsonIndent: 2, + }, + ); if (shouldCommit) { await this.gitAdd({ filepath: '.prettierrc' }); @@ -97,16 +101,19 @@ export default class Prettier extends BaseAddCommand { } }); - await this.runWithSpinner('Updating code to match prettier style', async () => { - await system.exec('yarn format:write'); - - if (shouldCommit) { - await this.gitAddUnstaged(); - await this.gitCommit({ - message: ':art: apply prettier style to project', - }); - } - }); + await this.runWithSpinner( + 'Updating code to match prettier style', + async () => { + await system.exec('yarn format:write'); + + if (shouldCommit) { + await this.gitAddUnstaged(); + await this.gitCommit({ + message: ':art: apply prettier style to project', + }); + } + }, + ); await this.handleMaybeEslint(shouldCommit); await this.handleMaybeTslint(shouldCommit); @@ -132,7 +139,8 @@ export default class Prettier extends BaseAddCommand { [ { type: 'confirm', - message: 'Eslint found in the project, do you want to add eslint prettier config ?', + message: + 'Eslint found in the project, do you want to add eslint prettier config ?', name: 'shouldOverrideEslint', initial: true, }, @@ -150,7 +158,14 @@ export default class Prettier extends BaseAddCommand { const eslintConfig = filesystem.read(eslintPath, 'json'); const finalEslintConfig = { ...eslintConfig, - extends: [...eslintConfig.extends, 'plugin:prettier/recommended'], + extends: [ + ...(typeof eslintConfig?.extends === 'string' + ? [eslintConfig.extends] + : Array.isArray(eslintConfig?.extends) + ? eslintConfig.extends + : []), + 'plugin:prettier/recommended', + ], }; await filesystem.write(eslintPath, finalEslintConfig, { jsonIndent: 2 }); @@ -174,7 +189,8 @@ export default class Prettier extends BaseAddCommand { [ { type: 'confirm', - message: 'Tslint found in the project, do you want to add tslint prettier config ?', + message: + 'Tslint found in the project, do you want to add tslint prettier config ?', name: 'shouldOverrideTslint', initial: true, }, @@ -192,9 +208,17 @@ export default class Prettier extends BaseAddCommand { const tslintConfig = filesystem.read(tslintPath, 'json'); const finalEslintConfig = { ...tslintConfig, - extends: [...tslintConfig.extends, 'tslint-plugin-prettier', 'tslint-config-prettier'], + extends: [ + ...(typeof tslintConfig?.extends === 'string' + ? [tslintConfig.extends] + : Array.isArray(tslintConfig?.extends) + ? tslintConfig.extends + : []), + 'tslint-plugin-prettier', + 'tslint-config-prettier', + ], rules: { - ...tslintConfig.rules, + ...(tslintConfig.rules ?? {}), prettier: true, }, }; diff --git a/src/commands/add/tailwind.ts b/src/commands/add/tailwind.ts index 5f3c48d..f561167 100644 --- a/src/commands/add/tailwind.ts +++ b/src/commands/add/tailwind.ts @@ -15,6 +15,10 @@ export default class Tailwind extends BaseAddCommand { this.error('There is no package.json not found in the current folder'); } + if (this.hasDependencyInPackageJson('tailwind')) { + this.error('Tailwind is already installed in this project.'); + } + if (!this.hasDependencyInPackageJson('react-scripts')) { this.error('This script support only for now create react apps.'); } @@ -45,16 +49,19 @@ export default class Tailwind extends BaseAddCommand { await this.addDevDependency('postcss-cli', shouldCommit); await this.addDependency('tailwindcss', shouldCommit); - await this.runWithSpinner('Generating tailwind initial config', async () => { - await system.exec('yarn tailwindcss init --full'); - - if (shouldCommit) { - await this.gitAdd({ filepath: 'tailwind.config.js' }); - await this.gitCommit({ - message: ':wrench: add tailwind config file', - }); - } - }); + await this.runWithSpinner( + 'Generating tailwind initial config', + async () => { + await system.exec('yarn tailwindcss init --full'); + + if (shouldCommit) { + await this.gitAdd({ filepath: 'tailwind.config.js' }); + await this.gitCommit({ + message: ':wrench: add tailwind config file', + }); + } + }, + ); await this.runWithSpinner('Generating postcss', async () => { await filesystem.write( 'postcss.config.js', @@ -109,8 +116,10 @@ module.exports = { 'build': 'npm-run-all build:css build:js', 'start:js': packageJsonWithDeps.scripts.start, 'build:js': packageJsonWithDeps.scripts.build, - 'start:css': 'postcss src/css/tailwind.src.css -o src/tailwind.css -w', - 'build:css': 'postcss src/css/tailwind.src.css -o src/tailwind.css --env production', + 'start:css': + 'postcss src/css/tailwind.src.css -o src/tailwind.css -w', + 'build:css': + 'postcss src/css/tailwind.src.css -o src/tailwind.css --env production', }, }; @@ -124,15 +133,21 @@ module.exports = { } }); - await this.runWithSpinner('Adding full tailwind css to .gitignore', async () => { - await patching.append('.gitignore', '\n# ignore tailwind generated css\nsrc/tailwind.css'); - - if (shouldCommit) { - await this.gitAdd({ filepath: '.gitignore' }); - await this.gitCommit({ - message: ':see_no_evil: add generated tailwind to .gitignore', - }); - } - }); + await this.runWithSpinner( + 'Adding full tailwind css to .gitignore', + async () => { + await patching.append( + '.gitignore', + '\n# ignore tailwind generated css\nsrc/tailwind.css', + ); + + if (shouldCommit) { + await this.gitAdd({ filepath: '.gitignore' }); + await this.gitCommit({ + message: ':see_no_evil: add generated tailwind to .gitignore', + }); + } + }, + ); } } diff --git a/src/commands/wall/index.ts b/src/commands/wall/index.ts index 23032be..6b41169 100644 --- a/src/commands/wall/index.ts +++ b/src/commands/wall/index.ts @@ -22,18 +22,34 @@ export default class Wall extends BaseCommand { ]; static args = [ - { name: 'terms', description: 'The search terms for the wallpaper', required: true }, + { + name: 'terms', + description: 'The search terms for the wallpaper', + required: true, + }, ]; static flags = { ...BaseCommand.flags, random: flags.boolean({ char: 'r', description: 'Pick one randomly' }), - sketchy: flags.boolean({ char: 's', description: 'Enables sketchy search' }), - general: flags.boolean({ char: 'g', description: 'Enable general category' }), + sketchy: flags.boolean({ + char: 's', + description: 'Enables sketchy search', + }), + general: flags.boolean({ + char: 'g', + description: 'Enable general category', + }), anime: flags.boolean({ char: 'a', description: 'Enable anime category' }), people: flags.boolean({ char: 'p', description: 'Enable people category' }), - output: flags.string({ char: 'o', description: 'Output for the wallpaper' }), - force: flags.boolean({ char: 'f', description: 'Override the file if found' }), + output: flags.string({ + char: 'o', + description: 'Output for the wallpaper', + }), + force: flags.boolean({ + char: 'f', + description: 'Override the file if found', + }), }; async run() { @@ -49,24 +65,30 @@ export default class Wall extends BaseCommand { this.error('You must use at least one category flag'); } - const resultFromSearch = await this.runWithSpinner('Searching wallpapers', async () => { - const categories = `${booleanToNumber(general)}${booleanToNumber(anime)}${booleanToNumber( - people, - )}`; - const { - data: { data }, - } = await axios.get<{ data: WallhavenItem[] }>('https://wallhaven.cc/api/v1/search', { - params: { - q: `${terms}`, - sorting: random ? 'random' : 'relevance', - categories, - purity: `1${booleanToNumber(sketchy)}0`, - atleast: '1920x1080', - ratios: '16x9', - }, - }); - return data; - }); + const resultFromSearch = await this.runWithSpinner( + 'Searching wallpapers', + async () => { + const categories = `${booleanToNumber(general)}${booleanToNumber( + anime, + )}${booleanToNumber(people)}`; + const { + data: { data }, + } = await axios.get<{ data: WallhavenItem[] }>( + 'https://wallhaven.cc/api/v1/search', + { + params: { + q: `${terms}`, + sorting: random ? 'random' : 'relevance', + categories, + purity: `1${booleanToNumber(sketchy)}0`, + atleast: '1920x1080', + ratios: '16x9', + }, + }, + ); + return data; + }, + ); if (!resultFromSearch || resultFromSearch.length === 0) { this.error('No image found, try another search term'); @@ -77,7 +99,7 @@ export default class Wall extends BaseCommand { const filename = output ? output : `wallhaven-${firstImage.id}.jpg`; - await this.runWithSpinner('Downloading wallpaper', async spinner => { + await this.runWithSpinner('Downloading wallpaper', async (spinner) => { if (filesystem.exists(filename)) { if (force) { spinner.warn(`Overriding ${filename}`); diff --git a/src/utls/base-add-command.spec.ts b/src/utls/base-add-command.spec.ts index 58c27b3..db19b6e 100644 --- a/src/utls/base-add-command.spec.ts +++ b/src/utls/base-add-command.spec.ts @@ -162,7 +162,11 @@ describe('BaseAddCommand', () => { await RunCommand.run(['initGit']); // eslint-disable-next-line unicorn/catch-error-name } catch (e) { - expect(e).toEqual(new Error('There is unsaved changed in the git repository, aborting')); + expect(e).toEqual( + new Error( + 'There is unsaved changed in the git repository, aborting', + ), + ); } }); } @@ -191,7 +195,9 @@ describe('BaseAddCommand', () => { await RunCommand.run(['initGit']); const gitConfig = filesystem.read('.git/config'); expect(gitConfig).toBeDefined(); - const gitConfigLines = gitConfig?.split('\n')?.map(value => value.trim()); + const gitConfigLines = gitConfig + ?.split('\n') + ?.map((value) => value.trim()); expect(gitConfigLines).toContainEqual('email = bbb'); expect(gitConfigLines).toContainEqual('name = aaa'); }); @@ -211,44 +217,70 @@ describe('BaseAddCommand', () => { describe('hasDependencyInPackageJson', () => { it('should return false if no packageJson is in the path', async () => { - const result = await RunCommand.run(['hasDependencyInPackageJson', 'testDep']); + const result = await RunCommand.run([ + 'hasDependencyInPackageJson', + 'testDep', + ]); expect(result).toBeFalsy(); }); it('should return false if the dependencies is not in package json', async () => { filesystem.write('package.json', { dependencies: {} }); - const result = await RunCommand.run(['hasDependencyInPackageJson', 'testDep']); + const result = await RunCommand.run([ + 'hasDependencyInPackageJson', + 'testDep', + ]); expect(result).toBeFalsy(); }); it('should return false if there is no dependencies in package json', async () => { filesystem.write('package.json', {}); - const result = await RunCommand.run(['hasDependencyInPackageJson', 'testDep']); + const result = await RunCommand.run([ + 'hasDependencyInPackageJson', + 'testDep', + ]); expect(result).toBeFalsy(); }); it('should return true if no packageJson is in the path', async () => { filesystem.write('package.json', { dependencies: { testDep: 'v1.0.0' } }); - const result = await RunCommand.run(['hasDependencyInPackageJson', 'testDep']); + const result = await RunCommand.run([ + 'hasDependencyInPackageJson', + 'testDep', + ]); expect(result).toBeTruthy(); }); }); describe('hasDevDependencyInPackageJson', () => { it('should return false if no packageJson is in the path', async () => { - const result = await RunCommand.run(['hasDevDependencyInPackageJson', 'testDep']); + const result = await RunCommand.run([ + 'hasDevDependencyInPackageJson', + 'testDep', + ]); expect(result).toBeFalsy(); }); it('should return false if the dependencies is not in package json', async () => { filesystem.write('package.json', { devDependencies: {} }); - const result = await RunCommand.run(['hasDevDependencyInPackageJson', 'testDep']); + const result = await RunCommand.run([ + 'hasDevDependencyInPackageJson', + 'testDep', + ]); expect(result).toBeFalsy(); }); it('should return false if there is no dependencies in package json', async () => { filesystem.write('package.json', {}); - const result = await RunCommand.run(['hasDevDependencyInPackageJson', 'testDep']); + const result = await RunCommand.run([ + 'hasDevDependencyInPackageJson', + 'testDep', + ]); expect(result).toBeFalsy(); }); it('should return true if no packageJson is in the path', async () => { - filesystem.write('package.json', { devDependencies: { testDep: 'v1.0.0' } }); - const result = await RunCommand.run(['hasDevDependencyInPackageJson', 'testDep']); + filesystem.write('package.json', { + devDependencies: { testDep: 'v1.0.0' }, + }); + const result = await RunCommand.run([ + 'hasDevDependencyInPackageJson', + 'testDep', + ]); expect(result).toBeTruthy(); }); }); @@ -292,18 +324,25 @@ describe('BaseAddCommand', () => { const chalkLatest = await latestVersion('chalk'); await RunCommand.run(['initGit']); - await RunCommand.run(['addDevDependency', 'chalk', '--opt', '--no-spinner']); + await RunCommand.run([ + 'addDevDependency', + 'chalk', + '--opt', + '--no-spinner', + ]); const after = await system.run('git log --name-status --format="%s" -1'); const afterSlitted = after .split('\n') - .map(val => val.trim()) - .map(val => stripANSI(val)) - .filter(val => val !== ''); + .map((val) => val.trim()) + .map((val) => stripANSI(val)) + .filter((val) => val !== ''); const packageJsonFinal = filesystem.read('package.json', 'json'); expect(consoleLogOutput).toMatchSnapshot(); - expect(packageJsonFinal).toStrictEqual({ devDependencies: { chalk: chalkLatest } }); + expect(packageJsonFinal).toStrictEqual({ + devDependencies: { chalk: chalkLatest }, + }); expect(afterSlitted[0]).toBe( `:heavy_plus_sign: add chalk@${chalkLatest} as a dev dependency`, ); @@ -323,7 +362,9 @@ describe('BaseAddCommand', () => { const packageJsonFinal = filesystem.read('package.json', 'json'); expect(consoleLogOutput).toMatchSnapshot(); - expect(packageJsonFinal).toStrictEqual({ devDependencies: { chalk: chalkLatest } }); + expect(packageJsonFinal).toStrictEqual({ + devDependencies: { chalk: chalkLatest }, + }); expect(after).toMatchSnapshot(); }); }); @@ -339,14 +380,18 @@ describe('BaseAddCommand', () => { const after = await system.run('git log --name-status --format="%s" -1'); const afterSlitted = after .split('\n') - .map(val => val.trim()) - .map(val => stripANSI(val)) - .filter(val => val !== ''); + .map((val) => val.trim()) + .map((val) => stripANSI(val)) + .filter((val) => val !== ''); const packageJsonFinal = filesystem.read('package.json', 'json'); expect(consoleLogOutput).toMatchSnapshot(); - expect(packageJsonFinal).toStrictEqual({ dependencies: { chalk: chalkLatest } }); - expect(afterSlitted[0]).toBe(`:heavy_plus_sign: add chalk@${chalkLatest} as a dependency`); + expect(packageJsonFinal).toStrictEqual({ + dependencies: { chalk: chalkLatest }, + }); + expect(afterSlitted[0]).toBe( + `:heavy_plus_sign: add chalk@${chalkLatest} as a dependency`, + ); expect(afterSlitted[1]).toMatch(/package\.json$/); expect(afterSlitted[2]).toMatch(/yarn\.lock$/); }); @@ -363,7 +408,9 @@ describe('BaseAddCommand', () => { const packageJsonFinal = filesystem.read('package.json', 'json'); expect(consoleLogOutput).toMatchSnapshot(); - expect(packageJsonFinal).toStrictEqual({ dependencies: { chalk: chalkLatest } }); + expect(packageJsonFinal).toStrictEqual({ + dependencies: { chalk: chalkLatest }, + }); expect(after).toMatchSnapshot(); }); }); diff --git a/src/utls/base-add-command.ts b/src/utls/base-add-command.ts index 2486482..1508332 100644 --- a/src/utls/base-add-command.ts +++ b/src/utls/base-add-command.ts @@ -31,7 +31,9 @@ export abstract class BaseAddCommand extends BaseCommand { value: config?.git?.email, }); } catch { - this.error('Could not set git config. Maybe the command was not run in a git repository.'); + this.error( + 'Could not set git config. Maybe the command was not run in a git repository.', + ); } const changes = (await statusMatrix({ dir: '.', fs })).filter( ([, head, workdir]) => head !== workdir, @@ -76,24 +78,27 @@ export abstract class BaseAddCommand extends BaseCommand { async gitAddUnstaged() { const commitsPromice = (await statusMatrix({ dir: '.', fs })) .filter(([, head, workdir]) => head !== workdir) - .map(arr => arr[0]) - .map(filepath => this.gitAdd({ filepath })); + .map((arr) => arr[0]) + .map((filepath) => this.gitAdd({ filepath })); await Promise.all(commitsPromice); } async addDevDependency(name: string, shouldCommit: boolean): Promise { - await this.runWithSpinner(`Adding ${name} as a dev dependency`, async () => { - const versionToInstall = await latestVersion(name); - await system.exec(`yarn add -D ${name}@${versionToInstall}`); - if (shouldCommit) { - await this.gitAdd({ filepath: 'package.json' }); - await this.gitAdd({ filepath: 'yarn.lock' }); - await this.gitCommit({ - message: `:heavy_plus_sign: add ${name}@${versionToInstall} as a dev dependency`, - }); - } - }); + await this.runWithSpinner( + `Adding ${name} as a dev dependency`, + async () => { + const versionToInstall = await latestVersion(name); + await system.exec(`yarn add -D ${name}@${versionToInstall}`); + if (shouldCommit) { + await this.gitAdd({ filepath: 'package.json' }); + await this.gitAdd({ filepath: 'yarn.lock' }); + await this.gitCommit({ + message: `:heavy_plus_sign: add ${name}@${versionToInstall} as a dev dependency`, + }); + } + }, + ); } async addDependency(name: string, shouldCommit: boolean): Promise { diff --git a/src/utls/base-command.spec.ts b/src/utls/base-command.spec.ts index aa2cd09..3cae35a 100644 --- a/src/utls/base-command.spec.ts +++ b/src/utls/base-command.spec.ts @@ -100,11 +100,17 @@ describe('BaseCommand', () => { describe('spinner', () => { it('should be enable by default', async () => { await SampleCommand.run(['-v']); - expect(consoleLogOutput).toContainEqual({ verbose: true, spinner: true }); + expect(consoleLogOutput).toContainEqual({ + verbose: true, + spinner: true, + }); }); it('can be disabled', async () => { await SampleCommand.run(['-v', '--no-spinner']); - expect(consoleLogOutput).toContainEqual({ verbose: true, spinner: false }); + expect(consoleLogOutput).toContainEqual({ + verbose: true, + spinner: false, + }); }); }); describe('help', () => { @@ -181,7 +187,7 @@ describe('BaseCommand', () => { }; async run() { - await this.runWithSpinner('Should be good', async spinner => { + await this.runWithSpinner('Should be good', async (spinner) => { spinner.succeed('Yay, done.'); return ''; }); @@ -239,10 +245,13 @@ describe('BaseCommand', () => { }; async run() { - const ret = await this.runWithSpinner('Should be good', async spinner => { - spinner.succeed('Yay, done.'); - return 'DONE'; - }); + const ret = await this.runWithSpinner( + 'Should be good', + async (spinner) => { + spinner.succeed('Yay, done.'); + return 'DONE'; + }, + ); expect(ret).toEqual('DONE'); } } diff --git a/src/utls/base-command.ts b/src/utls/base-command.ts index fdafc41..3b9fb7d 100644 --- a/src/utls/base-command.ts +++ b/src/utls/base-command.ts @@ -107,7 +107,9 @@ export abstract class BaseCommand extends Command { } async getConfig(): Promise<{ config: NbxConfig; path: string }> { - const cosmic = await import('cosmiconfig').then(cosmic => cosmic.cosmiconfig); + const cosmic = await import('cosmiconfig').then( + (cosmic) => cosmic.cosmiconfig, + ); const explorer = cosmic('nbx'); const data = await explorer.search(); if (!data || data.isEmpty || !data.config) {