Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[2.x] Add option to install ESLint with Prettier #412

Merged
merged 10 commits into from
Sep 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 68 additions & 0 deletions .github/workflows/coding-standards.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
name: fix code styling

on: [push]

jobs:
pint:
uses: laravel/.github/.github/workflows/coding-standards.yml@main
with:
message: "Pint: fix code styling"

eslint:
name: Lint stubs for Inertia stacks
runs-on: ubuntu-latest
needs: pint

steps:
- name: Checkout code
uses: actions/checkout@v4

# We need to pull the latest changes because the `pint` job might have pushed changes
- name: Pull Remote Changes
run: git pull

- uses: actions/setup-node@v4
with:
node-version: 20

- name: Install NPM packages
run: |
# Common packages
npm install \
eslint@^8.57.0 \
prettier@^3.3.0 \
prettier-plugin-organize-imports@^4.0.0 \
prettier-plugin-tailwindcss@^0.6.5

# React
npm install \
react@^18.2.0 \
eslint-plugin-react@^7.34.4 \
eslint-plugin-react-hooks@^4.6.2 \
eslint-plugin-prettier@^5.1.3 \
eslint-config-prettier@^9.1.0 \
@typescript-eslint/eslint-plugin@^7.16.0 \
@typescript-eslint/parser@^7.16.0

# Vue
npm install \
eslint-plugin-vue@^9.23.0 \
@rushstack/eslint-patch@^1.8.0 \
@vue/eslint-config-prettier@^9.0.0 \
@vue/eslint-config-typescript@^13.0.0

- name: Run ESLint
run: |
cp stubs/inertia-common/.prettierrc .
npx eslint --config stubs/inertia-react/.eslintrc.json stubs/inertia-react/resources/js --ext .js,.jsx --fix
npx eslint --config stubs/inertia-react-ts/.eslintrc.json stubs/inertia-react-ts/resources/js --ext .js,.jsx,.ts,.tsx --fix
npx eslint --config stubs/inertia-vue/.eslintrc.cjs stubs/inertia-vue/resources/js --ext .js,.vue --fix
npx eslint --config stubs/inertia-vue-ts/.eslintrc.cjs stubs/inertia-vue-ts/resources/js --ext .js,.ts,.vue --fix

- name: Clean up
run: rm -rf node_modules package.json package-lock.json .prettierrc

- name: Commit changes
uses: stefanzweifel/git-auto-commit-action@v5
with:
commit_message: "ESLint: fix code styling"
2 changes: 1 addition & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ on:

jobs:
stub-tests:
runs-on: ubuntu-22.04
runs-on: ubuntu-latest

strategy:
fail-fast: true
Expand Down
8 changes: 0 additions & 8 deletions .styleci.yml

This file was deleted.

35 changes: 27 additions & 8 deletions src/Console/InstallCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ class InstallCommand extends Command implements PromptsForMissingInput
{--pest : Indicate that Pest should be installed}
{--ssr : Indicates if Inertia SSR support should be installed}
{--typescript : Indicates if TypeScript is preferred for the Inertia stack}
{--eslint : Indicates if ESLint with Prettier should be installed}
{--composer=global : Absolute path to the Composer binary which should be used to install packages}';

/**
Expand Down Expand Up @@ -181,7 +182,6 @@ protected function hasComposerPackage($package)
/**
* Installs the given Composer Packages into the application.
*
* @param array $packages
* @param bool $asDev
* @return bool
*/
Expand Down Expand Up @@ -209,7 +209,6 @@ protected function requireComposerPackages(array $packages, $asDev = false)
/**
* Removes the given Composer Packages from the application.
*
* @param array $packages
* @param bool $asDev
* @return bool
*/
Expand All @@ -235,9 +234,8 @@ protected function removeComposerPackages(array $packages, $asDev = false)
}

