@ember-apply/typescript
Version:
ember-apply plugin for adding typescript to an existing app
128 lines (104 loc) • 3.3 kB
JavaScript
// @ts-check
import assert from 'node:assert';
import { dirname } from 'node:path';
import { fileURLToPath } from 'node:url';
import { ember, packageJson, project } from 'ember-apply';
import { createConfigDTS } from './src/config-directory.js';
import {
enableTSInAddonIndex,
enableTSInECBuild,
} from './src/ensure-ts-transpilation.js';
import { setupESLint } from './src/eslint.js';
import { printDetectedInfo } from './src/info.js';
import {
adjustAddonScripts,
adjustAppScripts,
configureDependencies,
} from './src/package-json.js';
import { createAddonTSConfig, createAppTSConfig } from './src/tsconfig.js';
import {
createAddonTypesDirectory,
createAppTypesDirectory,
} from './src/types-directory.js';
/**
* Codemod to transferm a JS ember project to a TS ember project.
* - Support
* - V1 App
* - V1 Addon
* - ember-data presence forcing the ejection of built in types
* (ember-data's types are not compatible with the built in types)
*
* - No Support
* - V2 Addon
*
*/
export default async function run() {
let isEmber = await ember.isEmberProject();
assert(
isEmber,
`Project is not an ember project, so typescript will not be applied`,
);
let isAddon = await ember.isAddon();
let isApp = !isAddon;
let isV2Addon = await ember.isV2Addon();
assert(
!isV2Addon,
`Project is a V2 addon and cannot be automatically updated to use TypeScript as V2 addons have too much variation. Confer with the V2 addon blueprint's --typescript output for details on using TypeScript: https://github.com/embroider-build/addon-blueprint/`,
);
assert(
await packageJson.hasDependency('ember-source', '>= 3.24.0'),
`ember-source version must be at least 3.24`,
);
if (isApp) {
return appToTypeScript();
}
return addonToTypeScript();
}
async function appToTypeScript() {
await printDetectedInfo();
await enableTSInECBuild();
await createConfigDTS();
await createAppTSConfig();
await createAppTypesDirectory();
await adjustAppScripts();
await setupESLint();
await configureDependencies();
// Grrr GlimmerVM
await fixPre1dot0GlimmerAndPnpm();
let manager = await project.getPackageManager();
console.info(`
✨✨✨
🥳 Your JavaScript app is now a TypeScript app 🥳
Tasks to manually do
- run '${manager} install'
- make sure '${manager} run lint:types' succeeds
- commit!
✨✨✨
`);
}
async function addonToTypeScript() {
await enableTSInECBuild(); // dummy app
await enableTSInAddonIndex();
await createAddonTSConfig();
await createAddonTypesDirectory();
await adjustAddonScripts();
await setupESLint();
await configureDependencies();
}
/**
* Without this we get a super old copy of manager/validator in the 0.4x range
*/
async function fixPre1dot0GlimmerAndPnpm() {
let manager = await project.getPackageManager();
if (manager !== 'pnpm') return;
let root = await project.workspaceRoot();
await packageJson.modify((json) => {
json.pnpm ||= {};
json.pnpm.overrides ||= {};
json.pnpm.overrides['@glimmer/manager'] ||= '>= 0.84.3';
json.pnpm.overrides['@glimmer/validator'] ||= '>= 0.84.3';
}, root);
}
// @ts-ignore
const __dirname = dirname(fileURLToPath(import.meta.url));
run.path = __dirname;