diff --git a/.prettierrc.cjs b/.prettierrc.cjs index 534e6d3..0b229aa 100644 --- a/.prettierrc.cjs +++ b/.prettierrc.cjs @@ -2,4 +2,12 @@ module.exports = { singleQuote: true, + overrides: [ + { + files: ['*.js', '*.ts', '*.cjs', '.mjs', '.cts', '.mts', '.cts'], + options: { + singleQuote: true, + }, + }, + ], }; diff --git a/eslint.config.mjs b/eslint.config.mjs index 4cb8891..43d3528 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -10,6 +10,7 @@ export default [ { files: [ 'files/*/app/**/*.js', + 'files-override/**/*.mjs', 'files-override/*/app/**/*.js', 'files-override/*/tests/**/*.js', ], @@ -24,6 +25,6 @@ export default [ pluginJs.configs.recommended, eslintPluginPrettierRecommended, { - ignores: ['tests/fixture/*'], + ignores: ['tests/fixture/*', 'tests/fixture-ts/*'], }, ]; diff --git a/files-override/shared/tests/index.html b/files-override/shared/tests/index.html index e875dee..e0f45c2 100644 --- a/files-override/shared/tests/index.html +++ b/files-override/shared/tests/index.html @@ -31,7 +31,7 @@ diff --git a/files-override/ts/app/app.ts b/files-override/ts/app/app.ts new file mode 100644 index 0000000..a3c0402 --- /dev/null +++ b/files-override/ts/app/app.ts @@ -0,0 +1,13 @@ +import Application from '@ember/application'; +import compatModules from '@embroider/virtual/compat-modules'; +import Resolver from 'ember-resolver'; +import loadInitializers from 'ember-load-initializers'; +import config from './config/environment'; + +export default class App extends Application { + modulePrefix = config.modulePrefix; + podModulePrefix = config.podModulePrefix; + Resolver = Resolver.withModules(compatModules); +} + +loadInitializers(App, config.modulePrefix, compatModules); diff --git a/files-override/ts/eslint.config.mjs b/files-override/ts/eslint.config.mjs new file mode 100644 index 0000000..4fbe283 --- /dev/null +++ b/files-override/ts/eslint.config.mjs @@ -0,0 +1,146 @@ +import globals from 'globals'; +import js from '@eslint/js'; + +import ts from 'typescript-eslint'; + +import ember from 'eslint-plugin-ember'; +import emberRecommended from 'eslint-plugin-ember/configs/recommended'; +import gjsRecommended from 'eslint-plugin-ember/configs/recommended-gjs'; +import gtsRecommended from 'eslint-plugin-ember/configs/recommended-gts'; + +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 parserOptions = { + esm: { + js: { + ecmaFeatures: { modules: true }, + ecmaVersion: 'latest', + }, + ts: { + projectService: true, + tsconfigRootDir: import.meta.dirname, + }, + }, +}; + +export default ts.config( + js.configs.recommended, + prettier, + { + files: ['**/*.js'], + languageOptions: { + parser: babelParser, + parserOptions: parserOptions.esm.js, + globals: { + ...globals.browser, + }, + }, + plugins: { + ember, + }, + rules: { + ...emberRecommended.rules, + }, + }, + { + files: ['**/*.ts'], + plugins: { ember }, + languageOptions: { + parserOptions: parserOptions.esm.ts, + }, + extends: [...ts.configs.strictTypeChecked, ...emberRecommended], + }, + { + files: ['**/*.gjs'], + languageOptions: { + parser: emberParser, + parserOptions: parserOptions.esm.js, + globals: { + ...globals.browser, + }, + }, + plugins: { + ember, + }, + rules: { + ...emberRecommended.rules, + ...gjsRecommended.rules, + }, + }, + { + files: ['**/*.gts'], + plugins: { ember }, + languageOptions: { + parserOptions: parserOptions.esm.ts, + }, + extends: [ + ...ts.configs.strictTypeChecked, + ...emberRecommended, + ...gtsRecommended, + ], + }, + { + 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: parserOptions.esm.js, + globals: { + ...globals.node, + }, + }, + }, + /** + * Settings + */ + { + ignores: ['dist/', 'node_modules/', 'coverage/', '!**/.*'], + linterOptions: { + reportUnusedDisableDirectives: 'error', + }, + }, +); diff --git a/files-override/ts/tests/test-helper.ts b/files-override/ts/tests/test-helper.ts new file mode 100644 index 0000000..7f12431 --- /dev/null +++ b/files-override/ts/tests/test-helper.ts @@ -0,0 +1,14 @@ +import Application from '<%= name %>/app'; +import config from '<%= name %>/config/environment'; +import * as QUnit from 'qunit'; +import { setApplication } from '@ember/test-helpers'; +import { setup } from 'qunit-dom'; +import { start as qunitStart } from 'ember-qunit'; + +export function start() { + setApplication(Application.create(config.APP)); + + setup(QUnit.assert); + + qunitStart(); +} diff --git a/files-override/ts/tsconfig.json b/files-override/ts/tsconfig.json new file mode 100644 index 0000000..9c0c246 --- /dev/null +++ b/files-override/ts/tsconfig.json @@ -0,0 +1,45 @@ +{ + "extends": "@tsconfig/ember/tsconfig.json", + "include": [ + "app", "tests", "types" + ], + "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/*" + ], + "<%= name %>/*": [ + "./app/*" + ], + "*": [ + "./types/*" + ] + }, + "types": [ + "ember-source/types" + ] + }, +} diff --git a/files-override/ts/types/index.d.ts b/files-override/ts/types/index.d.ts new file mode 100644 index 0000000..217abbb --- /dev/null +++ b/files-override/ts/types/index.d.ts @@ -0,0 +1 @@ +/// diff --git a/files/ts/app/templates/application.gts b/files/ts/app/templates/application.gts new file mode 100644 index 0000000..542cb04 --- /dev/null +++ b/files/ts/app/templates/application.gts @@ -0,0 +1,18 @@ +import Route from 'ember-route-template'; +import { pageTitle } from 'ember-page-title'; +<% if (welcome) {%>import { WelcomePage } from 'ember-welcome-page';<% } %> + +export default Route( + +); diff --git a/files/ts/babel.config.cjs b/files/ts/babel.config.cjs new file mode 100644 index 0000000..9572987 --- /dev/null +++ b/files/ts/babel.config.cjs @@ -0,0 +1,50 @@ +const { + babelCompatSupport, + templateCompatSupport, +} = require('@embroider/compat/babel'); + +module.exports = { + plugins: [ + [ + '@babel/plugin-transform-typescript', + { + allExtensions: true, + onlyRemoveTypeImports: true, + allowDeclareFields: true, + }, + ], + [ + 'babel-plugin-ember-template-compilation', + { + compilerPath: 'ember-source/dist/ember-template-compiler.js', + enableLegacyModules: [ + 'ember-cli-htmlbars', + 'ember-cli-htmlbars-inline-precompile', + 'htmlbars-inline-precompile', + ], + transforms: [...templateCompatSupport()], + }, + ], + [ + 'module:decorator-transforms', + { + runtime: { + import: require.resolve('decorator-transforms/runtime-esm'), + }, + }, + ], + [ + '@babel/plugin-transform-runtime', + { + absoluteRuntime: __dirname, + useESModules: true, + regenerator: false, + }, + ], + ...babelCompatSupport(), + ], + + generatorOpts: { + compact: false, + }, +}; diff --git a/index.js b/index.js index 94a5b6d..583e1d8 100644 --- a/index.js +++ b/index.js @@ -3,10 +3,19 @@ const fs = require('fs'); const { join } = require('path'); const emberCliUpdate = require('./lib/ember-cli-update'); const copyWithTemplate = require('./lib/copy-with-template'); -const { rm, readFile } = require('fs/promises'); +const { rm, rmdir, readFile, lstat } = require('fs/promises'); const appBlueprint = Blueprint.lookup('app'); +async function isDirectory(path) { + try { + let stat = await lstat(path); + return stat.isDirectory(); + } catch { + return false; + } +} + module.exports = { locals(options) { return appBlueprint.locals(options); @@ -15,10 +24,11 @@ module.exports = { /** * NOTE: we can't have a "shared" file here, * as we can with files-override + * (so shared things should go in files-override/shared) */ filesPath(options) { if (options.typescript) { - throw new Error(`TypeScript is not yet supported`); + return join(this.path, 'files/ts'); } return join(this.path, 'files/js'); @@ -63,7 +73,41 @@ module.exports = { 'ember-cli-sri', 'ember-cli-terser', // Linting + // No longer needed because we explicitly define a babel config '@babel/plugin-proposal-decorators', + + // Upstream TypeScript blueprint is out of date, but + // There is concensus on removing all this from the upstream blueprint as well. + ...(options.typescript + ? [ + '@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', + ] + : []), ].filter((depToRemove) => existingDeps.includes(depToRemove)), packageManager: options.packageManager, }); @@ -81,18 +125,50 @@ module.exports = { '@rollup/plugin-babel', 'decorator-transforms', - 'eslint@latest', - 'eslint-plugin-ember@latest', - 'eslint-plugin-n@latest', - '@babel/eslint-parser@latest', - '@babel/plugin-transform-runtime@latest', - '@babel/runtime@latest', - 'ember-resolver@latest', - 'ember-load-initializers@latest', + // Dependencies out of date from upstream + // (or waiting for the release train to catch up) + 'eslint@^9.14.0', + 'eslint-plugin-ember@^12.3.1', + 'eslint-plugin-n@^17.13.1', + '@babel/eslint-parser@^7.25.9', + '@babel/plugin-transform-runtime@^7.25.9', + '@babel/runtime@^7.26.0', + 'ember-template-lint@^6.0.0', + + '@ember/string@^4.0.0', + 'ember-resolver@^13.0.2', + 'ember-load-initializers@^3.0.1', + 'qunit@^2.22.0', + 'qunit-dom@^3.3.0', + 'concurrently@^9.1.0', + // Needed for eslint 'globals', 'babel-plugin-ember-template-compilation', 'prettier-plugin-ember-template-tag', + + // TypeScript + // Note that Vite supports TypeScript with 0 configuration on the user's part + ...(options.typescript + ? [ + // See RFC: https://github.com/emberjs/rfcs/pull/1046 + 'ember-route-template', + + '@babel/plugin-transform-typescript', + // TODO: see if there is a better way we can + // sync these libraries' versions + // typescript-eslint doesn't support typescript 5.6 yet + 'typescript@~5.5.0', + '@glint/core@unstable', + '@glint/environment-ember-loose@unstable', // currently required :( + '@glint/environment-ember-template-imports@unstable', + '@glint/template@unstable', + '@types/eslint__js', + 'typescript-eslint@^8.13.0', + '@typescript-eslint/eslint-plugin@^8.13.0', + '@typescript-eslint/parser@^8.13.0', + ] + : []), ], packageManager: options.packageManager, }); @@ -100,17 +176,48 @@ module.exports = { async afterInstall(options) { const filesToDelete = [ + // now in the project root 'app/index.html', - // replaced with the new ESLint flat config + // replaced with .eslintrc.cjs '.eslintrc.js', // This file is not supported in ESLint 9 '.eslintignore', // replaced with .prettierrc.cjs '.prettierrc.js', + + ...(options.typescript + ? [ + // Until we add application.gjs + 'app/templates/application.hbs', + // If folks are using models, they have this file. + // New projects should not be using it though + // 'types/ember-data/types/registries/model.d.ts', + 'types/global.d.ts', + ] + : []), ]; + // TODO: we should probably keep this because enabling TS for JS dev + // is actually very nice. + // Only difference would be that we don't have a lint:types + // or in-editor type-checking + if (!options.typescript) { + filesToDelete.push('tsconfig.json'); + } + for (let file of filesToDelete) { - await rm(join(options.target, file)); + let targetFile = join(options.target, file); + + // Don't try to delete TS files (for example) in a JS project + if (!fs.existsSync(targetFile)) continue; + + let isDir = await isDirectory(targetFile); + + if (isDir) { + await rmdir(targetFile); + } else { + await rm(targetFile); + } } // there doesn't seem to be a way to tell ember-cli to not prompt to override files that were added in the beforeInstall @@ -121,11 +228,19 @@ module.exports = { options, ); - copyWithTemplate( - join(__dirname, 'files-override/js'), - options.target, - options, - ); + if (options.typescript) { + copyWithTemplate( + join(__dirname, 'files-override/ts'), + options.target, + options, + ); + } else { + copyWithTemplate( + join(__dirname, 'files-override/js'), + options.target, + options, + ); + } let packageJson = join(options.target, 'package.json'); let json = JSON.parse(fs.readFileSync(packageJson)); @@ -137,6 +252,10 @@ module.exports = { 'test:ember': 'vite build --mode test && ember test --path dist', }; + if (json.scripts['lint:types']) { + json.scripts['lint:types'] = 'glint'; + } + json['ember-addon'] = { type: 'app', version: 2, diff --git a/tests/default.test.mjs b/tests/default.test.mjs index 2938be1..85b9095 100644 --- a/tests/default.test.mjs +++ b/tests/default.test.mjs @@ -11,6 +11,10 @@ const SCENARIOS = [ ], fixturePath: join(import.meta.dirname, 'fixture'), }, + { + flags: ['--typescript'], + fixturePath: join(import.meta.dirname, 'fixture-ts'), + }, ]; describe('basic functionality', function () { diff --git a/tests/fixture-ts/app/initializers/test-init.ts b/tests/fixture-ts/app/initializers/test-init.ts new file mode 100644 index 0000000..249ba71 --- /dev/null +++ b/tests/fixture-ts/app/initializers/test-init.ts @@ -0,0 +1,10 @@ +/* eslint-disable @typescript-eslint/no-unsafe-member-access */ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import type Application from '@ember/application'; + +export default { + name: 'test-init', + initialize(application: Application) { + (application as any).__test_init = 'coming from the initializer'; + }, +}; diff --git a/tests/fixture-ts/app/instance-initializers/test-instance-init.ts b/tests/fixture-ts/app/instance-initializers/test-instance-init.ts new file mode 100644 index 0000000..07f873a --- /dev/null +++ b/tests/fixture-ts/app/instance-initializers/test-instance-init.ts @@ -0,0 +1,10 @@ +/* eslint-disable @typescript-eslint/no-unsafe-member-access */ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import type ApplicationInstance from '@ember/application/instance'; + +export default { + name: 'test-instance-initializers', + initialize(instance: ApplicationInstance) { + (instance as any).__instance_test_init = 'set in the instance initializer'; + }, +}; diff --git a/tests/fixture-ts/app/router.ts b/tests/fixture-ts/app/router.ts new file mode 100644 index 0000000..8a5b048 --- /dev/null +++ b/tests/fixture-ts/app/router.ts @@ -0,0 +1,12 @@ +import EmberRouter from '@ember/routing/router'; +import config from '<%= name %>/config/environment'; + +export default class Router extends EmberRouter { + location = config.locationType; + rootURL = config.rootURL; +} + +Router.map(function () { + this.route('styles'); + this.route('custom-component'); +}); diff --git a/tests/fixture-ts/app/routes/styles.ts b/tests/fixture-ts/app/routes/styles.ts new file mode 100644 index 0000000..e071223 --- /dev/null +++ b/tests/fixture-ts/app/routes/styles.ts @@ -0,0 +1,8 @@ +import Route from '@ember/routing/route'; +import { service } from '@ember/service'; + +import type RouterService from '@ember/routing/router-service'; + +export default class StylesRoute extends Route { + @service declare router: RouterService; +} diff --git a/tests/fixture-ts/app/styles/app.css b/tests/fixture-ts/app/styles/app.css new file mode 100644 index 0000000..114ac2e --- /dev/null +++ b/tests/fixture-ts/app/styles/app.css @@ -0,0 +1,5 @@ +/* Ember supports plain CSS out of the box. More info: https://cli.emberjs.com/release/advanced-use/stylesheets/ */ + +.styles-test { + background-color: blue; +} diff --git a/tests/fixture-ts/app/templates/components/custom.gts b/tests/fixture-ts/app/templates/components/custom.gts new file mode 100644 index 0000000..c03b9db --- /dev/null +++ b/tests/fixture-ts/app/templates/components/custom.gts @@ -0,0 +1,5 @@ + diff --git a/tests/fixture-ts/app/templates/custom-component.gts b/tests/fixture-ts/app/templates/custom-component.gts new file mode 100644 index 0000000..32c8096 --- /dev/null +++ b/tests/fixture-ts/app/templates/custom-component.gts @@ -0,0 +1,8 @@ +import Route from 'ember-route-template'; +import Custom from './components/custom'; + +export default Route( + +); diff --git a/tests/fixture-ts/app/templates/index.gts b/tests/fixture-ts/app/templates/index.gts new file mode 100644 index 0000000..7d5524c --- /dev/null +++ b/tests/fixture-ts/app/templates/index.gts @@ -0,0 +1,8 @@ +import Route from 'ember-route-template'; +import { WelcomePage } from 'ember-welcome-page'; + +export default Route( + +); diff --git a/tests/fixture-ts/app/templates/styles.gts b/tests/fixture-ts/app/templates/styles.gts new file mode 100644 index 0000000..3cb15f5 --- /dev/null +++ b/tests/fixture-ts/app/templates/styles.gts @@ -0,0 +1,11 @@ +import Route from 'ember-route-template'; + +export default Route( + +); \ No newline at end of file diff --git a/tests/fixture-ts/testem-proxy.js b/tests/fixture-ts/testem-proxy.js new file mode 100644 index 0000000..d688f53 --- /dev/null +++ b/tests/fixture-ts/testem-proxy.js @@ -0,0 +1,36 @@ +/* eslint-disable */ +const httpProxy = require('http-proxy'); + +/* + This can be installed as a testem middleware to make testem run against an + arbitrary real webserver at targetURL. + + It allows testem to handle the well-known testem-specific paths and proxies + everything else, while rewriting the testem-added prefix out of your + "/tests/index.html" URL. +*/ + +module.exports = function testemProxy(targetURL) { + return function testemProxyHandler(app) { + const proxy = httpProxy.createProxyServer({ + changeOrigin: true, + ignorePath: true, + }); + + proxy.on('error', (err, _req, res) => { + res && res.status && res.status(500).json(err); + }); + + app.all('*', (req, res, next) => { + let url = req.url; + if (url === '/testem.js' || url.startsWith('/testem/')) { + return next(); + } + let m = /^(\/\d+)\/tests\/index.html/.exec(url); + if (m) { + url = url.slice(m[1].length); + } + proxy.web(req, res, { target: targetURL + url }); + }); + }; +}; diff --git a/tests/fixture-ts/tests/acceptance/app-init-test.ts b/tests/fixture-ts/tests/acceptance/app-init-test.ts new file mode 100644 index 0000000..e65bc63 --- /dev/null +++ b/tests/fixture-ts/tests/acceptance/app-init-test.ts @@ -0,0 +1,22 @@ +/* eslint-disable @typescript-eslint/no-unsafe-member-access */ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { module, test } from 'qunit'; +import { getApplication } from '@ember/test-helpers'; +import { assert as debugAssert } from '@ember/debug'; +import { setupApplicationTest } from '<%= name %>/tests/helpers'; + +module('Acceptance | app route', function (hooks) { + setupApplicationTest(hooks); + + test('loaded initializers /', function (assert) { + const app = getApplication(); + + debugAssert(`App failed to initialize`, app); + + assert.strictEqual( + ([...app._applicationInstances][0] as any).__instance_test_init, + 'set in the instance initializer', + ); + assert.strictEqual((app as any).__test_init, 'coming from the initializer'); + }); +}); diff --git a/tests/fixture-ts/tests/acceptance/custom-component-test.ts b/tests/fixture-ts/tests/acceptance/custom-component-test.ts new file mode 100644 index 0000000..24e6db0 --- /dev/null +++ b/tests/fixture-ts/tests/acceptance/custom-component-test.ts @@ -0,0 +1,14 @@ +import { module, test } from 'qunit'; +import { visit, currentURL } from '@ember/test-helpers'; +import { setupApplicationTest } from '<%= name %>/tests/helpers'; + +module('Acceptance | custom-component page', function (hooks) { + setupApplicationTest(hooks); + + test('visiting /custom-component', async function (assert) { + await visit('/custom-component'); + + assert.strictEqual(currentURL(), '/custom-component'); + assert.dom('#custom-component').containsText('I am a custom component'); + }); +}) diff --git a/tests/fixture-ts/tests/acceptance/styles-test.ts b/tests/fixture-ts/tests/acceptance/styles-test.ts new file mode 100644 index 0000000..00169a5 --- /dev/null +++ b/tests/fixture-ts/tests/acceptance/styles-test.ts @@ -0,0 +1,18 @@ +import { module, test } from 'qunit'; +import { visit } from '@ember/test-helpers'; +import { setupApplicationTest } from '<%= name %>/tests/helpers'; + +module('Acceptance | styles', function (hooks) { + setupApplicationTest(hooks); + + test('visiting /styles', async function (assert) { + await visit('/styles'); + + assert.dom('.styles-test').hasStyle( + { + 'background-color': 'rgb(0, 0, 255)', + }, + 'The background should be blue if the app styles are working correctly', + ); + }); +}); diff --git a/tests/fixture-ts/tests/acceptance/welcome-page-test.ts b/tests/fixture-ts/tests/acceptance/welcome-page-test.ts new file mode 100644 index 0000000..0ace2f3 --- /dev/null +++ b/tests/fixture-ts/tests/acceptance/welcome-page-test.ts @@ -0,0 +1,14 @@ +import { module, test } from 'qunit'; +import { visit, currentURL } from '@ember/test-helpers'; +import { setupApplicationTest } from '<%= name %>/tests/helpers'; + +module('Acceptance | welcome page', function (hooks) { + setupApplicationTest(hooks); + + test('visiting /index shows the welcome page', async function (assert) { + await visit('/'); + + assert.strictEqual(currentURL(), '/'); + assert.dom('h1').containsText('Congratulations, you made it!'); + }); +}); diff --git a/tests/fixture/app/router.ts b/tests/fixture/app/router.ts new file mode 100644 index 0000000..8a5b048 --- /dev/null +++ b/tests/fixture/app/router.ts @@ -0,0 +1,12 @@ +import EmberRouter from '@ember/routing/router'; +import config from '<%= name %>/config/environment'; + +export default class Router extends EmberRouter { + location = config.locationType; + rootURL = config.rootURL; +} + +Router.map(function () { + this.route('styles'); + this.route('custom-component'); +}); diff --git a/tests/typescript.test.mjs b/tests/typescript.test.mjs new file mode 100644 index 0000000..e308cc0 --- /dev/null +++ b/tests/typescript.test.mjs @@ -0,0 +1,24 @@ +import { describe, it, expect } from 'vitest'; +import { join } from 'path'; +import { existsSync } from 'fs'; +import { newProjectWithFixtures } from './helpers.mjs'; + +describe('typescript', function () { + let project = newProjectWithFixtures({ + fixturePath: join(__dirname, 'fixture-ts'), + flags: ['--typescript'], + }); + + it('verify files', async function () { + expect( + existsSync(join(project.dir(), 'tsconfig.json')), + 'the root tsconfig.json has been added', + ); + }); + + it('glint passes', async function () { + let result = await project.execa('pnpm', ['glint']); + + console.log(result.stdout); + }); +});