From 6e82b090adb1a03e3c1428bbce9c5d5852ce2c66 Mon Sep 17 00:00:00 2001 From: Pooya Parsa Date: Tue, 2 Jul 2024 14:54:38 +0200 Subject: [PATCH] refactor: add explicit return types (#412) --- README.md | 8 ++++---- eslint.config.mjs | 26 +++++++++++++++---------- examples/1.zero-config/src/utils.ts | 2 +- examples/3.untyped/src/index.ts | 3 ++- src/auto.ts | 4 ++-- src/build.ts | 6 +++--- src/builders/copy/index.ts | 2 +- src/builders/mkdist/index.ts | 2 +- src/builders/rollup/build.ts | 2 +- src/builders/rollup/config.ts | 2 +- src/builders/rollup/plugins/cjs.ts | 2 +- src/builders/rollup/plugins/esbuild.ts | 23 ++++++++++++---------- src/builders/rollup/plugins/raw.ts | 2 +- src/builders/rollup/plugins/shebang.ts | 8 ++++---- src/builders/rollup/stub.ts | 2 +- src/builders/rollup/utils.ts | 4 ++-- src/builders/rollup/watch.ts | 2 +- src/builders/untyped/index.ts | 2 +- src/utils.ts | 27 ++++++++++++++++---------- src/validate.ts | 4 ++-- test/validate.test.ts | 9 ++++++++- 21 files changed, 83 insertions(+), 59 deletions(-) diff --git a/README.md b/README.md index f8ac486..0bc63bc 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ CLI output also includes output size and exports for quick inspection. Create `src/index.ts`: -```ts +```js export const log = (...args) => { console.log(...args); }; @@ -75,7 +75,7 @@ Configuration is automatically inferred from fields in `package.json` mapped to Create `build.config.ts`: -```ts +```js export default { entries: ["./src/index"], }; @@ -87,7 +87,7 @@ See options [here](./src/types.ts). Example: -```ts +```js import { defineBuildConfig } from "unbuild"; export default defineBuildConfig({ @@ -113,7 +113,7 @@ export default defineBuildConfig({ Or with multiple builds you can declare an array of configs: -```ts +```js import { defineBuildConfig } from "unbuild"; export default defineBuildConfig([ diff --git a/eslint.config.mjs b/eslint.config.mjs index 9dd34d1..e730450 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -3,14 +3,20 @@ import unjs from "eslint-config-unjs"; // https://github.com/unjs/eslint-config export default unjs({ ignores: [ - ".git" -], + ".git", + ], rules: { - "unicorn/no-null": 0, - "unicorn/prevent-abbreviations": 0, - "unicorn/prefer-module": 0, - "unicorn/prefer-top-level-await": 0, - "@typescript-eslint/no-non-null-assertion": 0, - "@typescript-eslint/no-unused-vars": 0 -}, -}); \ No newline at end of file + "unicorn/no-null": 0, + "unicorn/prevent-abbreviations": 0, + "unicorn/prefer-module": 0, + "unicorn/prefer-top-level-await": 0, + "@typescript-eslint/no-non-null-assertion": 0, + "@typescript-eslint/no-unused-vars": 0, + }, +}, { + files: ["**/*.ts"], + rules: { + "@typescript-eslint/explicit-function-return-type": "error", + "@typescript-eslint/no-inferrable-types": "error", + } +}); diff --git a/examples/1.zero-config/src/utils.ts b/examples/1.zero-config/src/utils.ts index 892a974..bf87588 100644 --- a/examples/1.zero-config/src/utils.ts +++ b/examples/1.zero-config/src/utils.ts @@ -1,3 +1,3 @@ -export default function sum(a: number, b: number) { +export default function sum(a: number, b: number): number { return a + b; } diff --git a/examples/3.untyped/src/index.ts b/examples/3.untyped/src/index.ts index 5cbf2aa..88100aa 100644 --- a/examples/3.untyped/src/index.ts +++ b/examples/3.untyped/src/index.ts @@ -20,6 +20,7 @@ export const config = { height: 10, }, tags: { - $resolve: (val?: string[]) => ["tag1", ...(val || [])].filter(Boolean), + $resolve: (val?: string[]): string[] => + ["tag1", ...(val || [])].filter(Boolean), }, }; diff --git a/src/auto.ts b/src/auto.ts index 38afded..0dc7070 100644 --- a/src/auto.ts +++ b/src/auto.ts @@ -16,7 +16,7 @@ type InferEntriesResult = { export const autoPreset = definePreset(() => { return { hooks: { - "build:prepare"(ctx) { + "build:prepare"(ctx): void { // Disable auto if entries already provided or pkg not available if (!ctx.pkg || ctx.options.entries.length > 0) { return; @@ -167,7 +167,7 @@ export function inferEntries( return { entries, cjs, dts, warnings }; } -export const getEntrypointPaths = (path: string) => { +export const getEntrypointPaths = (path: string): string[] => { const segments = normalize(path).split("/"); return segments .map((_, index) => segments.slice(index).join("/")) diff --git a/src/build.ts b/src/build.ts index 31e2098..5ff626a 100644 --- a/src/build.ts +++ b/src/build.ts @@ -23,7 +23,7 @@ export async function build( rootDir: string, stub: boolean, inputConfig: BuildConfig = {}, -) { +): Promise { // Determine rootDir rootDir = resolve(process.cwd(), rootDir || "."); @@ -67,7 +67,7 @@ async function _build( cleanedDirs: string[], _stubMode: boolean, _watchMode: boolean, -) { +): Promise { // Resolve preset const preset = await resolvePreset( buildConfig.preset || @@ -305,7 +305,7 @@ async function _build( } } - const rPath = (p: string) => + const rPath = (p: string): string => relative(process.cwd(), resolve(options.outDir, p)); for (const entry of ctx.buildEntries.filter((e) => !e.chunk)) { let totalBytes = entry.bytes || 0; diff --git a/src/builders/copy/index.ts b/src/builders/copy/index.ts index e3ca490..982c706 100644 --- a/src/builders/copy/index.ts +++ b/src/builders/copy/index.ts @@ -7,7 +7,7 @@ import consola from "consola"; const copy = fsp.cp || fsp.copyFile; -export async function copyBuild(ctx: BuildContext) { +export async function copyBuild(ctx: BuildContext): Promise { const entries = ctx.options.entries.filter( (e) => e.builder === "copy", ) as CopyBuildEntry[]; diff --git a/src/builders/mkdist/index.ts b/src/builders/mkdist/index.ts index 9d6c53f..e306a47 100644 --- a/src/builders/mkdist/index.ts +++ b/src/builders/mkdist/index.ts @@ -4,7 +4,7 @@ import { symlink, rmdir } from "../../utils"; import type { MkdistBuildEntry, BuildContext } from "../../types"; import consola from "consola"; -export async function mkdistBuild(ctx: BuildContext) { +export async function mkdistBuild(ctx: BuildContext): Promise { const entries = ctx.options.entries.filter( (e) => e.builder === "mkdist", ) as MkdistBuildEntry[]; diff --git a/src/builders/rollup/build.ts b/src/builders/rollup/build.ts index ef6353c..8b3d6f4 100644 --- a/src/builders/rollup/build.ts +++ b/src/builders/rollup/build.ts @@ -10,7 +10,7 @@ import { getChunkFilename } from "./utils"; import { rollupStub } from "./stub"; import { rollupWatch } from "./watch"; -export async function rollupBuild(ctx: BuildContext) { +export async function rollupBuild(ctx: BuildContext): Promise { // Stub mode if (ctx.options.stub) { await rollupStub(ctx); diff --git a/src/builders/rollup/config.ts b/src/builders/rollup/config.ts index 30683cd..d3ed78f 100644 --- a/src/builders/rollup/config.ts +++ b/src/builders/rollup/config.ts @@ -133,7 +133,7 @@ export function getRollupOptions(ctx: BuildContext): RollupOptions { }), ctx.options.rollup.preserveDynamicImports && { - renderDynamicImport() { + renderDynamicImport(): { left: string; right: string } { return { left: "import(", right: ")" }; }, }, diff --git a/src/builders/rollup/plugins/cjs.ts b/src/builders/rollup/plugins/cjs.ts index 609173c..2bba6d0 100644 --- a/src/builders/rollup/plugins/cjs.ts +++ b/src/builders/rollup/plugins/cjs.ts @@ -28,7 +28,7 @@ const require = __cjs_mod__.createRequire(import.meta.url); `; // Shim __dirname, __filename and require -function CJSToESM(code: string) { +function CJSToESM(code: string): { code: string; map: any } | null { if (code.includes(CJSShim) || !CJSyntaxRe.test(code)) { return null; } diff --git a/src/builders/rollup/plugins/esbuild.ts b/src/builders/rollup/plugins/esbuild.ts index af9a0f0..459128f 100644 --- a/src/builders/rollup/plugins/esbuild.ts +++ b/src/builders/rollup/plugins/esbuild.ts @@ -52,7 +52,7 @@ export function esbuild(options: EsbuildOptions): Plugin { } } } - const getLoader = (id = "") => { + const getLoader = (id = ""): Loader | undefined => { return loaders[extname(id)]; }; @@ -61,7 +61,7 @@ export function esbuild(options: EsbuildOptions): Plugin { return { name: "esbuild", - async transform(code, id) { + async transform(code, id): Promise { if (!filter(id)) { return null; } @@ -79,15 +79,18 @@ export function esbuild(options: EsbuildOptions): Plugin { printWarnings(id, result, this); - return ( - result.code && { - code: result.code, - map: result.map || null, - } - ); + return result.code + ? { + code: result.code, + map: result.map || null, + } + : null; }, - async renderChunk(code, { fileName }) { + async renderChunk( + code, + { fileName }, + ): Promise { if (!options.minify) { return null; } @@ -118,7 +121,7 @@ function printWarnings( id: string, result: TransformResult, plugin: PluginContext, -) { +): void { if (result.warnings) { for (const warning of result.warnings) { let message = "[esbuild]"; diff --git a/src/builders/rollup/plugins/raw.ts b/src/builders/rollup/plugins/raw.ts index 112b5ff..54e0ec3 100644 --- a/src/builders/rollup/plugins/raw.ts +++ b/src/builders/rollup/plugins/raw.ts @@ -17,7 +17,7 @@ export function rawPlugin(opts: RawLoaderOptions = {}): Plugin { const filter = createFilter(opts.include, opts.exclude); return { name: "unbuild-raw", - transform(code, id) { + transform(code, id): { code: string; map: any } | undefined { if (filter(id)) { return { code: `export default ${JSON.stringify(code)}`, diff --git a/src/builders/rollup/plugins/shebang.ts b/src/builders/rollup/plugins/shebang.ts index ea9a0d7..f92c919 100644 --- a/src/builders/rollup/plugins/shebang.ts +++ b/src/builders/rollup/plugins/shebang.ts @@ -9,7 +9,7 @@ const SHEBANG_RE = /^#![^\n]*/; export function shebangPlugin(): Plugin { return { name: "unbuild-shebang", - async writeBundle(options, bundle) { + async writeBundle(options, bundle): Promise { for (const [fileName, output] of Object.entries(bundle)) { if (output.type !== "chunk") { continue; @@ -26,17 +26,17 @@ export function shebangPlugin(): Plugin { export function removeShebangPlugin(): Plugin { return { name: "unbuild-remove-shebang", - renderChunk(code) { + renderChunk(code): string { return code.replace(SHEBANG_RE, ""); }, }; } -export async function makeExecutable(filePath: string) { +export async function makeExecutable(filePath: string): Promise { await fsp.chmod(filePath, 0o755 /* rwx r-x r-x */).catch(() => {}); } -export function getShebang(code: string, append = "\n") { +export function getShebang(code: string, append = "\n"): string { const m = code.match(SHEBANG_RE); return m ? m + append : ""; } diff --git a/src/builders/rollup/stub.ts b/src/builders/rollup/stub.ts index 06ea986..8f96950 100644 --- a/src/builders/rollup/stub.ts +++ b/src/builders/rollup/stub.ts @@ -7,7 +7,7 @@ import type { BuildContext } from "../../types"; import { makeExecutable, getShebang } from "./plugins/shebang"; import { DEFAULT_EXTENSIONS, resolveAliases } from "./utils"; -export async function rollupStub(ctx: BuildContext) { +export async function rollupStub(ctx: BuildContext): Promise { const babelPlugins = ctx.options.stubOptions.jiti.transformOptions?.babel ?.plugins as any; const importedBabelPlugins: Array = []; diff --git a/src/builders/rollup/utils.ts b/src/builders/rollup/utils.ts index 2e5c027..f2f2d31 100644 --- a/src/builders/rollup/utils.ts +++ b/src/builders/rollup/utils.ts @@ -13,7 +13,7 @@ export const DEFAULT_EXTENSIONS = [ ".json", ]; -export function resolveAliases(ctx: BuildContext) { +export function resolveAliases(ctx: BuildContext): Record { const aliases: Record = { [ctx.pkg.name!]: ctx.options.rootDir, ...ctx.options.alias, @@ -57,7 +57,7 @@ export function getChunkFilename( ctx: BuildContext, chunk: PreRenderedChunk, ext: string, -) { +): string { if (chunk.isDynamicEntry) { return `chunks/[name].${ext}`; } diff --git a/src/builders/rollup/watch.ts b/src/builders/rollup/watch.ts index 074502b..4647ad6 100644 --- a/src/builders/rollup/watch.ts +++ b/src/builders/rollup/watch.ts @@ -4,7 +4,7 @@ import type { RollupOptions } from "../../types"; import consola from "consola"; import chalk from "chalk"; -export function rollupWatch(rollupOptions: RollupOptions) { +export function rollupWatch(rollupOptions: RollupOptions): void { const watcher = _rollupWatch(rollupOptions); let inputs: string[]; diff --git a/src/builders/untyped/index.ts b/src/builders/untyped/index.ts index 631f7dd..aec6638 100644 --- a/src/builders/untyped/index.ts +++ b/src/builders/untyped/index.ts @@ -16,7 +16,7 @@ import type { } from "../../types"; import consola from "consola"; -export async function typesBuild(ctx: BuildContext) { +export async function typesBuild(ctx: BuildContext): Promise { const entries = ctx.options.entries.filter( (entry) => entry.builder === "untyped", ) as UntypedBuildEntry[]; diff --git a/src/utils.ts b/src/utils.ts index 4df62a5..8ac1b6b 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -7,11 +7,11 @@ import type { PackageJson } from "pkg-types"; import { autoPreset } from "./auto"; import type { BuildPreset, BuildConfig, BuildContext } from "./types"; -export async function ensuredir(path: string) { +export async function ensuredir(path: string): Promise { await fsp.mkdir(dirname(path), { recursive: true }); } -export function warn(ctx: BuildContext, message: string) { +export function warn(ctx: BuildContext, message: string): void { if (ctx.warnings.has(message)) { return; } @@ -19,7 +19,11 @@ export function warn(ctx: BuildContext, message: string) { ctx.warnings.add(message); } -export async function symlink(from: string, to: string, force = true) { +export async function symlink( + from: string, + to: string, + force = true, +): Promise { await ensuredir(to); if (force) { await fsp.unlink(to).catch(() => {}); @@ -27,7 +31,7 @@ export async function symlink(from: string, to: string, force = true) { await fsp.symlink(from, to, "junction"); } -export function dumpObject(obj: Record) { +export function dumpObject(obj: Record): string { return ( "{ " + Object.keys(obj) @@ -37,19 +41,19 @@ export function dumpObject(obj: Record) { ); } -export function getpkg(id = "") { +export function getpkg(id = ""): string { const s = id.split("/"); return s[0][0] === "@" ? `${s[0]}/${s[1]}` : s[0]; } -export async function rmdir(dir: string) { +export async function rmdir(dir: string): Promise { await fsp.unlink(dir).catch(() => {}); await fsp.rm(dir, { recursive: true, force: true }).catch(() => {}); } -export function listRecursively(path: string) { +export function listRecursively(path: string): string[] { const filenames = new Set(); - const walk = (path: string) => { + const walk = (path: string): void => { const files = readdirSync(path); for (const file of files) { const fullPath = resolve(path, file); @@ -143,7 +147,10 @@ export function extractExportFilenames( ); } -export function arrayIncludes(arr: (string | RegExp)[], searchElement: string) { +export function arrayIncludes( + arr: (string | RegExp)[], + searchElement: string, +): boolean { return arr.some((entry) => entry instanceof RegExp ? entry.test(searchElement) @@ -151,6 +158,6 @@ export function arrayIncludes(arr: (string | RegExp)[], searchElement: string) { ); } -export function removeExtension(filename: string) { +export function removeExtension(filename: string): string { return filename.replace(/\.(js|mjs|cjs|ts|mts|cts|json|jsx|tsx)$/, ""); } diff --git a/src/validate.ts b/src/validate.ts index e3d90c8..d7bf131 100644 --- a/src/validate.ts +++ b/src/validate.ts @@ -5,7 +5,7 @@ import { PackageJson } from "pkg-types"; import { arrayIncludes, extractExportFilenames, getpkg, warn } from "./utils"; import { BuildContext } from "./types"; -export function validateDependencies(ctx: BuildContext) { +export function validateDependencies(ctx: BuildContext): void { const usedDependencies = new Set(); const unusedDependencies = new Set( Object.keys(ctx.pkg.dependencies || {}), @@ -50,7 +50,7 @@ export function validatePackage( pkg: PackageJson, rootDir: string, ctx: BuildContext, -) { +): void { if (!pkg) { return; } diff --git a/test/validate.test.ts b/test/validate.test.ts index 360294b..1fbcd0c 100644 --- a/test/validate.test.ts +++ b/test/validate.test.ts @@ -18,6 +18,7 @@ describe("validatePackage", () => { "./cli": "./dist/cli", }, module: "dist/mod", + // @ts-expect-error TODO: fix pkg-types exports: { "./runtime/*": "./runtime/*.mjs", ".": { node: "./src/index.mts" }, @@ -60,6 +61,7 @@ describe("validateDependencies", () => { stub: false, alias: {}, replace: {}, + // @ts-expect-error rollup: { replace: false, alias: false, @@ -79,7 +81,11 @@ describe("validateDependencies", () => { it("does not print implicit deps warning for peerDependencies", () => { const logs: string[] = []; consola.mockTypes((type) => - type === "warn" ? (str: string) => logs.push(str) : () => {}, + type === "warn" + ? (str: string): void => { + logs.push(str); + } + : (): void => {}, ); validateDependencies({ @@ -99,6 +105,7 @@ describe("validateDependencies", () => { stub: false, alias: {}, replace: {}, + // @ts-expect-error rollup: { replace: false, alias: false,