/**
* Update the "package.json" file.
* Update the dependencies in the "package.json" file.
*
* @param callable $callback
* @param bool $dev
* @return void
*/
Expand All @@ -264,6 +262,29 @@ protected static function updateNodePackages(callable $callback, $dev = true)
);
}

/**
* Update the scripts in the "package.json" file.
*
* @return void
*/
protected static function updateNodeScripts(callable $callback)
{
if (! file_exists(base_path('package.json'))) {
return;
}

$content = json_decode(file_get_contents(base_path('package.json')), true);

$content['scripts'] = $callback(
array_key_exists('scripts', $content) ? $content['scripts'] : []
);

file_put_contents(
base_path('package.json'),
json_encode($content, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT).PHP_EOL
);
}

/**
* Delete the "node_modules" directory and remove the associated lock files.
*
Expand Down Expand Up @@ -301,7 +322,7 @@ protected function replaceInFile($search, $replace, $path)
*/
protected function phpBinary()
{
return (new PhpExecutableFinder())->find(false) ?: 'php';
return (new PhpExecutableFinder)->find(false) ?: 'php';
}

/**
Expand Down Expand Up @@ -330,7 +351,6 @@ protected function runCommands($commands)
/**
* Remove Tailwind dark classes from the given files.
*
* @param \Symfony\Component\Finder\Finder $finder
* @return void
*/
protected function removeDarkClasses(Finder $finder)
Expand Down Expand Up @@ -366,8 +386,6 @@ protected function promptForMissingArgumentsUsing()
/**
* Interact further with the user if they were prompted for missing arguments.
*
* @param \Symfony\Component\Console\Input\InputInterface $input
* @param \Symfony\Component\Console\Output\OutputInterface $output
* @return void
*/
protected function afterPromptingForMissingArguments(InputInterface $input, OutputInterface $output)
Expand All @@ -381,6 +399,7 @@ protected function afterPromptingForMissingArguments(InputInterface $input, Outp
'dark' => 'Dark mode',
'ssr' => 'Inertia SSR',
'typescript' => 'TypeScript',
'eslint' => 'ESLint with Prettier',
]
))->each(fn ($option) => $input->setOption($option, true));
} elseif (in_array($stack, ['blade', 'livewire', 'livewire-functional'])) {
Expand Down
82 changes: 82 additions & 0 deletions src/Console/InstallsInertiaStacks.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,46 @@ protected function installInertiaVueStack()
});
}

if ($this->option('eslint')) {
$this->updateNodePackages(function ($packages) {
return [
'eslint' => '^8.57.0',
'eslint-plugin-vue' => '^9.23.0',
'@rushstack/eslint-patch' => '^1.8.0',
'@vue/eslint-config-prettier' => '^9.0.0',
'prettier' => '^3.3.0',
'prettier-plugin-organize-imports' => '^4.0.0',
'prettier-plugin-tailwindcss' => '^0.6.5',
] + $packages;
});

if ($this->option('typescript')) {
$this->updateNodePackages(function ($packages) {
return [
'@vue/eslint-config-typescript' => '^13.0.0',
] + $packages;
});

$this->updateNodeScripts(function ($scripts) {
return $scripts + [
'lint' => 'eslint resources/js --ext .js,.ts,.vue --ignore-path .gitignore --fix',
];
});

copy(__DIR__.'/../../stubs/inertia-vue-ts/.eslintrc.cjs', base_path('.eslintrc.cjs'));
} else {
$this->updateNodeScripts(function ($scripts) {
return $scripts + [
'lint' => 'eslint resources/js --ext .js,.vue --ignore-path .gitignore --fix',
];
});

copy(__DIR__.'/../../stubs/inertia-vue/.eslintrc.cjs', base_path('.eslintrc.cjs'));
}

copy(__DIR__.'/../../stubs/inertia-common/.prettierrc', base_path('.prettierrc'));
}

