From b13c6465c09951ede5776f060e49e7400ed53a3c Mon Sep 17 00:00:00 2001 From: Alex Kanunnikov Date: Sat, 9 Dec 2023 21:35:07 +0300 Subject: [PATCH] Improve typings (#86) * improve typings * improve types * improve typings --- plugins/drop-import-sync.ts | 46 +++++++++++++++---- plugins/ember.ts | 12 +++-- plugins/{gts-resolver.js => gts-resolver.ts} | 9 ++-- plugins/{hbs-resolver.js => hbs-resolver.ts} | 13 ++++-- plugins/{i18n-loader.js => i18n-loader.ts} | 3 +- plugins/remove-legacy-layout.ts | 48 ++++++++++++++++---- 6 files changed, 100 insertions(+), 31 deletions(-) rename plugins/{gts-resolver.js => gts-resolver.ts} (64%) rename plugins/{hbs-resolver.js => hbs-resolver.ts} (77%) rename plugins/{i18n-loader.js => i18n-loader.ts} (93%) diff --git a/plugins/drop-import-sync.ts b/plugins/drop-import-sync.ts index 403e188..72f5ff3 100644 --- a/plugins/drop-import-sync.ts +++ b/plugins/drop-import-sync.ts @@ -1,11 +1,23 @@ +import type { NodePath } from '@babel/traverse'; +import type { Program, ImportDeclaration, CallExpression } from '@babel/types'; +import type * as b from '@babel/types'; + export function dropImportSync(addons: string[]) { - return function dropImportSyncPlugin(babel) { - const { types: t } = babel; + return function dropImportSyncPlugin(babel: any) { + const { types: t } = babel as { types: typeof b }; let cnt = 0; + type State = { + file: { + opts: { + filename: string; + }; + }; + importsToAppend?: ImportDeclaration[]; + }; function keyValue() { return `_$key${cnt++}`; } - const shouldContinue = (state) => { + const shouldContinue = (state: State) => { const fName = state.file.opts.filename; return ( fName.includes('node_modules') && @@ -17,7 +29,7 @@ export function dropImportSync(addons: string[]) { name: 'drop-import-sync', // not required visitor: { Program: { - exit(path, state) { + exit(path: NodePath, state: State) { if (!shouldContinue(state)) { return; } @@ -35,24 +47,42 @@ export function dropImportSync(addons: string[]) { } }, }, - ImportDeclaration(path, state) { + ImportDeclaration(path: NodePath, state: State) { if (!shouldContinue(state)) { return; } if (path.node.source.value === '@embroider/macros') { path.node.specifiers = path.node.specifiers.filter((el) => { - return el.imported.name !== 'importSync'; + if ( + t.isImportDefaultSpecifier(el) || + t.isImportNamespaceSpecifier(el) + ) { + return true; + } + if (t.isStringLiteral(el.imported)) { + return; + } + return el.imported && el.imported.name !== 'importSync'; }); if (path.node.specifiers.length === 0) { path.remove(); } } }, - CallExpression(path, state) { + CallExpression(path: NodePath, state: State) { if (!shouldContinue(state)) { return; } - if (path.node.callee && path.node.callee.name === 'importSync') { + if (t.isV8IntrinsicIdentifier(path.node.callee)) { + return; + } + if ( + path.node.callee && + t.isIdentifier(path.node.callee) && + path.node.callee.name === 'importSync' && + path.node.arguments[0] && + t.isStringLiteral(path.node.arguments[0]) + ) { path.node.callee.name = '_$importSync'; state.importsToAppend = state.importsToAppend || []; const literalName = keyValue(); diff --git a/plugins/ember.ts b/plugins/ember.ts index 67ae17e..f56b4f7 100644 --- a/plugins/ember.ts +++ b/plugins/ember.ts @@ -9,6 +9,8 @@ import hbsResolver from './hbs-resolver'; import gtsResolver from './gts-resolver'; import i18nLoader from './i18n-loader'; import { babelHotReloadPlugin } from './hot-reload'; +import type { ASTv1 } from '@glimmer/syntax'; + const selfPath = import.meta.url + '/../..'; @@ -30,7 +32,7 @@ export function App(mode: string) { addon.babelPlugins = [ hbsResolver(isProd), - gtsResolver(isProd), + gtsResolver(), i18nLoader(), !isDev ? babel({ @@ -94,7 +96,7 @@ export function emberAppConfig( } function addonBabelConfig( - plugins = [], + plugins: unknown[] = [], isProd: boolean, enableSourceMaps = false ) { @@ -255,7 +257,7 @@ export function Addon(name: string, mode: string) { } export function defaultBabelConfig( - plugins = [], + plugins: unknown[] = [], isProd: boolean, enableSourceMaps = false ) { @@ -317,11 +319,11 @@ function templateCompilationPlugin(isProd: boolean) { refBucketTransform, isProd ? // eslint-disable-next-line @typescript-eslint/no-unused-vars - function sampleTransform(env) { + function sampleTransform() { return { name: 'skip-prod-test-selectors', visitor: { - ElementNode(node) { + ElementNode(node: ASTv1.ElementNode) { node.attributes = node.attributes.filter( (el) => !el.name.startsWith('data-test-') ); diff --git a/plugins/gts-resolver.js b/plugins/gts-resolver.ts similarity index 64% rename from plugins/gts-resolver.js rename to plugins/gts-resolver.ts index a703c0d..b23d1e9 100644 --- a/plugins/gts-resolver.js +++ b/plugins/gts-resolver.ts @@ -1,22 +1,25 @@ import { Preprocessor } from 'content-tag'; +import type { Plugin } from 'vite'; const p = new Preprocessor(); const fileRegex = /\.(gts|gjs)$/; -function tpl(raw, id) { +function tpl(raw: string, id: string) { return p.process(raw, id); } -export default function hbsResolver() { +export default function hbsResolver(): Plugin { return { name: 'gts-resolver', enforce: 'pre', transform(src, id) { - if (fileRegex.test(id, id)) { + if (fileRegex.test(id)) { return { code: tpl(src, id), map: null, // provide source map if available }; + } else { + return void 0; } }, }; diff --git a/plugins/hbs-resolver.js b/plugins/hbs-resolver.ts similarity index 77% rename from plugins/hbs-resolver.js rename to plugins/hbs-resolver.ts index c96b06a..38c3318 100644 --- a/plugins/hbs-resolver.js +++ b/plugins/hbs-resolver.ts @@ -1,13 +1,16 @@ +import type { Plugin } from 'vite'; + const fileRegex = /\.(hbs)$/; -function tpl(raw, id, isProd) { +function tpl(raw: string, id: string, isProd: boolean) { const code = raw.split('`').join('\\`'); const moduleName = id.includes('node_modules') ? id.split('node_modules/')[1] : id.split('src').pop(); - const name = moduleName.split('/components/').pop().split('.')[0]; + const name = + moduleName?.split('/components/').pop()?.split('.')[0] ?? 'unknown'; // we always want to return a template-only component // and corner-cases handled by patched ember-source, and glimmer @@ -26,16 +29,18 @@ function tpl(raw, id, isProd) { // `.trim(); } -export default function hbsResolver(isProd) { +export default function hbsResolver(isProd: boolean): Plugin { return { name: 'hbs-resolver', enforce: 'pre', transform(src, id) { - if (fileRegex.test(id, id)) { + if (fileRegex.test(id)) { return { code: tpl(src, id, isProd), map: null, // provide source map if available }; + } else { + return void 0; } }, }; diff --git a/plugins/i18n-loader.js b/plugins/i18n-loader.ts similarity index 93% rename from plugins/i18n-loader.js rename to plugins/i18n-loader.ts index 0a2dcea..3dd2e67 100644 --- a/plugins/i18n-loader.js +++ b/plugins/i18n-loader.ts @@ -2,11 +2,12 @@ import YAML from 'yaml'; import { readdir, access, readFile } from 'fs/promises'; import { basename, extname, join } from 'path'; import { constants } from 'fs'; +import type { Plugin } from 'vite'; const translationsFileName = 'ember-intl/translations'; const translationsDir = 'translations'; -export default function i18nLoader() { +export default function i18nLoader(): Plugin { return { name: 'i18n-loader', enforce: 'pre', diff --git a/plugins/remove-legacy-layout.ts b/plugins/remove-legacy-layout.ts index c3303d6..02b66a7 100644 --- a/plugins/remove-legacy-layout.ts +++ b/plugins/remove-legacy-layout.ts @@ -1,18 +1,35 @@ +import type { NodePath } from '@babel/traverse'; +import type { + Program, + ImportDeclaration, + ObjectProperty, + ClassProperty, +} from '@babel/types'; +import type * as b from '@babel/types'; + export function removeLegacyLayout(addons: string[]) { - return function removeLegacyLayoutPlugin (babel) { - const shouldContinue = (state) => { + return function removeLegacyLayoutPlugin(babel: any) { + type State = { + file: { + opts: { + filename: string; + }; + }; + shouldAppendLayout?: boolean; + }; + const shouldContinue = (state: State) => { const fName = state.file.opts.filename; return ( fName.includes('node_modules') && addons.some((el) => fName.includes(`/${el}/`)) ); }; - const { types: t } = babel; + const { types: t } = babel as { types: typeof b }; return { name: 'remove-layout', visitor: { Program: { - exit(path, state) { + exit(path: NodePath, state: State) { if (state.shouldAppendLayout) { path.node.body.push( t.variableDeclaration('var', [ @@ -25,7 +42,7 @@ export function removeLegacyLayout(addons: string[]) { } }, }, - ImportDeclaration(path, state) { + ImportDeclaration(path: NodePath, state: State) { if (!shouldContinue(state)) { return; } @@ -46,10 +63,16 @@ export function removeLegacyLayout(addons: string[]) { state.shouldAppendLayout = true; } }, - ObjectProperty(path, state) { + ObjectProperty(path: NodePath, state: State) { if (!shouldContinue(state)) { return; } + if ( + !t.isIdentifier(path.node.key) || + !t.isIdentifier(path.node.value) + ) { + return; + } if ( path.node.value.name === 'layout' && path.node.key.name === 'layout' @@ -57,10 +80,16 @@ export function removeLegacyLayout(addons: string[]) { path.remove(); } }, - ClassProperty(path, state) { + ClassProperty(path: NodePath, state: State) { if (!shouldContinue(state)) { return; } + if ( + !t.isIdentifier(path.node.key) || + !t.isIdentifier(path.node.value) + ) { + return; + } if ( path.node.value && path.node.value.name === 'layout' && @@ -87,6 +116,5 @@ export function removeLegacyLayout(addons: string[]) { // }, }, }; - } - -} \ No newline at end of file + }; +}