From cc085cc8da69baa0afe7686e39268b885eb10f0c Mon Sep 17 00:00:00 2001 From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com> Date: Wed, 25 Sep 2024 10:42:35 -0400 Subject: [PATCH 1/8] Run linting on the generated project in CI --- tests/default.test.mjs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/default.test.mjs b/tests/default.test.mjs index cd607c8..500b0ba 100644 --- a/tests/default.test.mjs +++ b/tests/default.test.mjs @@ -54,6 +54,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), From 9bca72609b18b6c536a25903f280d3b82782c79f Mon Sep 17 00:00:00 2001 From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com> Date: Wed, 25 Sep 2024 13:56:50 -0400 Subject: [PATCH 2/8] Add eslint config --- files-override/js/eslint.config.mjs | 93 +++++++++++++++++++++++++++++ index.js | 67 +++++++++++++-------- 2 files changed, 134 insertions(+), 26 deletions(-) create mode 100644 files-override/js/eslint.config.mjs diff --git a/files-override/js/eslint.config.mjs b/files-override/js/eslint.config.mjs new file mode 100644 index 0000000..7cfcfde --- /dev/null +++ b/files-override/js/eslint.config.mjs @@ -0,0 +1,93 @@ +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 = { + ecmaFeatures: { modules: true }, + ecmaVersion: 'latest', + requireConfigFile: false, + babelOptions: { + plugins: [ + ['@babel/plugin-proposal-decorators', { decoratorsBeforeExport: true }], + ], + }, +}; + +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: ember, + }, + rules: { + ...emberRecommended.rules, + ...gjsRecommended.rules, + }, + }, + { + files: ['**/*.gjs'], + languageOptions: { + parser: emberParser, + parserOptions: esmParserOptions, + globals: { + ...globals.browser, + }, + }, + plugins: { + ember: ember, + }, + rules: { + ...emberRecommended.rules, + ...gjsRecommended.rules, + }, + }, + { + plugins: { + qunit, + }, + files: ['tests/**/*-test.{js,gjs}'], + }, + /** + * CJS node files + */ + { + files: ['**/*.cjs', 'config/**/*.js'], + plugins: { + n, + }, + + languageOptions: { + globals: { + ...globals.node, + }, + + ecmaVersion: 6, + sourceType: 'script', + }, + }, +]; diff --git a/index.js b/index.js index 439ad66..3c45dc7 100644 --- a/index.js +++ b/index.js @@ -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'); @@ -36,8 +36,39 @@ 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']; + // 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, + ].filter((depToRemove) => existingDeps.includes(depToRemove)), + packageManager: options.packageManager, + }); + await installTask.run({ 'save-dev': true, verbose: false, @@ -50,37 +81,21 @@ module.exports = { 'vite', '@rollup/plugin-babel', 'decorator-transforms', + + ...ensureLatestDeps, + // Needed for eslint + 'globals', ], 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', + ]; for (let file of filesToDelete) { await rm(join(options.target, file)); From c4ef35ea52a90974786dcc7972ee8699472057d6 Mon Sep 17 00:00:00 2001 From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com> Date: Wed, 25 Sep 2024 15:47:19 -0400 Subject: [PATCH 3/8] Linting now works for all files --- files-override/js/eslint.config.mjs | 37 ++++++++++++++++++++++------- index.js | 12 +++++++++- 2 files changed, 39 insertions(+), 10 deletions(-) diff --git a/files-override/js/eslint.config.mjs b/files-override/js/eslint.config.mjs index 7cfcfde..a14676f 100644 --- a/files-override/js/eslint.config.mjs +++ b/files-override/js/eslint.config.mjs @@ -15,12 +15,6 @@ import babelParser from '@babel/eslint-parser'; const esmParserOptions = { ecmaFeatures: { modules: true }, ecmaVersion: 'latest', - requireConfigFile: false, - babelOptions: { - plugins: [ - ['@babel/plugin-proposal-decorators', { decoratorsBeforeExport: true }], - ], - }, }; export default [ @@ -76,18 +70,43 @@ export default [ * CJS node files */ { - files: ['**/*.cjs', 'config/**/*.js'], + files: [ + '**/*.cjs', + 'config/**/*.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 + */ + { + files: ['*.mjs'], + plugins: { + n, + }, - ecmaVersion: 6, - sourceType: 'script', + languageOptions: { + sourceType: 'module', + ecmaVersion: 'latest', + parserOptions: esmParserOptions, + globals: { + ...globals.node, + }, }, }, ]; diff --git a/index.js b/index.js index 3c45dc7..1fba541 100644 --- a/index.js +++ b/index.js @@ -45,7 +45,12 @@ module.exports = { ...Object.keys(manifest.devDependencies || {}), ]; - let ensureLatestDeps = ['eslint', 'eslint-plugin-ember', 'eslint-plugin-n']; + 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'); @@ -65,6 +70,8 @@ module.exports = { 'ember-cli-terser', ...ensureLatestDeps, + // Linting + '@babel/plugin-proposal-decorators', ].filter((depToRemove) => existingDeps.includes(depToRemove)), packageManager: options.packageManager, }); @@ -85,6 +92,7 @@ module.exports = { ...ensureLatestDeps, // Needed for eslint 'globals', + 'babel-plugin-ember-template-compilation', ], packageManager: options.packageManager, }); @@ -95,6 +103,8 @@ module.exports = { '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) { From 74cc608b8c578f868fac5a29264f0111cd563225 Mon Sep 17 00:00:00 2001 From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com> Date: Wed, 25 Sep 2024 15:48:53 -0400 Subject: [PATCH 4/8] Always put files on top --- files-override/js/eslint.config.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files-override/js/eslint.config.mjs b/files-override/js/eslint.config.mjs index a14676f..7d71ef2 100644 --- a/files-override/js/eslint.config.mjs +++ b/files-override/js/eslint.config.mjs @@ -61,10 +61,10 @@ export default [ }, }, { + files: ['tests/**/*-test.{js,gjs}'], plugins: { qunit, }, - files: ['tests/**/*-test.{js,gjs}'], }, /** * CJS node files From 95c9f89a77ae8fcf10fa4d42365b2e0ad313f8d3 Mon Sep 17 00:00:00 2001 From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com> Date: Wed, 25 Sep 2024 15:49:23 -0400 Subject: [PATCH 5/8] use ember shorthand --- files-override/js/eslint.config.mjs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/files-override/js/eslint.config.mjs b/files-override/js/eslint.config.mjs index 7d71ef2..8457758 100644 --- a/files-override/js/eslint.config.mjs +++ b/files-override/js/eslint.config.mjs @@ -36,7 +36,7 @@ export default [ }, }, plugins: { - ember: ember, + ember, }, rules: { ...emberRecommended.rules, @@ -53,7 +53,7 @@ export default [ }, }, plugins: { - ember: ember, + ember, }, rules: { ...emberRecommended.rules, From 9962dbd8b04803714f2eab2ae3eae1ec4dcdea8f Mon Sep 17 00:00:00 2001 From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com> Date: Wed, 25 Sep 2024 16:02:46 -0400 Subject: [PATCH 6/8] run lint:fix after generation --- index.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/index.js b/index.js index 1fba541..52e1484 100644 --- a/index.js +++ b/index.js @@ -149,5 +149,16 @@ module.exports = { }); await this.updateDeps(options); + + const lintFix = require('ember-cli/lib/utilities/lint-fix'); + + await lintFix.run({ + // Mock Project + pkg: { + scripts: { 'lint:fix': true }, + }, + ui: this.ui, + root: options.target, + }); }, }; From 64e9c30d6951ea611d346d3b7240805d6bdc6636 Mon Sep 17 00:00:00 2001 From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com> Date: Wed, 25 Sep 2024 16:22:22 -0400 Subject: [PATCH 7/8] run lint:fix after copying the fixtures --- files-override/js/eslint.config.mjs | 1 + tests/default.test.mjs | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/files-override/js/eslint.config.mjs b/files-override/js/eslint.config.mjs index 8457758..2a9d014 100644 --- a/files-override/js/eslint.config.mjs +++ b/files-override/js/eslint.config.mjs @@ -74,6 +74,7 @@ export default [ '**/*.cjs', 'config/**/*.js', 'testem.js', + 'testem*.js', '.prettierrc.js', '.stylelintrc.js', '.template-lintrc.js', diff --git a/tests/default.test.mjs b/tests/default.test.mjs index 500b0ba..6f72a23 100644 --- a/tests/default.test.mjs +++ b/tests/default.test.mjs @@ -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 () => { From a41a0c164399a46367a15b735ce4a9e5c9aa5c1a Mon Sep 17 00:00:00 2001 From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com> Date: Wed, 25 Sep 2024 18:53:52 -0400 Subject: [PATCH 8/8] Vendor isn't ignored in the upstream blueprint --- files-override/js/eslint.config.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files-override/js/eslint.config.mjs b/files-override/js/eslint.config.mjs index 2a9d014..0d67eb3 100644 --- a/files-override/js/eslint.config.mjs +++ b/files-override/js/eslint.config.mjs @@ -21,7 +21,7 @@ export default [ js.configs.recommended, prettier, { - ignores: ['vendor/', 'dist/', 'node_modules/', 'coverage/', '!**/.*'], + ignores: ['dist/', 'node_modules/', 'coverage/', '!**/.*'], linterOptions: { reportUnusedDisableDirectives: 'error', },