diff --git a/files-override/js/eslint.config.mjs b/files-override/js/eslint.config.mjs new file mode 100644 index 0000000..0d67eb3 --- /dev/null +++ b/files-override/js/eslint.config.mjs @@ -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 = { + ecmaFeatures: { modules: true }, + ecmaVersion: 'latest', +}; + +export default [ + js.configs.recommended, + prettier, + { + ignores: ['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 + */ + { + files: ['*.mjs'], + plugins: { + n, + }, + + languageOptions: { + sourceType: 'module', + ecmaVersion: 'latest', + parserOptions: esmParserOptions, + globals: { + ...globals.node, + }, + }, + }, +]; diff --git a/index.js b/index.js index 439ad66..52e1484 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,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', + ].filter((depToRemove) => existingDeps.includes(depToRemove)), + packageManager: options.packageManager, + }); + await installTask.run({ 'save-dev': true, verbose: false, @@ -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)); @@ -124,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, + }); }, }; diff --git a/tests/default.test.mjs b/tests/default.test.mjs index cd607c8..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 () => { @@ -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),