// Providers...
(new Filesystem)->copyDirectory(__DIR__.'/../../stubs/inertia-common/app/Providers', app_path('Providers'));

Expand Down Expand Up @@ -216,6 +256,48 @@ protected function installInertiaReactStack()
});
}

if ($this->option('eslint')) {
$this->updateNodePackages(function ($packages) {
return [
'eslint' => '^8.57.0',
'eslint-plugin-react' => '^7.34.4',
'eslint-plugin-react-hooks' => '^4.6.2',
'eslint-plugin-prettier' => '^5.1.3',
'eslint-config-prettier' => '^9.1.0',
'prettier' => '^3.3.0',
'prettier-plugin-organize-imports' => '^4.0.0',
'prettier-plugin-tailwindcss' => '^0.6.5',
] + $packages;
});

if ($this->option('typescript')) {
$this->updateNodePackages(function ($packages) {
return [
'@typescript-eslint/eslint-plugin' => '^7.16.0',
'@typescript-eslint/parser' => '^7.16.0',
] + $packages;
});

$this->updateNodeScripts(function ($scripts) {
return $scripts + [
'lint' => 'eslint resources/js --ext .js,.jsx,.ts,.tsx --ignore-path .gitignore --fix',
];
});

copy(__DIR__.'/../../stubs/inertia-react-ts/.eslintrc.json', base_path('.eslintrc.json'));
} else {
$this->updateNodeScripts(function ($scripts) {
return $scripts + [
'lint' => 'eslint resources/js --ext .js,.jsx --ignore-path .gitignore --fix',
];
});

copy(__DIR__.'/../../stubs/inertia-react/.eslintrc.json', base_path('.eslintrc.json'));
}

copy(__DIR__.'/../../stubs/inertia-common/.prettierrc', base_path('.prettierrc'));
}

// Providers...
(new Filesystem)->copyDirectory(__DIR__.'/../../stubs/inertia-common/app/Providers', app_path('Providers'));

Expand Down
28 changes: 14 additions & 14 deletions stubs/api/routes/auth.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,29 +9,29 @@
use Illuminate\Support\Facades\Route;

Route::post('/register', [RegisteredUserController::class, 'store'])
->middleware('guest')
->name('register');
->middleware('guest')
->name('register');

Route::post('/login', [AuthenticatedSessionController::class, 'store'])
->middleware('guest')
->name('login');
->middleware('guest')
->name('login');

Route::post('/forgot-password', [PasswordResetLinkController::class, 'store'])
->middleware('guest')
->name('password.email');
->middleware('guest')
->name('password.email');

Route::post('/reset-password', [NewPasswordController::class, 'store'])
->middleware('guest')
->name('password.store');
->middleware('guest')
->name('password.store');

Route::get('/verify-email/{id}/{hash}', VerifyEmailController::class)
->middleware(['auth', 'signed', 'throttle:6,1'])
->name('verification.verify');
->middleware(['auth', 'signed', 'throttle:6,1'])
->name('verification.verify');

Route::post('/email/verification-notification', [EmailVerificationNotificationController::class, 'store'])
->middleware(['auth', 'throttle:6,1'])
->name('verification.send');
->middleware(['auth', 'throttle:6,1'])
->name('verification.send');

Route::post('/logout', [AuthenticatedSessionController::class, 'destroy'])
->middleware('auth')
->name('logout');
->middleware('auth')
->name('logout');
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,6 @@ function ($user) use ($request) {
return $status == Password::PASSWORD_RESET
? redirect()->route('login')->with('status', __($status))
: back()->withInput($request->only('email'))
->withErrors(['email' => __($status)]);
->withErrors(['email' => __($status)]);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,6 @@ public function store(Request $request): RedirectResponse
return $status == Password::RESET_LINK_SENT
? back()->with('status', __($status))
: back()->withInput($request->only('email'))
->withErrors(['email' => __($status)]);
->withErrors(['email' => __($status)]);
}
}
Loading