Browse Source

🐛 fix various bugs

pull/58/head
Nicolas Beaussart 6 years ago
parent
commit
3fed88a25c
  1. 15
      src/commands/add/dep.ts
  2. 60
      src/commands/add/prettier.ts
  3. 59
      src/commands/add/tailwind.ts
  4. 70
      src/commands/wall/index.ts
  5. 93
      src/utls/base-add-command.spec.ts
  6. 33
      src/utls/base-add-command.ts
  7. 23
      src/utls/base-command.spec.ts
  8. 4
      src/utls/base-command.ts

15
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.`);
}

60
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,
},
};

59
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',
});
}
},
);
}
}

70
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}`);

93
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();
});
});

33
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<void> {
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<void> {

23
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');
}
}

4
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) {

Loading…
Cancel
Save