Repository: sveltejs/svelte
File: packages/svelte/scripts/generate-types.js (JavaScript)

Code before:
import { createBundle } from 'dts-buddy';

const dir = fileURLToPath(new URL('..', import.meta.url));
const pkg = JSON.parse(fs.readFileSync(`${dir}/package.json`, 'utf-8'));

// For people not using moduleResolution: 'bundler', we need to generate these files. Think about removing this in Svelte 6 or 7
// It may look weird, but the imports MUST be ending with index.js to be properly resolved in all TS modes
for (const name of ['action', 'animate', 'easing', 'motion', 'store', 'transition', 'legacy']) {
	fs.writeFileSync(`${dir}/${name}.d.ts`, "import './types/index.js';\n");
}

fs.writeFileSync(`${dir}/index.d.ts`, "import './types/index.js';\n");
fs.writeFileSync(`${dir}/compiler.d.ts`, "import './types/index.js';\n");

// TODO: Remove these in Svelte 6. They are here so that tooling (which historically made use of these) can support Svelte 4-6 in one minor version
fs.mkdirSync(`${dir}/types/compiler`, { recursive: true });
fs.writeFileSync(`${dir}/types/compiler/preprocess.d.ts`, "import '../index.js';\n");
fs.writeFileSync(`${dir}/types/compiler/interfaces.d.ts`, "import '../index.js';\n");

await createBundle({
	output: `${dir}/types/index.d.ts`,
	compilerOptions: {
		// so that types/properties with `@internal` (and its dependencies) are removed from the output
		stripInternal: true,
		paths: Object.fromEntries(
			Object.entries(pkg.imports).map(/** @param {[string,any]} import */([key, value]) => {
				return [key, [value.types ?? value.default ?? value]];
			})
		)
	},
	modules: {
		[pkg.name]: `${dir}/src/index.d.ts`,
		[`${pkg.name}/action`]: `${dir}/src/action/public.d.ts`,
		[`${pkg.name}/animate`]: `${dir}/src/animate/public.d.ts`,
		[`${pkg.name}/attachments`]: `${dir}/src/attachments/public.d.ts`,
		[`${pkg.name}/compiler`]: `${dir}/src/compiler/public.d.ts`,
		[`${pkg.name}/easing`]: `${dir}/src/easing/index.js`,
		[`${pkg.name}/legacy`]: `${dir}/src/legacy/legacy-client.js`,
		[`${pkg.name}/motion`]: `${dir}/src/motion/public.d.ts`,
		[`${pkg.name}/reactivity`]: `${dir}/src/reactivity/index-client.js`,
		[`${pkg.name}/reactivity/window`]: `${dir}/src/reactivity/window/index.js`,
		[`${pkg.name}/server`]: `${dir}/src/server/index.d.ts`,
		[`${pkg.name}/store`]: `${dir}/src/store/public.d.ts`,
		[`${pkg.name}/transition`]: `${dir}/src/transition/public.d.ts`,
		[`${pkg.name}/events`]: `${dir}/src/events/public.d.ts`,
		// TODO remove in Svelte 6
		[`${pkg.name}/types/compiler/preprocess`]: `${dir}/src/compiler/preprocess/legacy-public.d.ts`,
		[`${pkg.name}/types/compiler/interfaces`]: `${dir}/src/compiler/types/legacy-interfaces.d.ts`
	}
});


Review comment (suggestion):
`pkg.imports: any` and `Object.entries` now infers `[string, unknown]` instead of `[string, any]`. This is stricter, and what happens in .ts files, but requires an explicit param type.
This shows up quite a bit in this PR.

Code after:
import { createBundle } from 'dts-buddy';

const dir = fileURLToPath(new URL('..', import.meta.url));
const pkg = JSON.parse(fs.readFileSync(`${dir}/package.json`, 'utf-8'));

// For people not using moduleResolution: 'bundler', we need to generate these files. Think about removing this in Svelte 6 or 7
// It may look weird, but the imports MUST be ending with index.js to be properly resolved in all TS modes
for (const name of ['action', 'animate', 'easing', 'motion', 'store', 'transition', 'legacy']) {
	fs.writeFileSync(`${dir}/${name}.d.ts`, "import './types/index.js';\n");
}

fs.writeFileSync(`${dir}/index.d.ts`, "import './types/index.js';\n");
fs.writeFileSync(`${dir}/compiler.d.ts`, "import './types/index.js';\n");

// TODO: Remove these in Svelte 6. They are here so that tooling (which historically made use of these) can support Svelte 4-6 in one minor version
fs.mkdirSync(`${dir}/types/compiler`, { recursive: true });
fs.writeFileSync(`${dir}/types/compiler/preprocess.d.ts`, "import '../index.js';\n");
fs.writeFileSync(`${dir}/types/compiler/interfaces.d.ts`, "import '../index.js';\n");

await createBundle({
	output: `${dir}/types/index.d.ts`,
	compilerOptions: {
		// so that types/properties with `@internal` (and its dependencies) are removed from the output
		stripInternal: true,
		paths: Object.fromEntries(
			Object.entries(pkg.imports).map(
				/** @param {[string,any]} import */ ([key, value]) => {
					return [key, [value.types ?? value.default ?? value]];
				}
			)
		)
	},
	modules: {
		[pkg.name]: `${dir}/src/index.d.ts`,
		[`${pkg.name}/action`]: `${dir}/src/action/public.d.ts`,
		[`${pkg.name}/animate`]: `${dir}/src/animate/public.d.ts`,
		[`${pkg.name}/attachments`]: `${dir}/src/attachments/public.d.ts`,
		[`${pkg.name}/compiler`]: `${dir}/src/compiler/public.d.ts`,
		[`${pkg.name}/easing`]: `${dir}/src/easing/index.js`,
		[`${pkg.name}/legacy`]: `${dir}/src/legacy/legacy-client.js`,
		[`${pkg.name}/motion`]: `${dir}/src/motion/public.d.ts`,
		[`${pkg.name}/reactivity`]: `${dir}/src/reactivity/index-client.js`,
		[`${pkg.name}/reactivity/window`]: `${dir}/src/reactivity/window/index.js`,
		[`${pkg.name}/server`]: `${dir}/src/server/index.d.ts`,
		[`${pkg.name}/store`]: `${dir}/src/store/public.d.ts`,
		[`${pkg.name}/transition`]: `${dir}/src/transition/public.d.ts`,
		[`${pkg.name}/events`]: `${dir}/src/events/public.d.ts`,
		// TODO remove in Svelte 6
		[`${pkg.name}/types/compiler/preprocess`]: `${dir}/src/compiler/preprocess/legacy-public.d.ts`,
		[`${pkg.name}/types/compiler/interfaces`]: `${dir}/src/compiler/types/legacy-interfaces.d.ts`
	}