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

Run linting on the generated project in CI // add a working eslintconfig #84

Merged
merged 8 commits into from
Sep 26, 2024
Merged
Show file tree
Hide file tree
Changes from 7 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
113 changes: 113 additions & 0 deletions files-override/js/eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import globals from 'globals';
import js from '@eslint/js';

import ember from 'eslint-plugin-ember';
import emberRecommended from 'eslint-plugin-ember/configs/recommended';
import gjsRecommended from 'eslint-plugin-ember/configs/recommended-gjs';

import prettier from 'eslint-plugin-prettier/recommended';
import qunit from 'eslint-plugin-qunit';
import n from 'eslint-plugin-n';

import emberParser from 'ember-eslint-parser';
import babelParser from '@babel/eslint-parser';

const esmParserOptions = {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unlike the upstream blueprint, we have a babel config, so we don't need to specify one here

ecmaFeatures: { modules: true },
ecmaVersion: 'latest',
};

export default [
js.configs.recommended,
prettier,
{
ignores: ['vendor/', 'dist/', 'node_modules/', 'coverage/', '!**/.*'],
linterOptions: {
reportUnusedDisableDirectives: 'error',
},
},
{
files: ['**/*.js'],
languageOptions: {
parser: babelParser,
parserOptions: esmParserOptions,
globals: {
...globals.browser,
},
},
plugins: {
ember,
},
rules: {
...emberRecommended.rules,
...gjsRecommended.rules,
},
},
{
files: ['**/*.gjs'],
languageOptions: {
parser: emberParser,
parserOptions: esmParserOptions,
globals: {
...globals.browser,
},
},
plugins: {
ember,
},
rules: {
...emberRecommended.rules,
...gjsRecommended.rules,
},
},
{
files: ['tests/**/*-test.{js,gjs}'],
plugins: {
qunit,
},
},
/**
* CJS node files
*/
{
files: [
'**/*.cjs',
'config/**/*.js',
'testem.js',
'testem*.js',
'.prettierrc.js',
'.stylelintrc.js',
'.template-lintrc.js',
'ember-cli-build.js',
],
plugins: {
n,
},

languageOptions: {
sourceType: 'script',
ecmaVersion: 'latest',
globals: {
...globals.node,
},
},
},
/**
* ESM node files
*/
{
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this section isn't present in the upstream blueprint, because we have a vite.config.mjs and now eslint.config.mjs

files: ['*.mjs'],
plugins: {
n,
},

languageOptions: {
sourceType: 'module',
ecmaVersion: 'latest',
parserOptions: esmParserOptions,
globals: {
...globals.node,
},
},
},
];
88 changes: 62 additions & 26 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ const fs = require('fs');
const { join } = require('path');
const emberCliUpdate = require('./lib/ember-cli-update');
const copyWithTemplate = require('./lib/copy-with-template');
const { rm } = require('fs/promises');
const { rm, readFile } = require('fs/promises');

const appBlueprint = Blueprint.lookup('app');

Expand Down Expand Up @@ -36,8 +36,46 @@ module.exports = {
},

async updateDeps(options) {
let manifestPath = join(options.target, 'package.json');
let manifestBuffer = await readFile(manifestPath);
let manifest = JSON.parse(manifestBuffer.toString());

let existingDeps = [
...Object.keys(manifest.dependencies || {}),
...Object.keys(manifest.devDependencies || {}),
];

let ensureLatestDeps = [
'eslint',
'eslint-plugin-ember',
'eslint-plugin-n',
'@babel/eslint-parser',
];

// this.addPackagesToProject doesn't respect the packageManager that the blueprint specified 🙈 so we're skipping a level here
let installTask = this.taskFor('npm-install');
let uninstallTask = this.taskFor('npm-uninstall');

await uninstallTask.run({
'save-dev': true,
verbose: false,
packages: [
// Not needed anymore
'ember-fetch',
'broccoli-asset-rev',
'ember-cli-app-version',
'ember-cli-clean-css',
'ember-cli-dependency-checker',
'ember-cli-sri',
'ember-cli-terser',

...ensureLatestDeps,
// Linting
'@babel/plugin-proposal-decorators',
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unlike upstream, we don't want this plugin because we're using decorator-transforms in our babel config.

].filter((depToRemove) => existingDeps.includes(depToRemove)),
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

because of this filter, there is no danger to accidentally specifying something that isn't present in the upstream blueprint.

packageManager: options.packageManager,
});

await installTask.run({
'save-dev': true,
verbose: false,
Expand All @@ -50,37 +88,24 @@ module.exports = {
'vite',
'@rollup/plugin-babel',
'decorator-transforms',

...ensureLatestDeps,
// Needed for eslint
'globals',
'babel-plugin-ember-template-compilation',
],
packageManager: options.packageManager,
});

let uninstallTask = this.taskFor('npm-uninstall');
const packages = [
'ember-fetch',
'broccoli-asset-rev',
'ember-cli-app-version',
'ember-cli-clean-css',
'ember-cli-dependency-checker',
'ember-cli-sri',
'ember-cli-terser',
];

for (const package of packages) {
try {
await uninstallTask.run({
'save-dev': true,
verbose: false,
packages: [package],
packageManager: options.packageManager,
});
} catch {
console.log(`Could not uninstall ${package}`);
}
}
},

async afterInstall(options) {
const filesToDelete = ['app/index.html'];
const filesToDelete = [
'app/index.html',
// replaced with the new ESLint flat config
'.eslintrc.js',
// This file is not supported in ESLint 9
'.eslintignore',
];

for (let file of filesToDelete) {
await rm(join(options.target, file));
Expand Down Expand Up @@ -124,5 +149,16 @@ module.exports = {
});

await this.updateDeps(options);

const lintFix = require('ember-cli/lib/utilities/lint-fix');
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lint:fix wasn't running at all before and now it is (and is kinda required, since version drift could change how the output of files end up)


await lintFix.run({
// Mock Project
pkg: {
scripts: { 'lint:fix': true },
},
ui: this.ui,
root: options.target,
});
},
};
13 changes: 13 additions & 0 deletions tests/default.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ describe('basic functionality', function () {
copyWithTemplate(join(__dirname, 'fixture'), join(tmpDir.path, appName), {
name: appName,
});

// Sync the lints for the fixtures with the project's config
await execa(`pnpm`, ['lint:fix'], {
cwd: join(tmpDir.path, appName),
});
});

afterAll(async () => {
Expand All @@ -54,6 +59,14 @@ describe('basic functionality', function () {
);
});

it('successfully lints', async function () {
let result = await execa('pnpm', ['lint'], {
cwd: join(tmpDir.path, appName),
});

console.log(result.stdout);
});

it('successfully builds', async function () {
let result = await execa('pnpm', ['build'], {
cwd: join(tmpDir.path, appName),
Expand Down