Skip to content

Commit 23fb9be

Browse files
committed
feat(framework): add framework detection and shim functionality for Vue and Astro
1 parent 5d3469a commit 23fb9be

1 file changed

Lines changed: 82 additions & 0 deletions

File tree

packages/cli/src/migration/migrator.ts

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -683,6 +683,88 @@ function cleanupDeprecatedTsconfigOptions(
683683
}
684684
}
685685

686+
// Svelte is intentionally excluded: @sveltejs/vite-plugin-svelte and svelte-check handle
687+
// .svelte file types automatically. No env.d.ts shim is needed or documented officially.
688+
// https://svelte.dev/docs/svelte/typescript
689+
export type Framework = 'vue' | 'astro';
690+
691+
const FRAMEWORK_SHIMS: Record<Framework, string> = {
692+
// https://vuejs.org/guide/typescript/overview#volar-takeover-mode
693+
vue: [
694+
"declare module '*.vue' {",
695+
" import type { DefineComponent } from 'vue';",
696+
' const component: DefineComponent<{}, {}, unknown>;',
697+
' export default component;',
698+
'}',
699+
].join('\n'),
700+
// astro/client is the pre-v4.14 form; v4.14+ prefers `/// <reference path="../.astro/types.d.ts" />`
701+
// but .astro/types.d.ts is generated at build time and may not exist yet after migration.
702+
// astro/client remains valid and is still used in official Astro integrations.
703+
// https://docs.astro.build/en/guides/typescript/#extending-global-types
704+
astro: '/// <reference types="astro/client" />',
705+
};
706+
707+
export function detectFramework(projectPath: string): Framework | null {
708+
const packageJsonPath = path.join(projectPath, 'package.json');
709+
if (!fs.existsSync(packageJsonPath)) {
710+
return null;
711+
}
712+
const pkg = readJsonFile(packageJsonPath) as {
713+
dependencies?: Record<string, string>;
714+
devDependencies?: Record<string, string>;
715+
};
716+
const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
717+
for (const framework of ['vue', 'astro'] as const) {
718+
if (allDeps[framework]) {
719+
return framework;
720+
}
721+
}
722+
return null;
723+
}
724+
725+
function getEnvDtsPath(projectPath: string): string {
726+
const srcEnvDts = path.join(projectPath, 'src', 'env.d.ts');
727+
const rootEnvDts = path.join(projectPath, 'env.d.ts');
728+
for (const candidate of [srcEnvDts, rootEnvDts]) {
729+
if (fs.existsSync(candidate)) {
730+
return candidate;
731+
}
732+
}
733+
return fs.existsSync(path.join(projectPath, 'src')) ? srcEnvDts : rootEnvDts;
734+
}
735+
736+
export function hasFrameworkShim(projectPath: string, framework: Framework): boolean {
737+
const envDtsPath = getEnvDtsPath(projectPath);
738+
if (!fs.existsSync(envDtsPath)) {
739+
return false;
740+
}
741+
742+
const content = fs.readFileSync(envDtsPath, 'utf-8');
743+
if (framework === 'astro') {
744+
return content.includes('astro/client');
745+
}
746+
return content.includes(`'*.${framework}'`) || content.includes(`"*.${framework}"`);
747+
}
748+
749+
export function addFrameworkShim(
750+
projectPath: string,
751+
framework: Framework,
752+
report?: MigrationReport,
753+
): void {
754+
const envDtsPath = getEnvDtsPath(projectPath);
755+
const shim = FRAMEWORK_SHIMS[framework];
756+
if (fs.existsSync(envDtsPath)) {
757+
const existing = fs.readFileSync(envDtsPath, 'utf-8');
758+
fs.writeFileSync(envDtsPath, `${existing.trimEnd()}\n\n${shim}\n`, 'utf-8');
759+
} else {
760+
fs.mkdirSync(path.dirname(envDtsPath), { recursive: true });
761+
fs.writeFileSync(envDtsPath, `${shim}\n`, 'utf-8');
762+
}
763+
if (report) {
764+
report.frameworkShimAdded = true;
765+
}
766+
}
767+
686768
/**
687769
* Rewrite standalone project to add vite-plus dependencies
688770
* @param projectPath - The path to the project

0 commit comments

Comments
 (0)