diff --git a/files-override/.eslintrc.cjs b/files-override/.eslintrc.cjs new file mode 100644 index 0000000..fb0ac4d --- /dev/null +++ b/files-override/.eslintrc.cjs @@ -0,0 +1,98 @@ +'use strict'; + +module.exports = { + overrides: [ + { + files: ['*.{js,ts,mjs,cjs}'], + plugins: ['ember'], + parser: '@typescript-eslint/parser', + extends: ['eslint:recommended', 'plugin:ember/recommended'], + }, + { + files: ['*.gts'], + parser: 'ember-eslint-parser', + plugins: ['ember'], + extends: [ + 'eslint:recommended', + 'plugin:ember/recommended', + 'plugin:ember/recommended-gts', + ], + }, + { + files: ['*.gjs'], + parser: 'ember-eslint-parser', + plugins: ['ember'], + extends: [ + 'eslint:recommended', + 'plugin:ember/recommended', + 'plugin:ember/recommended-gjs', + ], + }, + // test files + { + files: ['tests/**/*-test.{js,ts}'], + plugins: ['ember'], + parser: '@typescript-eslint/parser', + extends: ['eslint:recommended', 'plugin:qunit/recommended'], + }, + { + files: ['tests/**/*-test.{gjs,gts}'], + parser: 'ember-eslint-parser', + plugins: ['ember'], + extends: [ + 'eslint:recommended', + 'plugin:ember/recommended', + 'plugin:ember/recommended-gts', + ], + }, + { + files: ['*.gts', '*.ts'], + plugins: ['no-relative-import-paths'], + settings: { + node: { + tryExtensions: ['.gts', '.ts', '.js', '.module.css', '.css'], + }, + }, + rules: { + 'no-relative-import-paths/no-relative-import-paths': [ + 'warn', + { allowSameFolder: true, rootDir: 'app', prefix: 'discord-clone' }, + ], + 'n/file-extension-in-import': [ + 'error', + 'always', + { + '.css': 'always', + '.module.css': 'always', + '.gts': 'never', + '.ts': 'never', + '.js': 'never', + }, + ], + }, + }, + + // node files + { + files: [ + './.eslintrc.{js,cjs}', + './.prettierrc.{js,cjs}', + './.stylelintrc.{js,cjs}', + './.template-lintrc.{js,cjs}', + './ember-cli-build.js', + './testem.js', + './blueprints/*/index.js', + './config/**/*.js', + './lib/*/index.js', + './server/**/*.js', + '*.mjs', + '*.cjs', + ], + env: { + browser: false, + node: true, + }, + extends: ['plugin:n/recommended'], + }, + ], +}; diff --git a/files-override/.prettierrc.cjs b/files-override/.prettierrc.cjs new file mode 100644 index 0000000..6197eb1 --- /dev/null +++ b/files-override/.prettierrc.cjs @@ -0,0 +1,34 @@ +'use strict'; + +module.exports = { + plugins: ['prettier-plugin-ember-template-tag'], + overrides: [ + { + files: ['*.js', '*.ts', '*.cjs', '.mjs', '.cts', '.mts', '.cts'], + options: { + singleQuote: true, + trailingComma: 'es5', + }, + }, + { + files: ['*.json'], + options: { + singleQuote: false, + }, + }, + { + files: ['*.hbs'], + options: { + singleQuote: false, + }, + }, + { + files: ['*.gjs', '*.gts'], + options: { + singleQuote: true, + templateSingleQuote: false, + trailingComma: 'es5', + }, + }, + ], +}; diff --git a/files-override/app/app.js b/files-override/app/app.ts similarity index 100% rename from files-override/app/app.js rename to files-override/app/app.ts diff --git a/files-override/tsconfig.json b/files-override/tsconfig.json new file mode 100644 index 0000000..db88a01 --- /dev/null +++ b/files-override/tsconfig.json @@ -0,0 +1,46 @@ +{ + "extends": "@tsconfig/ember/tsconfig.json", + "include": [ + "app/**/*", + "tests/**/*", + ], + "glint": { + "environment": [ + "ember-loose", + "ember-template-imports" + ] + }, + "compilerOptions": { + "allowJs": true, + /** + https://www.typescriptlang.org/tsconfig#noEmitOnError + Do not block emit on TS errors. + */ + "noEmitOnError": false, + + "declaration": false, + "declarationMap": false, + + /** + https://www.typescriptlang.org/tsconfig#allowImportingTsExtensions + + We want our tooling to know how to resolve our custom files so the appropriate plugins + can do the proper transformations on those files. + */ + "allowImportingTsExtensions": true, + "paths": { + "<%= name %./tests/*": [ + "./tests/*" + ], + "<%= naem %./*": [ + "./app/*" + ], + "*": [ + "./types/*" + ] + }, + "types": [ + "ember-source/types" + ] + }, +} diff --git a/files/babel.config.cjs b/files/babel.config.cjs index 419088a..9572987 100644 --- a/files/babel.config.cjs +++ b/files/babel.config.cjs @@ -5,6 +5,14 @@ const { module.exports = { plugins: [ + [ + '@babel/plugin-transform-typescript', + { + allExtensions: true, + onlyRemoveTypeImports: true, + allowDeclareFields: true, + }, + ], [ 'babel-plugin-ember-template-compilation', { diff --git a/index.js b/index.js index 669af02..9b965ec 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'); @@ -23,6 +23,84 @@ 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 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', + + // Upstream TypeScript blueprint is too conservative + // at the same time, ember-data has been what's holding it back + '@types/ember', + '@types/ember-data', + '@types/ember-data__adapter', + '@types/ember-data__model', + '@types/ember-data__serializer', + '@types/ember-data__store', + '@types/ember__application', + '@types/ember__array', + '@types/ember__component', + '@types/ember__controller', + '@types/ember__debug', + '@types/ember__destroyable', + '@types/ember__engine', + '@types/ember__error', + '@types/ember__helper', + '@types/ember__modifier', + '@types/ember__object', + '@types/ember__owner', + '@types/ember__polyfills', + '@types/ember__routing', + '@types/ember__runloop', + '@types/ember__service', + '@types/ember__string', + '@types/ember__template', + '@types/ember__test', + '@types/ember__utils', + + // These dependencies in the blueprint we want to keep (if they exist) + // but they are generally too out of date + '@ember/string', + '@ember/test-helpers', + 'ember-resolver', + 'eslint-plugin-ember', + 'ember-template-lint', + 'qunit-dom', + 'qunit', + 'stylelint', + 'stylelint-prettier', + 'stylelint-config-standard', + 'concurrently', + 'typescript', + + '@glint/core', + '@glint/environment-ember-loose', // currently required :( + '@glint/environment-ember-template-imports', + '@glint/template', + '@typescript-eslint/eslint-plugin', + '@typescript-eslint/parser', + ].filter((depToRemove) => existingDeps.includes(depToRemove)); + + await uninstallTask.run({ + 'save-dev': true, + verbose: false, + packages, + packageManager: options.packageManager, + }); + // this.addPackagesToProject doesn't respect the packageManager that the blueprint specified 🙈 so we're skipping a level here let installTask = this.taskFor('npm-install'); await installTask.run({ @@ -37,40 +115,46 @@ module.exports = { 'vite', '@rollup/plugin-babel', 'decorator-transforms', + + // Dependencies out of date from upstream + '@ember/string', + '@ember/test-helpers', + 'ember-resolver', + 'eslint-plugin-ember', + 'ember-template-lint', + 'qunit-dom', + 'qunit', + 'stylelint', + 'stylelint-prettier', + 'stylelint-config-standard', + 'concurrently', + 'prettier-plugin-ember-template-tag', + + // TypeScript + // Note that Vite supports TypeScript with 0 configuration on the user's part + '@babel/plugin-transform-typescript', + 'typescript', + '@glint/core', + '@glint/environment-ember-loose', // currently required :( + '@glint/environment-ember-template-imports', + '@glint/template', + '@typescript-eslint/eslint-plugin', + '@typescript-eslint/parser', ], 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', + '.eslintrc.js', + '.prettierrc.js', + 'types', + ]; for (let file of filesToDelete) { - await rm(join(options.target, file)); + await rm(join(options.target, file), { recursive: true }); } // there doesn't seem to be a way to tell ember-cli to not prompt to override files that were added in the beforeInstall