diff --git a/swc-plugins/.eslintignore b/swc-plugins/.eslintignore index 318bf5e..7eaeda2 100644 --- a/swc-plugins/.eslintignore +++ b/swc-plugins/.eslintignore @@ -1,8 +1,3 @@ *.d.ts /lib/generated /components/ui - - -# TODO: Fix eslint config -app/ -lib/ \ No newline at end of file diff --git a/swc-plugins/.eslintrc.json b/swc-plugins/.eslintrc.json index 9ecac64..b1a0a62 100644 --- a/swc-plugins/.eslintrc.json +++ b/swc-plugins/.eslintrc.json @@ -1,6 +1,8 @@ { "extends": "next/core-web-vitals", "rules": { - "@typescript-eslint/no-unused-vars": "off" + "@typescript-eslint/no-unused-vars": "off", + "@next/next/no-server-import-in-page": "off", + "@typescript-eslint/ban-types": "off" } } diff --git a/swc-plugins/app/import/page.tsx b/swc-plugins/app/import/page.tsx deleted file mode 100644 index 22c5214..0000000 --- a/swc-plugins/app/import/page.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import fs from "node:fs/promises"; - -export default async function Page() { - if (process.env.NODE_ENV === "production") { - return
Not allowed
; - } - - const plugins = JSON.parse( - await fs.readFile("./data/.cache/plugins.json", "utf8") - ); -} - -export const dynamic = "force-dynamic"; diff --git a/swc-plugins/app/import/runtime/route.ts b/swc-plugins/app/import/runtime/route.ts new file mode 100644 index 0000000..74172a9 --- /dev/null +++ b/swc-plugins/app/import/runtime/route.ts @@ -0,0 +1,70 @@ +import { db } from "@/lib/prisma"; +import { createCaller } from "@/lib/server"; +import { NextRequest, NextResponse } from "next/server"; +import { z } from "zod"; + +const VersionSchema = z.object({ + version: z.string(), + swcCoreVersion: z.string(), +}); + +const BodySchema = z.object({ + runtime: z.enum(["@swc/core", "next", "rspack"]), + versions: z.array(VersionSchema), +}); + +export async function POST(req: NextRequest) { + if (process.env.NODE_ENV === "production") { + return NextResponse.json( + { + error: "Not allowed", + }, + { + status: 403, + } + ); + } + + const { runtime, versions } = BodySchema.parse(await req.json()); + + const rt = await db.swcRuntime.findUniqueOrThrow({ + where: { + name: runtime, + }, + }); + const api = await createCaller(); + + const items: { + runtimeId: bigint; + version: string; + compatRangeId: bigint; + swcCoreVersion: string; + }[] = []; + + for (const version of versions) { + const compatRange = await api.compatRange.byVersion({ + version: version.swcCoreVersion, + }); + if (!compatRange) { + console.log(`No compat range found for ${version.swcCoreVersion}`); + continue; + } + + items.push({ + runtimeId: rt.id, + // Just to ensure it's a valid semver + version: version.version.replace("v", ""), + compatRangeId: compatRange.id, + // Just to ensure it's a valid semver + swcCoreVersion: version.swcCoreVersion.replace("v", ""), + }); + } + + await db.swcRuntimeVersion.createMany({ + data: items, + }); + + return NextResponse.json({ + ok: true, + }); +} diff --git a/swc-plugins/data/ranges.json b/swc-plugins/data/ranges.json index 63db482..9780423 100644 --- a/swc-plugins/data/ranges.json +++ b/swc-plugins/data/ranges.json @@ -4,7 +4,7 @@ "max": "0.59.40" }, { - "min": "v0.61.0", + "min": "0.61.0", "max": "0.64.10" }, { diff --git a/swc-plugins/lib/api/compatRange/router.ts b/swc-plugins/lib/api/compatRange/router.ts index 8972132..1b110e2 100644 --- a/swc-plugins/lib/api/compatRange/router.ts +++ b/swc-plugins/lib/api/compatRange/router.ts @@ -122,11 +122,7 @@ export const compatRangeRouter = router({ }); for (const range of versions) { - if (semver.lt(version, range.from)) { - continue; - } - - if (semver.gte(version, range.to)) { + if (semver.gt(version, range.from) && semver.lt(version, range.to)) { return range; } } @@ -160,7 +156,8 @@ function merge(ranges: { name: string; version: string }[]): VersionRange[] { * @param newValue semver */ function mergeVersion(min: string, max: string, newValue: string) { - const minVersion = semver.lt(min, newValue) ? min : newValue; + const minVersion = + min !== "0.0.0" && semver.lt(min, newValue) ? min : newValue; const maxVersion = semver.gt(max, newValue) ? max : newValue; return { min: minVersion, max: maxVersion }; diff --git a/swc-plugins/package.json b/swc-plugins/package.json index 319fa46..e8d26f1 100644 --- a/swc-plugins/package.json +++ b/swc-plugins/package.json @@ -91,8 +91,10 @@ "postcss": "8.4.33", "prisma": "^5.17.0", "tailwindcss": "3.4.1", + "toml": "^3.0.0", "tsconfig-replace-paths": "^0.0.14", "typescript": "^5.5.4", - "zod-prisma-types": "^3.1.6" + "zod-prisma-types": "^3.1.6", + "zx": "^8.1.4" } } diff --git a/swc-plugins/prisma/schema.prisma b/swc-plugins/prisma/schema.prisma index fccd69e..13f46d8 100644 --- a/swc-plugins/prisma/schema.prisma +++ b/swc-plugins/prisma/schema.prisma @@ -155,14 +155,16 @@ model SwcRuntime { } model SwcRuntimeVersion { - id BigInt @id @default(autoincrement()) - runtime SwcRuntime @relation(fields: [runtimeId], references: [id], onDelete: Cascade) - runtimeId BigInt - version String - compatRange CompatRange @relation(fields: [compatRangeId], references: [id]) - compatRangeId BigInt - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt + id BigInt @id @default(autoincrement()) + runtime SwcRuntime @relation(fields: [runtimeId], references: [id], onDelete: Cascade) + runtimeId BigInt + version String + /// The version of `swc_core` used by the plugin. + swcCoreVersion String + compatRange CompatRange @relation(fields: [compatRangeId], references: [id]) + compatRangeId BigInt + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt @@unique([runtimeId, version]) } @@ -176,14 +178,17 @@ model SwcPlugin { } model SwcPluginVersion { - id BigInt @id @default(autoincrement()) - plugin SwcPlugin @relation(fields: [pluginId], references: [id], onDelete: Cascade) - pluginId BigInt - version String - compatRange CompatRange @relation(fields: [compatRangeId], references: [id]) - compatRangeId BigInt - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt + id BigInt @id @default(autoincrement()) + plugin SwcPlugin @relation(fields: [pluginId], references: [id], onDelete: Cascade) + pluginId BigInt + /// The version of the plugin. + version String + /// The version of `swc_core` used by the plugin. + swcCoreVersion String? + compatRange CompatRange @relation(fields: [compatRangeId], references: [id]) + compatRangeId BigInt + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt @@unique([pluginId, version]) } diff --git a/swc-plugins/scripts/import-runtime.mjs b/swc-plugins/scripts/import-runtime.mjs new file mode 100755 index 0000000..64f8963 --- /dev/null +++ b/swc-plugins/scripts/import-runtime.mjs @@ -0,0 +1,86 @@ +#!/usr/bin/env zx +// +// Run this script using an absolute path to the runtime directory. +import path from "path"; +import semver from "semver"; +import toml from "toml"; +import { $ } from "zx"; + +const runtimeName = process.argv[2]; +const runtimeDir = process.argv[3]; + +if (!runtimeName || !runtimeDir) { + console.error("Runtime name and directory are required"); + process.exit(1); +} + +const $$ = $({ cwd: runtimeDir }); + +const repositoryRoot = (await $$`git rev-parse --show-toplevel`.text()).trim(); +const cargoLockPath = path.resolve(`${runtimeDir}/Cargo.lock`); +const relativePathToCargoLock = path.relative(repositoryRoot, cargoLockPath); + +console.log("Runtime name:", runtimeName); +console.log("Runtime dir:", runtimeDir); +console.log("Repository root:", repositoryRoot); +console.log("Cargo.lock path:", cargoLockPath); +console.log("Relative path to Cargo.lock:", relativePathToCargoLock); + +// Get all git tags +const gitTags = (await $$`git tag`.text()).split("\n"); + +const data = { + runtime: runtimeName, + versions: [], +}; + +// For each tag, get the content of `${runtimeDir}/Cargo.lock`. +for (const tag of gitTags) { + let tagVersion = tag.replace("v", ""); + if (!semver.valid(tagVersion)) { + console.log(`Skipping tag ${tag} because it is not a valid semver`); + continue; + } + + try { + const cargoLock = + await $$`git show ${tag}:${relativePathToCargoLock}`.text(); + + const parsed = toml.parse(cargoLock); + const packages = parsed.package; + + for (const pkg of packages) { + if (pkg.name === "swc_core") { + const swcCoreVersion = pkg.version; + + data.versions.push({ + version: tagVersion, + swcCoreVersion, + }); + console.log(`Found swc_core version ${swcCoreVersion} for tag ${tag}`); + } + } + + // Send the data to the server + if (data.versions.length >= 20) { + await fetch("http://localhost:50000/import/runtime", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(data), + }); + data.versions = []; + } + } catch (e) { + console.error(`Failed to parse Cargo.lock for tag ${tag}: ${e}`); + } +} + +await fetch("http://localhost:50000/import/runtime", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(data), +});