diff --git a/.changeset/silent-gifts-repair.md b/.changeset/silent-gifts-repair.md new file mode 100644 index 0000000..47229ad --- /dev/null +++ b/.changeset/silent-gifts-repair.md @@ -0,0 +1,5 @@ +--- +"@effect/build-utils": patch +--- + +add pack v4 diff --git a/src/PackV4.ts b/src/PackV4.ts new file mode 100644 index 0000000..d57065b --- /dev/null +++ b/src/PackV4.ts @@ -0,0 +1,226 @@ +import * as NodeFileSystem from "@effect/platform-node/NodeFileSystem" +import * as NodePath from "@effect/platform-node/NodePath" +import { FileSystem } from "@effect/platform/FileSystem" +import { Path } from "@effect/platform/Path" +import * as Effect from "effect/Effect" +import * as Layer from "effect/Layer" +import * as Record from "effect/Record" +import { FsUtils, FsUtilsLive } from "./FsUtils" +import type { PackageJson } from "./PackageContext" +import { PackageContext, PackageContextLive } from "./PackageContext" + +export const run = Effect.gen(function*() { + const fsUtils = yield* FsUtils + const fs = yield* FileSystem + const path = yield* Path + const ctx = yield* PackageContext + + const templates = yield* fsUtils.glob("src/**/.index.ts") + const entrypoints: Record = {} + yield* Effect.forEach( + templates, + Effect.fnUntraced(function*(template) { + const directory = path.dirname(template) + const files = (yield* fs.readDirectory(directory)).map((_) => + path.basename(_) + ) + .filter((path) => path.endsWith(".ts") && !path.startsWith(".")).sort(( + a, + b + ) => a.localeCompare(b)).map((file) => + path.relative( + "src", + path.join(directory, file) + ).replace(/\.ts$/, "") + ) + + for (const file of files) { + const isIndex = file.endsWith("index") + const stripped = isIndex ? file.slice(0, -6) : file + const withDot = stripped === "" ? "." : `./${stripped}` + entrypoints[withDot] = file + } + }), + { concurrency: "inherit", discard: true } + ) + + const buildPackageJson = Effect.sync(() => { + const out: Record = { + name: ctx.packageJson.name, + version: ctx.packageJson.version, + description: ctx.packageJson.description, + license: ctx.packageJson.license, + repository: ctx.packageJson.repository, + sideEffects: [ + ...(ctx.hasCjs ? ["/dist/cjs/"] : []), + ...(ctx.hasEsm ? ["/dist/esm/"] : []) + ].flatMap((dir) => + ctx.packageJson.sideEffects.map((_) => + _.replace(".ts", ".js").replace(".tsx", ".js").replace("/src/", dir) + ) + ) + } + + const addOptional = (key: keyof PackageJson) => { + if (ctx.packageJson[key]) { + out[key as string] = ctx.packageJson[key] + } + } + + addOptional("author") + addOptional("homepage") + addOptional("dependencies") + addOptional("peerDependencies") + addOptional("peerDependenciesMeta") + addOptional("optionalDependencies") + addOptional("gitHead") + addOptional("bin") + + if (ctx.packageJson.publishConfig?.provenance === true) { + out.publishConfig = { provenance: true } + } + + if ( + ctx.packageJson.publishConfig?.executableFiles !== undefined + && ctx.packageJson.publishConfig.executableFiles.length > 0 + ) { + out.publishConfig = { + ...out.publishConfig, + executableFiles: ctx.packageJson.publishConfig.executableFiles + } + } + + if (Object.keys(entrypoints).length > 0) { + const main = "." in entrypoints ? entrypoints["."] : undefined + if (main !== undefined) { + out.main = `./dist/${ctx.hasCjs ? "cjs" : "esm"}/${main}.js` + + if (ctx.hasEsm && ctx.hasCjs) { + out.module = `./dist/esm/${main}.js` + } + + if (ctx.hasDts) { + out.types = `./dist/dts/${main}.d.ts` + } + } + + out.exports = Record.fromEntries( + Object.entries(entrypoints).map(([entry, module]) => { + return [entry, { + types: `./dist/dts/${module}.d.ts`, + import: `./dist/esm/${module}.js`, + default: `./dist/cjs/${module}.js` + }] + }) + ) + + out.typesVersions = { + "*": Record.fromEntries( + Object.entries(entrypoints) + .filter(([entry]) => entry !== ".") + .map(([entry, module]) => [entry.replace(/^\.\//, ""), [ + `./dist/dts/${module}.d.ts` + ]]) + ) + } + } + + return out + }) + + const createProxies = Effect.forEach( + Object.entries(entrypoints).filter(([entry]) => entry !== "."), + ([entry, module]) => + Effect.gen(function*() { + yield* fsUtils.mkdirCached(`dist/${entry}`) + + const out: Record = { + sideEffects: [] + } + + out.main = path.relative( + `dist/${entry}`, + `dist/dist/${ctx.hasCjs ? "cjs" : "esm"}/${module}.js` + ) + + if (ctx.hasEsm && ctx.hasCjs) { + out.module = path.relative( + `dist/${entry}`, + `dist/dist/esm/${module}.js` + ) + } + + out.types = path.relative( + `dist/${entry}`, + `dist/dist/dts/${module}.d.ts` + ) + + yield* fsUtils.writeJson(`dist/${entry}/package.json`, out) + }), + { + concurrency: "inherit", + discard: true + } + ) + + const writePackageJson = buildPackageJson.pipe( + Effect.map((_) => JSON.stringify(_, null, 2)), + Effect.flatMap((_) => fs.writeFileString("dist/package.json", _)), + Effect.withSpan("Pack-v4/buildPackageJson") + ) + + const mkDist = fsUtils.rmAndMkdir("dist") + const copyReadme = fs.copy("README.md", "dist/README.md") + const copyLicense = fs.copy("LICENSE", "dist/LICENSE") + + const copyEsm = ctx.hasEsm + ? fsUtils.rmAndCopy("build/esm", "dist/dist/esm").pipe( + Effect.zipRight(fsUtils.writeJson("dist/dist/esm/package.json", { + type: "module", + sideEffects: ctx.packageJson.sideEffects.map((_) => + _.replace(".ts", ".js").replace("/src/", "/") + ) + })) + ) + : Effect.void + const copyCjs = ctx.hasCjs + ? fsUtils.rmAndCopy("build/cjs", "dist/dist/cjs") + : Effect.void + const copyDts = ctx.hasDts + ? fsUtils.rmAndCopy("build/dts", "dist/dist/dts") + : Effect.void + const copySrc = ctx.hasSrc + ? fsUtils.rmAndCopy("src", "dist/src").pipe( + Effect.zipRight(fs.remove("dist/src/.index.ts").pipe(Effect.ignore)) + ) + : Effect.void + + const copySources = Effect.all([ + copyEsm, + copyCjs, + copyDts, + copySrc + ], { concurrency: "inherit", discard: true }).pipe( + Effect.withSpan("Pack-v4/copySources") + ) + + yield* mkDist + yield* Effect.all([ + writePackageJson, + copyReadme, + copyLicense, + copySources, + createProxies + ], { concurrency: "inherit", discard: true }).pipe( + Effect.withConcurrency(10) + ) +}).pipe( + Effect.provide( + Layer.mergeAll( + NodeFileSystem.layer, + NodePath.layerPosix, + FsUtilsLive, + PackageContextLive + ) + ) +) diff --git a/src/main.ts b/src/main.ts index bb3f0a8..fdc737d 100644 --- a/src/main.ts +++ b/src/main.ts @@ -7,6 +7,7 @@ import * as Effect from "effect/Effect" import * as PackV1 from "./PackV1" import * as PackV2 from "./PackV2" import * as PackV3 from "./PackV3" +import * as PackV4 from "./PackV4" import * as PrepareV1 from "./PrepareV1" import * as PrepareV2 from "./PrepareV2" import * as PrepareV3 from "./PrepareV3" @@ -17,6 +18,7 @@ const run = Command.make("build-utils").pipe( Command.make("pack-v1", {}, () => PackV1.run), Command.make("pack-v2", {}, () => PackV2.run), Command.make("pack-v3", {}, () => PackV3.run), + Command.make("pack-v4", {}, () => PackV4.run), Command.make("prepare-v1", {}, () => PrepareV1.run), Command.make("prepare-v2", {}, () => PrepareV2.run), Command.make("prepare-v3", {}, () => PrepareV3.run),